├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── components ├── site.vue └── styles.css ├── functions ├── certs.js ├── find-cert.js └── suscribed.js ├── layouts └── 404.vue ├── package.json ├── pages ├── certificados │ ├── index.vue │ └── not │ │ └── found │ │ └── index.vue ├── discord │ └── index.vue ├── gracias │ └── index.vue ├── index.vue └── swag │ └── index.vue ├── postcss.config.js ├── saber-browser.js ├── saber-config.js ├── shopify.js ├── static ├── 404.gif ├── 404.svg ├── _redirects ├── favicon.png ├── images │ ├── banner.svg │ ├── button.svg │ ├── d7.png │ ├── heart.png │ ├── item-bg.svg │ ├── logo.png │ ├── netlify-light.svg │ ├── no-profile.png │ ├── swag.jpg │ ├── triangles.png │ └── yaay.gif ├── seo-discord.jpg ├── seo-swag.jpg └── seo.jpg ├── tailwind.config.js ├── todo.js └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | patreon: d3portillo 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | .saber -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Denny Portillo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![LOGO](./static/seo.jpg)](https://aprendejs.email) 2 | 3 | **Aprendé Javascript** desde tu email con un contenido previamente preparado y curado, además al completar recibirás un certificado válido por lo aprendido. 4 | 5 | ## Código de conducta 6 | 7 | Por favor lee, respeta y promueve el [código de conducta acá](https://github.com/D3Portillo/aprendejs/wiki/Código-de-conducta) de **AprendeJS**. 8 | 9 | ## Recursos 10 | 11 | - [Código de conducta](https://github.com/D3Portillo/aprendejs/wiki/Código-de-conducta). 12 | - [Discord de AprendeJS](https://discord.com/invite/7PyRZ6n) 13 | - [Licencia del proyecto](/LICENSE) 14 | - [Wiki y FAQs](https://github.com/D3Portillo/aprendejs/wiki/FAQ) 15 | 16 | > Deploys by Netlify 17 | 18 | --- 19 | 20 | [![Netlify Status](https://api.netlify.com/api/v1/badges/d502cb9f-26aa-442f-ac41-8e81b6bf9f8e/deploy-status)](https://app.netlify.com/sites/aprendejs/deploys) [![Discord](https://img.shields.io/discord/716223433264070696?color=7289da&label=Discord&logo=discord&logoColor=7289da)](https://discord.com/invite/7PyRZ6n) 21 | -------------------------------------------------------------------------------- /components/site.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 87 | -------------------------------------------------------------------------------- /components/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind utilities; 3 | 4 | @import url("https://fonts.googleapis.com/css2?family=Cutive&family=Open+Sans:wght@400;700&display=swap"); 5 | * { 6 | font-family: "Open Sans", sans-serif; 7 | position: relative; 8 | outline: none; 9 | } 10 | body { 11 | background-color: #eeeeee; 12 | } 13 | p { 14 | @apply my-6; 15 | } 16 | a { 17 | @apply border-b border-transparent border-dashed z-1; 18 | } 19 | a:not([no-link]):hover { 20 | @apply border-black; 21 | } 22 | .cta:hover, 23 | a[no-link]:hover { 24 | transform: scale(1.03); 25 | } 26 | input:invalid { 27 | box-shadow: none !important; 28 | border: none !important; 29 | outline: none; 30 | } 31 | input:invalid:focus { 32 | outline: dotted 1px rgba(255, 0, 0, 0.4); 33 | } 34 | a:not([no-link])::before { 35 | content: ""; 36 | height: 50%; 37 | width: 100%; 38 | z-index: -1; 39 | margin-bottom: 1px; 40 | opacity: 0.2; 41 | @apply bg-yellow bottom-0 left-0 absolute; 42 | } 43 | 44 | .medium-zoom-overlay { 45 | z-index: 10; 46 | } 47 | 48 | @tailwind components; 49 | -------------------------------------------------------------------------------- /functions/certs.js: -------------------------------------------------------------------------------- 1 | const fetch = require("node-fetch") 2 | const { TOKEN = "" } = process.env 3 | const URL = `https://api.airtable.com/v0/appU8sXkXLRsB7KVe/AprendeJS%20-%20Certificados?view=List` 4 | exports.handler = (event, context, callback) => { 5 | const voidData = () => { 6 | const nothing = { 7 | statusCode: 200, 8 | body: JSON.stringify({}), 9 | } 10 | callback(null, nothing) 11 | } 12 | fetch(URL, { 13 | headers: { 14 | Authorization: `Bearer ${TOKEN}`, 15 | }, 16 | }) 17 | .then((r) => r.json()) 18 | .then(({ records }) => 19 | callback(null, { 20 | statusCode: 200, 21 | body: JSON.stringify( 22 | records 23 | .filter((e) => { 24 | return Array.isArray(e.fields.cert) 25 | }) 26 | .map( 27 | ({ 28 | id, 29 | fields: { 30 | name = "Usuario", 31 | email = "noemail@service.has", 32 | picture, 33 | }, 34 | }) => { 35 | return { 36 | id, 37 | name, 38 | email, 39 | picture: Array.isArray(picture) 40 | ? picture[0].thumbnails.large.url 41 | : `/images/no-profile.png`, 42 | } 43 | } 44 | ) 45 | ), 46 | }) 47 | ) 48 | .catch((error) => { 49 | console.log({ error }) 50 | voidData() 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /functions/find-cert.js: -------------------------------------------------------------------------------- 1 | const fetch = require("node-fetch") 2 | const { TOKEN = "" } = process.env 3 | const BASE_URL = `https://api.airtable.com/v0/appU8sXkXLRsB7KVe/AprendeJS%20-%20Certificados` 4 | const NOT_FOUND_URL = `https://aprendejs.email/certificados/not/found` 5 | const getMetas = ({ 6 | title = `AprendeJS`, 7 | description = `Aprendé Javascript desde tu email con un contenido previamente preparado y curado, además al completar recibirás un certificado válido por lo aprendido.`, 8 | image = "/seo.jpg", 9 | url = "https://aprendejs.email", 10 | }) => { 11 | const TWITTER_USER = `AprendeJS` 12 | if (!image.startsWith("http")) { 13 | image = `https://${`aprendejs.email/${image}`.replace(/\/+/g, "/")}` 14 | } 15 | return [ 16 | { 17 | name: "author", 18 | content: TWITTER_USER, 19 | }, 20 | { 21 | name: "keywords", 22 | content: "javascript,aprendejs,coding,newsletter", 23 | }, 24 | { 25 | name: "description", 26 | content: description, 27 | }, 28 | { 29 | name: "og:type", 30 | content: "article", 31 | }, 32 | { 33 | name: "og:title", 34 | content: title, 35 | }, 36 | { 37 | name: "og:description", 38 | content: description, 39 | }, 40 | { 41 | name: "og:image", 42 | content: image, 43 | }, 44 | { 45 | name: "og:url", 46 | content: url, 47 | }, 48 | { 49 | name: "og:site_name", 50 | content: title, 51 | }, 52 | { 53 | name: "twitter:card", 54 | content: "summary_large_image", 55 | }, 56 | { 57 | name: "twitter:image", 58 | content: image, 59 | }, 60 | { 61 | name: "twitter:site", 62 | content: TWITTER_USER, 63 | }, 64 | { 65 | name: "twitter:creator", 66 | content: TWITTER_USER, 67 | }, 68 | { 69 | name: "twitter:image:alt", 70 | content: url, 71 | }, 72 | ] 73 | } 74 | module.exports = { 75 | handler: (event, context, callback) => { 76 | const embedPDF = ({ name = "Sín nombre", pdfURL, image, url }) => { 77 | const title = `AprendeJS | ${name} ~ Curso completado` 78 | const description = `${name} ha completado con éxito el curso de 20 capítulos #AprendeJS, via: https://aprendejs.email` 79 | const metas = getMetas({ title, description, image, url }) 80 | .map(({ name, content }) => { 81 | return `` 82 | }) 83 | .join("\n") 84 | 85 | return ` 86 | ${title}${metas} 87 |