├── TEST.md ├── introduccion-a-node ├── logs.txt ├── file-example.js └── cli-example.js ├── introducción-a-html ├── file-to-delete ├── cat.jpg ├── main.css ├── about.html ├── practica-css.html ├── achievements │ └── mentoring.html └── index.html ├── improvr-components ├── src │ ├── atoms │ │ ├── Card │ │ │ ├── Card.css │ │ │ ├── index.js │ │ │ └── Card.jsx │ │ ├── Icon │ │ │ ├── Icon.css │ │ │ ├── index.js │ │ │ └── Icon.jsx │ │ └── Button │ │ │ ├── index.js │ │ │ ├── Button.stories.js │ │ │ ├── Button.css │ │ │ └── Button.jsx │ ├── molecules │ │ └── DropdownButton │ │ │ ├── index.js │ │ │ ├── DropdownButton.stories.js │ │ │ ├── DropdownButton.css │ │ │ └── DropdownButton.jsx │ ├── main.jsx │ ├── App.css │ ├── App.jsx │ ├── index.css │ └── assets │ │ └── react.svg ├── vite.config.js ├── .storybook │ ├── preview.js │ └── main.js ├── .gitignore ├── index.html ├── README.md ├── .eslintrc.cjs ├── package.json └── public │ └── vite.svg ├── practica-blog-next ├── styles │ ├── components │ │ ├── avatar.scss │ │ ├── picture.scss │ │ └── input.scss │ ├── generic.scss │ ├── components.scss │ ├── main.scss │ ├── _tools.scss │ ├── elements.scss │ ├── main.css │ └── objects.scss ├── components │ ├── Tag │ │ ├── index.js │ │ ├── Tag.module.scss │ │ └── Tag.jsx │ ├── Card │ │ ├── index.js │ │ ├── Card.module.scss │ │ └── Card.jsx │ ├── Time │ │ ├── index.js │ │ └── Time.jsx │ ├── Author │ │ ├── index.js │ │ ├── Author.module.scss │ │ └── Author.jsx │ ├── Heading │ │ ├── index.js │ │ ├── Heading.module.scss │ │ └── Heading.js │ ├── Link │ │ ├── index.js │ │ ├── Link.module.scss │ │ └── Link.jsx │ ├── Button │ │ ├── index.js │ │ ├── Button.jsx │ │ └── Button.module.scss │ ├── Paragraph │ │ ├── index.js │ │ ├── Paragraph.module.scss │ │ └── Paragraph.jsx │ └── TagsFilter │ │ ├── index.js │ │ ├── TagsFilter.module.scss │ │ └── TagsFilter.jsx ├── .eslintrc.json ├── jsconfig.json ├── pages │ ├── about.js │ ├── _app.js │ ├── _document.js │ ├── api │ │ └── posts.js │ └── index.jsx ├── next.config.js ├── data │ ├── filters.json │ └── articles.json ├── .gitignore ├── package.json ├── utils │ └── humanize.js └── README.md ├── practica-blog ├── src │ ├── styles │ │ ├── components │ │ │ ├── avatar.scss │ │ │ ├── picture.scss │ │ │ ├── heading.scss │ │ │ ├── link.scss │ │ │ ├── paragraph.scss │ │ │ ├── author.scss │ │ │ ├── tag.scss │ │ │ ├── input.scss │ │ │ ├── tags-filter.scss │ │ │ ├── button.scss │ │ │ └── card.scss │ │ ├── generic.scss │ │ ├── utilities.scss │ │ ├── main.scss │ │ ├── tools.scss │ │ ├── elements.scss │ │ ├── components.scss │ │ ├── settings.scss │ │ └── objects.scss │ └── scripts │ │ ├── utils │ │ ├── capitalize.js │ │ ├── sortByDate.js │ │ ├── humanizeDate.js │ │ └── humanize.js │ │ └── main.js ├── package.json └── README.md ├── practica-blog-react ├── src │ ├── styles │ │ ├── components │ │ │ ├── avatar.scss │ │ │ ├── picture.scss │ │ │ ├── heading.scss │ │ │ └── input.scss │ │ ├── generic.scss │ │ ├── utilities.scss │ │ ├── components.scss │ │ ├── main.scss │ │ ├── tools.scss │ │ ├── elements.scss │ │ ├── settings.scss │ │ └── objects.scss │ ├── components │ │ ├── Tag │ │ │ ├── index.js │ │ │ ├── Tag.jsx │ │ │ └── Tag.scss │ │ ├── Card │ │ │ ├── index.js │ │ │ ├── Card.scss │ │ │ └── Card.jsx │ │ ├── Time │ │ │ ├── index.js │ │ │ └── Time.jsx │ │ ├── Author │ │ │ ├── index.js │ │ │ ├── Author.scss │ │ │ └── Author.jsx │ │ ├── Link │ │ │ ├── index.js │ │ │ ├── Link.scss │ │ │ └── Link.jsx │ │ ├── Button │ │ │ ├── index.js │ │ │ ├── Button.jsx │ │ │ └── Button.scss │ │ ├── Paragraph │ │ │ ├── index.js │ │ │ ├── Paragraph.scss │ │ │ └── Paragraph.jsx │ │ └── TagsFilter │ │ │ ├── index.js │ │ │ ├── TagsFilter.scss │ │ │ └── TagsFilter.jsx │ ├── main.jsx │ ├── data │ │ ├── filters.json │ │ └── articles.json │ ├── utils │ │ └── humanize.js │ └── App.jsx ├── vite.config.js ├── .gitignore ├── .eslintrc.cjs ├── package.json ├── index.html └── public │ └── vite.svg ├── README.md ├── improvr ├── atoms │ ├── Button │ │ ├── index.js │ │ ├── Button.stories.js │ │ ├── Button.jsx │ │ └── Button.css │ ├── Card │ │ ├── index.js │ │ ├── Card.css │ │ ├── Card.stories.js │ │ └── Card.jsx │ ├── Icon │ │ ├── index.js │ │ ├── Icon.css │ │ ├── Icon.stories.js │ │ └── Icon.jsx │ └── Textarea │ │ ├── index.js │ │ ├── Textarea.css │ │ ├── Textarea.stories.js │ │ └── Textarea.jsx ├── organisms │ ├── Form │ │ ├── index.js │ │ ├── Form.stories.js │ │ ├── Form.css │ │ └── Form.jsx │ └── Result │ │ ├── index.js │ │ ├── Result.css │ │ ├── Result.stories.js │ │ └── Result.jsx ├── molecules │ ├── IconLabel │ │ ├── index.js │ │ ├── IconLabel.css │ │ ├── IconLabel.stories.js │ │ └── IconLabel.jsx │ ├── ButtonIcon │ │ ├── index.js │ │ ├── ButtonIcon.stories.js │ │ └── ButtonIcon.jsx │ └── SplitButton │ │ ├── index.js │ │ ├── SplitButton.stories.js │ │ ├── SplitButton.css │ │ └── SplitButton.jsx ├── app │ ├── favicon.ico │ ├── page.module.css │ ├── layout.js │ ├── page.js │ ├── api │ │ └── translate │ │ │ └── route.js │ └── globals.css ├── jsconfig.json ├── next.config.js ├── .eslintrc.json ├── .storybook │ ├── preview.js │ └── main.js ├── .gitignore ├── public │ ├── vercel.svg │ └── next.svg ├── package.json └── README.md ├── .vscode └── settings.json ├── mongoose ├── .env.example ├── posts │ ├── model.js │ ├── schema.js │ └── router.js ├── package.json └── index.js ├── intro-to-mongo ├── .env.example ├── package.json ├── index.js └── mongo.js ├── css-flexbox-grid ├── src │ └── styles │ │ ├── main.scss │ │ ├── desktop.scss │ │ ├── reset.scss │ │ └── base.scss ├── package.json └── index.html ├── frameworks-ui ├── tailwind-setup │ ├── src │ │ ├── input.css │ │ └── index.html │ ├── tailwind.config.js │ └── package.json └── bootstrap-setup │ ├── src │ ├── js │ │ └── main.js │ ├── scss │ │ └── styles.scss │ └── index.html │ ├── vite.config.js │ └── package.json ├── html-semantico ├── semantic-elements.png ├── cv.html └── index.html ├── .gitmodules ├── intro-a-react ├── src │ ├── main.jsx │ ├── Card.jsx │ ├── App.jsx │ ├── App.css │ ├── index.css │ └── assets │ │ └── react.svg ├── vite.config.js ├── .gitignore ├── .eslintrc.cjs ├── index.html ├── package.json └── public │ └── vite.svg ├── javascript-algorithms ├── package.json ├── bubble-sort.js ├── binary-search.js ├── index.js ├── README.md └── books.js ├── formularios-html ├── main.mjs ├── package.json ├── styles.css └── index.html ├── biblioteca-utilidades ├── package.json ├── package-lock.json └── index.js ├── extendiendo-sass ├── styles │ ├── base.scss │ ├── main.css.map │ ├── main.scss │ └── main.css ├── package.json └── index.html ├── passport ├── package.json └── index.js ├── fechas-javascript ├── package.json ├── package-lock.json └── index.js ├── intro-a-express ├── node-server.js ├── package.json └── index.js ├── css-responsive ├── index.html └── styles.css ├── .gitignore └── scripts ├── staleprs.sh └── closeprs.sh /TEST.md: -------------------------------------------------------------------------------- 1 | Hola mundo 🌎 2 | -------------------------------------------------------------------------------- /introduccion-a-node/logs.txt: -------------------------------------------------------------------------------- 1 | JaváScript -------------------------------------------------------------------------------- /introducción-a-html/file-to-delete: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Card/Card.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Icon/Icon.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-next/styles/components/avatar.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/avatar.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/picture.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-next/styles/components/picture.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/components/avatar.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/components/picture.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # undefined-academy 2 | https://undefined.academy 3 | -------------------------------------------------------------------------------- /improvr/atoms/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Button' -------------------------------------------------------------------------------- /improvr/atoms/Card/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Card' -------------------------------------------------------------------------------- /improvr/atoms/Icon/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Icon" -------------------------------------------------------------------------------- /improvr/organisms/Form/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Form' -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotenv.enableAutocloaking": true 3 | } -------------------------------------------------------------------------------- /improvr/atoms/Textarea/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Textarea' -------------------------------------------------------------------------------- /improvr/organisms/Result/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Result' -------------------------------------------------------------------------------- /improvr/molecules/IconLabel/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './IconLabel' -------------------------------------------------------------------------------- /practica-blog-next/components/Tag/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Tag' -------------------------------------------------------------------------------- /improvr-components/src/atoms/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Button' -------------------------------------------------------------------------------- /improvr-components/src/atoms/Card/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Card' -------------------------------------------------------------------------------- /improvr-components/src/atoms/Icon/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Icon" -------------------------------------------------------------------------------- /improvr/molecules/ButtonIcon/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ButtonIcon' -------------------------------------------------------------------------------- /improvr/molecules/SplitButton/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SplitButton' -------------------------------------------------------------------------------- /practica-blog-next/components/Card/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Card' -------------------------------------------------------------------------------- /practica-blog-next/components/Time/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Time' -------------------------------------------------------------------------------- /practica-blog-react/src/components/Tag/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Tag' -------------------------------------------------------------------------------- /practica-blog-next/components/Author/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Author' -------------------------------------------------------------------------------- /practica-blog-next/components/Heading/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Heading' -------------------------------------------------------------------------------- /practica-blog-next/components/Link/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Link' 2 | -------------------------------------------------------------------------------- /practica-blog-next/styles/generic.scss: -------------------------------------------------------------------------------- 1 | a { 2 | text-decoration: none; 3 | } 4 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Card/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Card' -------------------------------------------------------------------------------- /practica-blog-react/src/components/Time/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Time' -------------------------------------------------------------------------------- /practica-blog/src/styles/generic.scss: -------------------------------------------------------------------------------- 1 | a { 2 | text-decoration: none; 3 | } 4 | -------------------------------------------------------------------------------- /practica-blog-next/components/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Button"; 2 | -------------------------------------------------------------------------------- /practica-blog-next/components/Paragraph/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Paragraph' -------------------------------------------------------------------------------- /practica-blog-next/components/TagsFilter/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TagsFilter' -------------------------------------------------------------------------------- /practica-blog-react/src/components/Author/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Author' -------------------------------------------------------------------------------- /practica-blog-react/src/components/Link/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Link' 2 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/generic.scss: -------------------------------------------------------------------------------- 1 | a { 2 | text-decoration: none; 3 | } 4 | -------------------------------------------------------------------------------- /mongoose/.env.example: -------------------------------------------------------------------------------- 1 | PORT=3001 2 | MONGO_USERNAME= 3 | MONGO_PASSWORD= 4 | MONGO_HOSTNAME= -------------------------------------------------------------------------------- /practica-blog-react/src/components/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Button"; 2 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Paragraph/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Paragraph' -------------------------------------------------------------------------------- /practica-blog-react/src/components/TagsFilter/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TagsFilter' -------------------------------------------------------------------------------- /improvr-components/src/molecules/DropdownButton/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './DropdownButton' -------------------------------------------------------------------------------- /intro-to-mongo/.env.example: -------------------------------------------------------------------------------- 1 | PORT=3001 2 | MONGO_USERNAME= 3 | MONGO_PASSWORD= 4 | MONGO_HOSTNAME= -------------------------------------------------------------------------------- /practica-blog-next/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/babel", "next/core-web-vitals"] 3 | } 4 | -------------------------------------------------------------------------------- /css-flexbox-grid/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | @use "./reset.scss"; 2 | @use "./base.scss"; 3 | @use "./desktop.scss"; -------------------------------------------------------------------------------- /frameworks-ui/tailwind-setup/src/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /improvr/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glrodasz/undefined-academy/HEAD/improvr/app/favicon.ico -------------------------------------------------------------------------------- /introducción-a-html/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glrodasz/undefined-academy/HEAD/introducción-a-html/cat.jpg -------------------------------------------------------------------------------- /improvr/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Icon/Icon.jsx: -------------------------------------------------------------------------------- 1 | import "./Icon.css" 2 | 3 | const Icon = () => { 4 | 5 | } 6 | 7 | export default Icon; -------------------------------------------------------------------------------- /improvr/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /practica-blog-next/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /html-semantico/semantic-elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glrodasz/undefined-academy/HEAD/html-semantico/semantic-elements.png -------------------------------------------------------------------------------- /practica-blog/src/styles/utilities.scss: -------------------------------------------------------------------------------- 1 | .font-regular { 2 | font-weight: 400; 3 | } 4 | 5 | .font-bold { 6 | font-weight: 700; 7 | } 8 | -------------------------------------------------------------------------------- /practica-blog-next/styles/components.scss: -------------------------------------------------------------------------------- 1 | // Atoms 2 | @use "components/picture"; 3 | @use "components/avatar"; 4 | @use "components/input"; 5 | -------------------------------------------------------------------------------- /practica-blog-next/styles/main.scss: -------------------------------------------------------------------------------- 1 | @import "tools"; 2 | @import "generic"; 3 | @import "elements"; 4 | @import "objects"; 5 | @import "components"; -------------------------------------------------------------------------------- /practica-blog-react/src/styles/utilities.scss: -------------------------------------------------------------------------------- 1 | .font-regular { 2 | font-weight: 400; 3 | } 4 | 5 | .font-bold { 6 | font-weight: 700; 7 | } 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "el-mundo-del-markdown"] 2 | path = el-mundo-del-markdown 3 | url = https://github.com/glrodasz/el-mundo-del-markdown.git 4 | -------------------------------------------------------------------------------- /practica-blog-next/pages/about.js: -------------------------------------------------------------------------------- 1 | const about = () => { 2 | return ( 3 |
4 | About 5 |
6 | ); 7 | }; 8 | 9 | export default about; -------------------------------------------------------------------------------- /improvr-components/src/atoms/Card/Card.jsx: -------------------------------------------------------------------------------- 1 | const Card = () => { 2 | return ( 3 |
4 | 5 |
6 | ); 7 | }; 8 | 9 | export default Card; -------------------------------------------------------------------------------- /improvr/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "next/babel", 4 | "next/core-web-vitals", 5 | "plugin:storybook/recommended" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /practica-blog/src/scripts/utils/capitalize.js: -------------------------------------------------------------------------------- 1 | export default function capitalize(str) { 2 | return str.charAt(0).toUpperCase() + str.slice(1); 3 | } 4 | -------------------------------------------------------------------------------- /improvr/atoms/Card/Card.css: -------------------------------------------------------------------------------- 1 | .card { 2 | border: 1px solid lightgray; 3 | padding: 20px; 4 | border-radius: 8px; 5 | box-shadow: 1px 1px 10px 2px rgba(0, 0, 0, 0.1); 6 | } -------------------------------------------------------------------------------- /mongoose/posts/model.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import { postSchema } from "./schema.js"; 3 | 4 | export const postModel = mongoose.model("post", postSchema); -------------------------------------------------------------------------------- /improvr/atoms/Icon/Icon.css: -------------------------------------------------------------------------------- 1 | .icon { 2 | display: inline-flex; 3 | justify-content: center; 4 | align-items: center; 5 | } 6 | 7 | .is-clickable { 8 | cursor: pointer; 9 | } -------------------------------------------------------------------------------- /practica-blog-next/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /practica-blog/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | @use "settings"; 2 | @use "tools"; 3 | @use "generic"; 4 | @use "elements"; 5 | @use "objects"; 6 | @use "components"; 7 | @use "utilities"; -------------------------------------------------------------------------------- /intro-a-react/src/main.jsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom/client"; 2 | import App from "./App.jsx"; 3 | 4 | ReactDOM.createRoot(document.querySelector("#root")).render(); 5 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/components.scss: -------------------------------------------------------------------------------- 1 | // Atoms 2 | @use "components/heading"; 3 | @use "components/picture"; 4 | @use "components/avatar"; 5 | @use "components/input"; 6 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | @use "settings"; 2 | @use "tools"; 3 | @use "generic"; 4 | @use "elements"; 5 | @use "objects"; 6 | @use "components"; 7 | @use "utilities"; -------------------------------------------------------------------------------- /frameworks-ui/bootstrap-setup/src/js/main.js: -------------------------------------------------------------------------------- 1 | // Import our custom CSS 2 | import '../scss/styles.scss' 3 | 4 | // Import all of Bootstrap's JS 5 | import * as bootstrap from 'bootstrap' -------------------------------------------------------------------------------- /javascript-algorithms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-algorithms", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "type": "module" 7 | } 8 | -------------------------------------------------------------------------------- /css-flexbox-grid/src/styles/desktop.scss: -------------------------------------------------------------------------------- 1 | $desktop-media-query: 980px; 2 | 3 | @media screen and (min-width: $desktop-media-query) { 4 | .item, .grid-item { 5 | background: lightblue; 6 | } 7 | } -------------------------------------------------------------------------------- /improvr/app/page.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | padding: 6rem; 6 | min-height: 100vh; 7 | flex-direction: column; 8 | gap: 20px; 9 | } -------------------------------------------------------------------------------- /improvr/organisms/Form/Form.stories.js: -------------------------------------------------------------------------------- 1 | import Form from "./Form"; 2 | 3 | export default { 4 | component: Form, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Default = { 9 | args: {}, 10 | }; 11 | -------------------------------------------------------------------------------- /intro-a-react/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /frameworks-ui/tailwind-setup/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{html,js}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /improvr-components/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /improvr/atoms/Textarea/Textarea.css: -------------------------------------------------------------------------------- 1 | .textarea { 2 | resize: vertical; 3 | min-height: 180px; 4 | width: 100%; 5 | border: 1px solid lightgray; 6 | border-radius: 4px; 7 | padding: 10px; 8 | box-sizing: border-box; 9 | } -------------------------------------------------------------------------------- /improvr/molecules/IconLabel/IconLabel.css: -------------------------------------------------------------------------------- 1 | .icon-label { 2 | display: flex; 3 | align-items: baseline; 4 | gap: 8px; 5 | } 6 | 7 | .icon-label-text { 8 | text-decoration: underline; 9 | color: mediumblue; 10 | } -------------------------------------------------------------------------------- /practica-blog-react/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/heading.scss: -------------------------------------------------------------------------------- 1 | // Heading/Desktop/SM 2 | .heading { 3 | color: var(--color-black-pearl-900); 4 | } 5 | 6 | .heading-sm { 7 | font-size: 23px; 8 | line-height: 29px; 9 | } 10 | -------------------------------------------------------------------------------- /css-flexbox-grid/src/styles/reset.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | box-sizing: border-box; 4 | } 5 | 6 | * { 7 | box-sizing: inherit; 8 | } 9 | 10 | body { 11 | background: whitesmoke; 12 | margin: 0; 13 | } -------------------------------------------------------------------------------- /formularios-html/main.mjs: -------------------------------------------------------------------------------- 1 | function handleSubmit(event) { 2 | event.preventDefault() 3 | console.log("Hola mundo"); 4 | } 5 | 6 | const $form = document.querySelector("form") 7 | 8 | $form.addEventListener("submit", handleSubmit) -------------------------------------------------------------------------------- /practica-blog-react/src/styles/components/heading.scss: -------------------------------------------------------------------------------- 1 | // Heading/Desktop/SM 2 | .heading { 3 | color: var(--color-black-pearl-900); 4 | } 5 | 6 | .heading-sm { 7 | font-size: 23px; 8 | line-height: 29px; 9 | } 10 | -------------------------------------------------------------------------------- /practica-blog-next/components/Heading/Heading.module.scss: -------------------------------------------------------------------------------- 1 | // Heading/Desktop/SM 2 | .heading { 3 | color: var(--color-black-pearl-900); 4 | } 5 | 6 | .heading-sm { 7 | font-size: 23px; 8 | line-height: 29px; 9 | } 10 | -------------------------------------------------------------------------------- /practica-blog-next/pages/_app.js: -------------------------------------------------------------------------------- 1 | import "minireset.css" 2 | import '@/styles/main.css' 3 | import '@/styles/main.scss' 4 | 5 | export default function App({ Component, pageProps }) { 6 | return 7 | } 8 | -------------------------------------------------------------------------------- /intro-a-react/src/Card.jsx: -------------------------------------------------------------------------------- 1 | export const Card = ({ title, children }) => { 2 | // JavaScript 3 | return ( 4 |
5 |

{title}

6 |

{children}

7 |
8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /improvr/atoms/Icon/Icon.stories.js: -------------------------------------------------------------------------------- 1 | import Icon from "./Icon"; 2 | 3 | export default { 4 | component: Icon, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Default = { 9 | args: { 10 | name: "grammar", 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /biblioteca-utilidades/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "biblioteca-utilidades", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "type": "module", 6 | "license": "MIT", 7 | "dependencies": { 8 | "lodash": "^4.17.21" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /improvr/molecules/SplitButton/SplitButton.stories.js: -------------------------------------------------------------------------------- 1 | import SplitButton from "./SplitButton"; 2 | 3 | export default { 4 | component: SplitButton, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Default = { 9 | args: {}, 10 | }; 11 | -------------------------------------------------------------------------------- /improvr/organisms/Form/Form.css: -------------------------------------------------------------------------------- 1 | .form { 2 | display: flex; 3 | flex-direction: column; 4 | gap: 10px; 5 | width: 800px; 6 | } 7 | 8 | .form-buttons { 9 | display: flex; 10 | gap: 10px; 11 | justify-content: flex-end; 12 | margin-top: 10px; 13 | } -------------------------------------------------------------------------------- /improvr/atoms/Card/Card.stories.js: -------------------------------------------------------------------------------- 1 | import Card from "./Card"; 2 | 3 | export default { 4 | component: Card, 5 | tags: ["autodocs"], 6 | args: { 7 | children: "Esto es una card", 8 | }, 9 | }; 10 | 11 | export const Default = { 12 | args: {}, 13 | }; -------------------------------------------------------------------------------- /practica-blog/src/styles/components/link.scss: -------------------------------------------------------------------------------- 1 | .text-button { 2 | color: var(--color-black-pearl-900); 3 | 4 | &.is-active { 5 | color: var(--color-aquarius-600); 6 | } 7 | } 8 | 9 | .text-button-md { 10 | font-size: 15px; 11 | line-height: 19px; 12 | } -------------------------------------------------------------------------------- /practica-blog-react/src/components/Link/Link.scss: -------------------------------------------------------------------------------- 1 | .text-button { 2 | color: var(--color-black-pearl-900); 3 | 4 | &.is-active { 5 | color: var(--color-aquarius-600); 6 | } 7 | } 8 | 9 | .text-button-md { 10 | font-size: 15px; 11 | line-height: 19px; 12 | } -------------------------------------------------------------------------------- /frameworks-ui/bootstrap-setup/src/scss/styles.scss: -------------------------------------------------------------------------------- 1 | // Import all of Bootstrap's CSS 2 | @import "~bootstrap/scss/bootstrap"; 3 | 4 | body { 5 | background: whitesmoke; 6 | } 7 | 8 | @include media-breakpoint-up(lg) { 9 | body { 10 | background: tomato; 11 | } 12 | } -------------------------------------------------------------------------------- /practica-blog-next/components/Link/Link.module.scss: -------------------------------------------------------------------------------- 1 | .text-button { 2 | color: var(--color-black-pearl-900); 3 | 4 | &.is-active { 5 | color: var(--color-aquarius-600); 6 | } 7 | } 8 | 9 | .text-button-md { 10 | font-size: 15px; 11 | line-height: 19px; 12 | } -------------------------------------------------------------------------------- /improvr-components/src/molecules/DropdownButton/DropdownButton.stories.js: -------------------------------------------------------------------------------- 1 | import DropdownButton from "./DropdownButton"; 2 | 3 | export default { 4 | component: DropdownButton, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Default = { 9 | args: {}, 10 | }; 11 | -------------------------------------------------------------------------------- /practica-blog-react/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | 5 | ReactDOM.createRoot(document.getElementById('root')).render( 6 | 7 | 8 | , 9 | ) 10 | -------------------------------------------------------------------------------- /practica-blog/src/scripts/utils/sortByDate.js: -------------------------------------------------------------------------------- 1 | export default function sortByDate($a, $b) { 2 | const dateA = new Date($a.querySelector("time").getAttribute("datetime")); 3 | const dateB = new Date($b.querySelector("time").getAttribute("datetime")); 4 | return dateB - dateA; 5 | } 6 | -------------------------------------------------------------------------------- /practica-blog/src/styles/tools.scss: -------------------------------------------------------------------------------- 1 | @use "settings"; 2 | 3 | @mixin container-width { 4 | width: 100%; 5 | max-width: var(--container-max-width); 6 | } 7 | 8 | @mixin desktop { 9 | @media screen and (min-width: settings.$breakpoint-large) { 10 | @content; 11 | } 12 | } -------------------------------------------------------------------------------- /improvr/atoms/Textarea/Textarea.stories.js: -------------------------------------------------------------------------------- 1 | import Textarea from "./Textarea"; 2 | 3 | export default { 4 | component: Textarea, 5 | tags: ["autodocs"], 6 | args: { 7 | children: "Esto es un Textarea", 8 | }, 9 | }; 10 | 11 | export const Default = { 12 | args: {}, 13 | }; -------------------------------------------------------------------------------- /practica-blog-react/src/styles/tools.scss: -------------------------------------------------------------------------------- 1 | @use "settings"; 2 | 3 | @mixin container-width { 4 | width: 100%; 5 | max-width: var(--container-max-width); 6 | } 7 | 8 | @mixin desktop { 9 | @media screen and (min-width: settings.$breakpoint-large) { 10 | @content; 11 | } 12 | } -------------------------------------------------------------------------------- /improvr/molecules/IconLabel/IconLabel.stories.js: -------------------------------------------------------------------------------- 1 | import IconLabel from "./IconLabel"; 2 | 3 | export default { 4 | component: IconLabel, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Default = { 9 | args: { 10 | children: "Corrected", 11 | icon: "grammar", 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /practica-blog-next/data/filters.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "Todos", "href": "#" }, 3 | { "name": "HTML", "href": "#" }, 4 | { "name": "CSS", "href": "#" }, 5 | { "name": "Javascript", "href": "#" }, 6 | { "name": "Web components", "href": "#" }, 7 | { "name": "Sistemas de diseño", "href": "#" } 8 | ] 9 | -------------------------------------------------------------------------------- /improvr-components/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /improvr/atoms/Card/Card.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import "./Card.css"; 3 | 4 | const Card = ({ children }) => { 5 | return
{children}
; 6 | }; 7 | 8 | Card.propTypes = { 9 | children: PropTypes.node.isRequired, 10 | }; 11 | 12 | export default Card; 13 | -------------------------------------------------------------------------------- /practica-blog-react/src/data/filters.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "Todos", "href": "#" }, 3 | { "name": "HTML", "href": "#" }, 4 | { "name": "CSS", "href": "#" }, 5 | { "name": "Javascript", "href": "#" }, 6 | { "name": "Web components", "href": "#" }, 7 | { "name": "Sistemas de diseño", "href": "#" } 8 | ] 9 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/paragraph.scss: -------------------------------------------------------------------------------- 1 | // Paragraph/SM/Regular 2 | .paragraph { 3 | color: var(--color-black-pearl-700); 4 | } 5 | 6 | .paragraph-sm { 7 | font-size: 16px; 8 | line-height: 22px; 9 | } 10 | 11 | .paragraph-xs { 12 | font-size: 13px; 13 | line-height: 19px; 14 | } 15 | -------------------------------------------------------------------------------- /practica-blog-next/styles/_tools.scss: -------------------------------------------------------------------------------- 1 | // SASS Variables 2 | $breakpoint-large: 992px; 3 | 4 | @mixin container-width { 5 | width: 100%; 6 | max-width: var(--container-max-width); 7 | } 8 | 9 | @mixin desktop { 10 | @media screen and (min-width: $breakpoint-large) { 11 | @content; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /introducción-a-html/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | max-width: 600px; 3 | font-size: 14px; 4 | margin: 0 auto; 5 | background: #f3f4f6; 6 | color: #333; 7 | font-family: Arial, Helvetica, sans-serif; 8 | 9 | } 10 | 11 | p { 12 | line-height: 1.1; 13 | } 14 | 15 | h1, 16 | h2 { 17 | line-height: 1.5; 18 | margin-top: 50px; 19 | } -------------------------------------------------------------------------------- /practica-blog/src/styles/components/author.scss: -------------------------------------------------------------------------------- 1 | .author { 2 | display: flex; 3 | gap: 0 12px; 4 | align-items: center; 5 | } 6 | 7 | .author img { 8 | width: 100%; 9 | max-width: 32px; 10 | max-height: 32px; 11 | border-radius: 50%; 12 | } 13 | 14 | .author span { 15 | color: var(--color-black-pearl-900); 16 | } 17 | -------------------------------------------------------------------------------- /frameworks-ui/bootstrap-setup/vite.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | export default { 4 | root: path.resolve(__dirname, 'src'), 5 | resolve: { 6 | alias: { 7 | '~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'), 8 | } 9 | }, 10 | server: { 11 | port: 8080, 12 | hot: true 13 | } 14 | } -------------------------------------------------------------------------------- /practica-blog-next/components/Author/Author.module.scss: -------------------------------------------------------------------------------- 1 | .author { 2 | display: flex; 3 | gap: 0 12px; 4 | align-items: center; 5 | } 6 | 7 | .author img { 8 | width: 100%; 9 | max-width: 32px; 10 | max-height: 32px; 11 | border-radius: 50%; 12 | } 13 | 14 | .author span { 15 | color: var(--color-black-pearl-900); 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Author/Author.scss: -------------------------------------------------------------------------------- 1 | .author { 2 | display: flex; 3 | gap: 0 12px; 4 | align-items: center; 5 | } 6 | 7 | .author img { 8 | width: 100%; 9 | max-width: 32px; 10 | max-height: 32px; 11 | border-radius: 50%; 12 | } 13 | 14 | .author span { 15 | color: var(--color-black-pearl-900); 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog/src/scripts/utils/humanizeDate.js: -------------------------------------------------------------------------------- 1 | import humanize from "./humanize.js"; 2 | import capitalize from "./capitalize"; 3 | 4 | export default function humanizeDate($date) { 5 | const datetime = $date.getAttribute("datetime"); 6 | const humanizedDate = humanize(datetime); 7 | $date.textContent = capitalize(humanizedDate); 8 | } 9 | -------------------------------------------------------------------------------- /extendiendo-sass/styles/base.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | box-sizing: border-box; 6 | } 7 | 8 | * { 9 | box-sizing: inherit; 10 | } 11 | 12 | body { 13 | max-width: 800px; 14 | margin: 0 auto; 15 | background-color: whitesmoke; 16 | font-family: Arial, Helvetica, sans-serif; 17 | font-size: 16px; 18 | } -------------------------------------------------------------------------------- /improvr/organisms/Result/Result.css: -------------------------------------------------------------------------------- 1 | .result { 2 | display: flex; 3 | flex-direction: column; 4 | gap: 10px; 5 | position: relative; 6 | width: 800px; 7 | } 8 | 9 | .result-buttons { 10 | display: flex; 11 | gap: 10px; 12 | justify-content: space-between; 13 | } 14 | 15 | .result-close { 16 | position: absolute; 17 | top: 0; 18 | right: 0; 19 | } -------------------------------------------------------------------------------- /practica-blog-next/styles/elements.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | body { 4 | font-family: Inter; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | width: 100%; 9 | margin: 0 auto; 10 | background-color: var(--color-black-pearl-50); 11 | } 12 | 13 | main { 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog/src/styles/elements.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | body { 4 | font-family: Inter; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | width: 100%; 9 | margin: 0 auto; 10 | background-color: var(--color-black-pearl-50); 11 | } 12 | 13 | main { 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/elements.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | body { 4 | font-family: Inter; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | width: 100%; 9 | margin: 0 auto; 10 | background-color: var(--color-black-pearl-50); 11 | } 12 | 13 | main { 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | -------------------------------------------------------------------------------- /extendiendo-sass/styles/main.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["base.scss","main.scss"],"names":[],"mappings":"AAAA;EACC;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;ACdD;EACC;;;AAcD;EACC,YAZY;EAaZ;EACA;EACA;EACA;EAbA;EACA;EACA;EACA;EACA,OAWgB;EAVhB,QAUuB;;AAGtB;EACC;;;AAMF;EACC;;;AADD;EACC;;;AADD;EACC;;;AADD;EACC;;;AADD;EACC","file":"main.css"} -------------------------------------------------------------------------------- /improvr/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | /** @type { import('@storybook/react').Preview } */ 2 | const preview = { 3 | parameters: { 4 | actions: { argTypesRegex: "^on[A-Z].*" }, 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | }, 12 | }; 13 | 14 | export default preview; 15 | -------------------------------------------------------------------------------- /improvr-components/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | /** @type { import('@storybook/react').Preview } */ 2 | const preview = { 3 | parameters: { 4 | actions: { argTypesRegex: "^on[A-Z].*" }, 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | }, 12 | }; 13 | 14 | export default preview; 15 | -------------------------------------------------------------------------------- /practica-blog-next/components/Time/Time.jsx: -------------------------------------------------------------------------------- 1 | import Paragraph from "../Paragraph"; 2 | import humanize from "../../utils/humanize"; 3 | 4 | const Time = ({ children }) => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default Time; 13 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Time/Time.jsx: -------------------------------------------------------------------------------- 1 | import Paragraph from "../Paragraph"; 2 | import humanize from "../../utils/humanize"; 3 | 4 | const Time = ({ children }) => { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default Time; 13 | -------------------------------------------------------------------------------- /intro-a-react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /passport/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "type": "module", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "node --watch index.js" 9 | }, 10 | "dependencies": { 11 | "bcrypt": "^5.1.1", 12 | "express": "^4.18.2", 13 | "passport": "^0.6.0", 14 | "passport-http": "^0.3.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /improvr-components/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /formularios-html/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "formularios-html", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vite", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "vite": "^4.2.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog-next/components/Paragraph/Paragraph.module.scss: -------------------------------------------------------------------------------- 1 | // Paragraph/SM/Regular 2 | .paragraph { 3 | color: var(--color-black-pearl-700); 4 | } 5 | 6 | .paragraph-sm { 7 | font-size: 16px; 8 | line-height: 22px; 9 | } 10 | 11 | .paragraph-xs { 12 | font-size: 13px; 13 | line-height: 19px; 14 | } 15 | 16 | .is-help-text { 17 | color: var(--color-black-pearl-400); 18 | } 19 | -------------------------------------------------------------------------------- /practica-blog-react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Paragraph/Paragraph.scss: -------------------------------------------------------------------------------- 1 | // Paragraph/SM/Regular 2 | .paragraph { 3 | color: var(--color-black-pearl-700); 4 | } 5 | 6 | .paragraph-sm { 7 | font-size: 16px; 8 | line-height: 22px; 9 | } 10 | 11 | .paragraph-xs { 12 | font-size: 13px; 13 | line-height: 19px; 14 | } 15 | 16 | .is-help-text { 17 | color: var(--color-black-pearl-400); 18 | } 19 | -------------------------------------------------------------------------------- /fechas-javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fechas-javascript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "dayjs": "^1.11.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog-next/components/Heading/Heading.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames/bind"; 3 | 4 | import styles from "./Heading.module.scss"; 5 | 6 | const cx = classNames.bind(styles); 7 | 8 | const Heading = ({ children }) => { 9 | return

{children}

; 10 | }; 11 | 12 | export default Heading; 13 | -------------------------------------------------------------------------------- /intro-a-express/node-server.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); // CommonJS 2 | 3 | function serverCallback(request, response) { 4 | response.writeHead(200, { "Content-Type": "application/json" }); 5 | response.end(JSON.stringify({ message: "Hello Bootcamp Texto" })); 6 | } 7 | 8 | const server = http.createServer(serverCallback); 9 | 10 | server.listen(3000, () => console.log("🌍 Server running on port 3000")); 11 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Tag/Tag.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import "./Tag.scss"; 3 | 4 | const Tag = ({ children, type = "primary", link = "#" }) => { 5 | return ( 6 | 11 | {children} 12 | 13 | ); 14 | }; 15 | 16 | export default Tag; 17 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Tag/Tag.scss: -------------------------------------------------------------------------------- 1 | .tag { 2 | padding: 8px; 3 | border-radius: 2px; 4 | 5 | font-weight: regular; 6 | font-size: 13px; 7 | line-height: 19px; 8 | } 9 | 10 | .tag a { 11 | color: var(--color-aquarius-900); 12 | } 13 | 14 | .tag-primary { 15 | background: var(--color-aquarius-100); 16 | } 17 | 18 | .tag-secondary { 19 | background: var(--color-morrocan-blue-100); 20 | } 21 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/tag.scss: -------------------------------------------------------------------------------- 1 | .tag { 2 | padding: 8px; 3 | border-radius: 2px; 4 | 5 | font-weight: regular; 6 | font-size: 13px; 7 | line-height: 19px; 8 | } 9 | 10 | .tag a { 11 | color: var(--color-aquarius-900); 12 | } 13 | 14 | .tag-primary { 15 | background: var(--color-aquarius-100); 16 | } 17 | 18 | .tag-secondary { 19 | background: var(--color-morrocan-blue-100); 20 | } 21 | -------------------------------------------------------------------------------- /css-flexbox-grid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-flexbox-grid", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vite", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "sass": "^1.60.0", 15 | "vite": "^4.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /introducción-a-html/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | About Guillermo Rodas 7 | 8 | 9 | 10 | 11 |

Esta es la información acerca de Guillermo Rodas

12 | Mentoring 13 | Volver al Home 14 | 15 | 16 | -------------------------------------------------------------------------------- /practica-blog-next/components/Tag/Tag.module.scss: -------------------------------------------------------------------------------- 1 | .tag { 2 | padding: 8px; 3 | border-radius: 2px; 4 | 5 | font-weight: regular; 6 | font-size: 13px; 7 | line-height: 19px; 8 | } 9 | 10 | .tag a { 11 | color: var(--color-aquarius-900); 12 | } 13 | 14 | .tag-primary { 15 | background: var(--color-aquarius-100); 16 | } 17 | 18 | .tag-secondary { 19 | background: var(--color-morrocan-blue-100); 20 | } 21 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components.scss: -------------------------------------------------------------------------------- 1 | // Atoms 2 | @use "components/heading"; 3 | @use "components/paragraph"; 4 | @use "components/link"; 5 | @use "components/picture"; 6 | @use "components/avatar"; 7 | @use "components/input"; 8 | 9 | // Molecules 10 | @use "components/tag"; 11 | @use "components/button"; 12 | 13 | // Organisms 14 | @use "components/card"; 15 | @use "components/author"; 16 | @use "components/tags-filter"; -------------------------------------------------------------------------------- /improvr-components/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /practica-blog-next/components/Tag/Tag.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import styles from "./Tag.module.scss"; 3 | 4 | const Tag = ({ children, type = "primary", link = "#" }) => { 5 | return ( 6 | 11 | {children} 12 | 13 | ); 14 | }; 15 | 16 | export default Tag; 17 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Link/Link.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import "./Link.scss"; 3 | 4 | const Link = ({ children, href = "#", isActive }) => { 5 | return ( 6 | 12 | {children} 13 | 14 | ); 15 | }; 16 | 17 | export default Link; 18 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Button/Button.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import "./Button.scss"; 3 | 4 | const Button = ({ children, type = "primary", onClick }) => { 5 | return ( 6 | 14 | ); 15 | }; 16 | 17 | export default Button; 18 | -------------------------------------------------------------------------------- /introducción-a-html/practica-css.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Práctica CSS 6 | 8 | 9 | 10 |
11 |
Encabezado
12 |
Uno
Dos
Tres
13 | 14 |
15 | 16 | -------------------------------------------------------------------------------- /javascript-algorithms/bubble-sort.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(arr, compareFunction) { 2 | let swapped = true; 3 | 4 | while (swapped) { 5 | swapped = false; 6 | 7 | for(let i = 1; i < arr.length; i++) { 8 | if (compareFunction(arr[i-1], arr[i])) { 9 | const temp = arr[i - 1]; 10 | arr[i-1] = arr[i]; 11 | arr[i] = temp; 12 | swapped = true; 13 | } 14 | } 15 | 16 | } 17 | 18 | return arr; 19 | } 20 | 21 | export default bubbleSort; -------------------------------------------------------------------------------- /practica-blog-react/src/components/Author/Author.jsx: -------------------------------------------------------------------------------- 1 | import "./Author.scss"; 2 | 3 | const Author = ({ 4 | name, 5 | avatarUrl = "https://i.pravatar.cc/300", 6 | avatarAlt = "Avatar de un autor", 7 | }) => { 8 | return ( 9 |
10 | {avatarAlt} 11 | {name} 12 |
13 | ); 14 | }; 15 | 16 | export default Author; 17 | -------------------------------------------------------------------------------- /improvr/app/layout.js: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /improvr/atoms/Button/Button.stories.js: -------------------------------------------------------------------------------- 1 | import Button from "./Button"; 2 | 3 | export default { 4 | component: Button, 5 | tags: ["autodocs"], 6 | args: { 7 | children: "Esto es un botón", 8 | }, 9 | }; 10 | 11 | export const Default = { 12 | args: {}, 13 | }; 14 | 15 | export const Primary = { 16 | args: { 17 | type: "primary", 18 | }, 19 | }; 20 | 21 | export const Secondary = { 22 | args: { 23 | type: "secondary", 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /intro-to-mongo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "intro-to-mongo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "dotenv": "^16.0.3", 8 | "express": "^4.18.2", 9 | "mongodb": "^5.5.0" 10 | }, 11 | "scripts": { 12 | "dev": "node --watch index.js", 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC" 18 | } 19 | -------------------------------------------------------------------------------- /introducción-a-html/achievements/mentoring.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mentoring 7 | 8 | 9 | 10 | 11 | 15 | About 16 | 17 | 18 | -------------------------------------------------------------------------------- /improvr/molecules/ButtonIcon/ButtonIcon.stories.js: -------------------------------------------------------------------------------- 1 | import ButtonIcon from "./ButtonIcon"; 2 | 3 | export default { 4 | component: ButtonIcon, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Primary = { 9 | args: { 10 | type: "primary", 11 | children: "Grammar", 12 | icon: "grammar", 13 | }, 14 | }; 15 | 16 | export const Secondary = { 17 | args: { 18 | type: "secondary", 19 | children: "Copy", 20 | icon: "copy", 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /intro-a-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "intro-a-express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "node-server.js", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "node --watch index.js", 9 | "start": "node index.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "express": "^4.18.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /extendiendo-sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extendiendo-sass", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vite", 8 | "sass": "sass styles/main.scss styles/main.css", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "sass": "^1.60.0", 16 | "vite": "^4.2.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Button/Button.stories.js: -------------------------------------------------------------------------------- 1 | import Button from "./Button"; 2 | 3 | export default { 4 | component: Button, 5 | tags: ["autodocs"], 6 | args: { 7 | children: "Esto es un botón", 8 | }, 9 | }; 10 | 11 | export const Default = { 12 | args: {}, 13 | }; 14 | 15 | export const Primary = { 16 | args: { 17 | type: "primary", 18 | }, 19 | }; 20 | 21 | export const Secondary = { 22 | args: { 23 | type: "secondary", 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /mongoose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongoose", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "node --watch index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "dotenv": "^16.0.3", 16 | "express": "^4.18.2", 17 | "mongoose": "^7.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frameworks-ui/tailwind-setup/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Document 10 | 11 | 12 | 13 |

14 | Hello world! 15 |

16 | 17 | 18 | -------------------------------------------------------------------------------- /improvr-components/README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /intro-a-react/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:react/recommended', 6 | 'plugin:react/jsx-runtime', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | settings: { react: { version: '18.2' } }, 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': 'warn', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /javascript-algorithms/binary-search.js: -------------------------------------------------------------------------------- 1 | function binarySearch(books, valueToFind, key) { 2 | let start = 0; 3 | let end = books.length - 1; 4 | 5 | while (start <= end) { 6 | let mid = Math.floor((start + end) / 2); 7 | 8 | if (books[mid][key] === valueToFind) { 9 | return books[mid]; 10 | } else if (books[mid][key] < valueToFind) { 11 | start = mid + 1; 12 | } else { 13 | end = mid - 1; 14 | } 15 | } 16 | 17 | return null; 18 | } 19 | 20 | export default binarySearch; 21 | -------------------------------------------------------------------------------- /practica-blog-next/components/Author/Author.jsx: -------------------------------------------------------------------------------- 1 | import Paragraph from "@/components/Paragraph"; 2 | import styles from "./Author.module.scss"; 3 | 4 | const Author = ({ 5 | name, 6 | avatarUrl = "https://i.pravatar.cc/300", 7 | avatarAlt = "Avatar de un autor", 8 | }) => { 9 | return ( 10 |
11 | {avatarAlt} 12 | {name} 13 |
14 | ); 15 | }; 16 | 17 | export default Author; 18 | -------------------------------------------------------------------------------- /improvr/atoms/Textarea/Textarea.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import "./Textarea.css"; 3 | 4 | const Textarea = ({ children, onChange }) => { 5 | return ( 6 | 12 | ); 13 | }; 14 | 15 | Textarea.propTypes = { 16 | children: PropTypes.node.isRequired, 17 | onChange: PropTypes.func.isRequired, 18 | }; 19 | 20 | export default Textarea; 21 | -------------------------------------------------------------------------------- /frameworks-ui/bootstrap-setup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-setup", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "vite", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "sass": "^1.59.3", 15 | "vite": "^4.2.1" 16 | }, 17 | "dependencies": { 18 | "@popperjs/core": "^2.11.6", 19 | "bootstrap": "^5.2.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /practica-blog-next/styles/components/input.scss: -------------------------------------------------------------------------------- 1 | @use "../tools"; 2 | 3 | .input { 4 | padding: 12px; 5 | height: 48px; 6 | width: 100%; 7 | color: var(--color-black-pearl-700); 8 | background: var(--color-black-pearl-100); 9 | border-radius: 2px; 10 | border: 1px solid transparent; 11 | 12 | font-weight: 400; 13 | font-size: 16px; 14 | line-height: 22px; 15 | 16 | @include tools.desktop { 17 | max-width: 290px; 18 | } 19 | } 20 | 21 | input::placeholder { 22 | color: var(--color-black-pearl-400); 23 | } 24 | -------------------------------------------------------------------------------- /practica-blog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "practica-blog", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "vite", 8 | "serve": "vite --host", 9 | "build": "vite build", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "sass": "^1.60.0", 17 | "vite": "^4.2.1" 18 | }, 19 | "dependencies": { 20 | "dayjs": "^1.11.7" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/input.scss: -------------------------------------------------------------------------------- 1 | @use "../tools"; 2 | 3 | .input { 4 | padding: 12px; 5 | height: 48px; 6 | width: 100%; 7 | color: var(--color-black-pearl-700); 8 | background: var(--color-black-pearl-100); 9 | border-radius: 2px; 10 | border: 1px solid transparent; 11 | 12 | font-weight: 400; 13 | font-size: 16px; 14 | line-height: 22px; 15 | 16 | @include tools.desktop { 17 | max-width: 290px; 18 | } 19 | } 20 | 21 | input::placeholder { 22 | color: var(--color-black-pearl-400); 23 | } 24 | -------------------------------------------------------------------------------- /improvr/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /intro-a-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /practica-blog-react/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:react/recommended', 6 | 'plugin:react/jsx-runtime', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | settings: { react: { version: '18.2' } }, 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': 'warn', 14 | "react/prop-types": "off", 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/components/input.scss: -------------------------------------------------------------------------------- 1 | @use "../tools"; 2 | 3 | .input { 4 | padding: 12px; 5 | height: 48px; 6 | width: 100%; 7 | color: var(--color-black-pearl-700); 8 | background: var(--color-black-pearl-100); 9 | border-radius: 2px; 10 | border: 1px solid transparent; 11 | 12 | font-weight: 400; 13 | font-size: 16px; 14 | line-height: 22px; 15 | 16 | @include tools.desktop { 17 | max-width: 290px; 18 | } 19 | } 20 | 21 | input::placeholder { 22 | color: var(--color-black-pearl-400); 23 | } 24 | -------------------------------------------------------------------------------- /improvr/molecules/IconLabel/IconLabel.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import Icon from "../../atoms/Icon"; 3 | 4 | import "./IconLabel.css"; 5 | 6 | const IconLabel = ({ children, icon }) => { 7 | return ( 8 |
9 | 10 | {children} 11 |
12 | ); 13 | }; 14 | 15 | IconLabel.propTypes = { 16 | children: PropTypes.node.isRequired, 17 | icon: PropTypes.string.isRequired, 18 | }; 19 | 20 | export default IconLabel; 21 | -------------------------------------------------------------------------------- /javascript-algorithms/index.js: -------------------------------------------------------------------------------- 1 | import binarySearch from "./binary-search.js"; 2 | import books from "./books.js"; 3 | 4 | import bubbleSort from "./bubble-sort.js"; 5 | 6 | const [, , titleToSearch] = process.argv; 7 | 8 | const sortedBooks = bubbleSort(books, (a, b) => a.title > b.title); 9 | 10 | // console.log(sortedBooks.map((book) => book.title)); 11 | 12 | const foundBook = binarySearch(sortedBooks, titleToSearch, "title"); 13 | 14 | if (foundBook) { 15 | console.log(foundBook); 16 | } else { 17 | console.log("Book not found"); 18 | } 19 | -------------------------------------------------------------------------------- /mongoose/posts/schema.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | export const postSchema = mongoose.Schema({ 4 | permalink: { 5 | type: String, 6 | unique: true, 7 | required: true, 8 | }, 9 | title: { 10 | type: String, 11 | required: true, 12 | }, 13 | body: { 14 | type: String, 15 | required: true, 16 | }, 17 | author: { 18 | type: String, 19 | required: true, 20 | }, 21 | tags: { 22 | type: [String], 23 | }, 24 | date: { 25 | type: Date, 26 | required: true, 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /practica-blog-next/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Paragraph/Paragraph.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import "./Paragraph.scss"; 3 | 4 | const Paragraph = ({ 5 | as: Component = "span", 6 | children, 7 | size = "sm", 8 | isHelpText, 9 | }) => { 10 | return ( 11 | 17 | {children} 18 | 19 | ); 20 | }; 21 | 22 | export default Paragraph; 23 | -------------------------------------------------------------------------------- /improvr-components/.storybook/main.js: -------------------------------------------------------------------------------- 1 | /** @type { import('@storybook/react-vite').StorybookConfig } */ 2 | const config = { 3 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], 4 | addons: [ 5 | "@storybook/addon-links", 6 | "@storybook/addon-essentials", 7 | "@storybook/addon-onboarding", 8 | "@storybook/addon-interactions", 9 | ], 10 | framework: { 11 | name: "@storybook/react-vite", 12 | options: {}, 13 | }, 14 | docs: { 15 | autodocs: "tag", 16 | }, 17 | }; 18 | export default config; 19 | -------------------------------------------------------------------------------- /improvr/.storybook/main.js: -------------------------------------------------------------------------------- 1 | /** @type { import('@storybook/nextjs').StorybookConfig } */ 2 | const config = { 3 | stories: [ 4 | "../**/*.mdx", 5 | "../**/*.stories.@(js|jsx|mjs|ts|tsx)", 6 | ], 7 | addons: [ 8 | "@storybook/addon-links", 9 | "@storybook/addon-essentials", 10 | "@storybook/addon-onboarding", 11 | "@storybook/addon-interactions", 12 | ], 13 | framework: { 14 | name: "@storybook/nextjs", 15 | options: {}, 16 | }, 17 | docs: { 18 | autodocs: "tag", 19 | }, 20 | }; 21 | export default config; 22 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Button/Button.css: -------------------------------------------------------------------------------- 1 | .button { 2 | border: 1px solid transparent; 3 | border-radius: 4px; 4 | padding: 5px 10px; 5 | cursor: pointer; 6 | } 7 | 8 | .button:hover { 9 | background: color-mix(in srgb, mediumblue 80%, black 20%); 10 | } 11 | 12 | .button:active { 13 | background: color-mix(in srgb, mediumblue 50%, black 50%); 14 | } 15 | 16 | .type-primary { 17 | background: mediumblue; 18 | color: white; 19 | } 20 | 21 | .type-secondary { 22 | background: white; 23 | color: mediumblue; 24 | border: 1px solid mediumblue; 25 | } -------------------------------------------------------------------------------- /practica-blog-next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "practica-blog-next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "classnames": "^2.3.2", 13 | "dayjs": "^1.11.7", 14 | "eslint": "8.40.0", 15 | "eslint-config-next": "13.4.1", 16 | "minireset.css": "^0.0.7", 17 | "next": "13.4.1", 18 | "react": "18.2.0", 19 | "react-dom": "18.2.0", 20 | "sass": "^1.62.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /practica-blog-next/components/Link/Link.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import styles from "./Link.module.scss"; 3 | 4 | // FIXME: font-bold is not be taking 5 | const Link = ({ children, href = "#", isActive }) => { 6 | return ( 7 | 18 | {children} 19 | 20 | ); 21 | }; 22 | 23 | export default Link; 24 | -------------------------------------------------------------------------------- /improvr/organisms/Result/Result.stories.js: -------------------------------------------------------------------------------- 1 | import Result from "./Result"; 2 | 3 | export default { 4 | component: Result, 5 | tags: ["autodocs"], 6 | }; 7 | 8 | export const Grammar = { 9 | args: { 10 | type: "grammar", 11 | text: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", 12 | }, 13 | }; 14 | 15 | export const Translated = { 16 | args: { 17 | type: "translate", 18 | text: "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /improvr-components/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: ['eslint:recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended'], 5 | ignorePatterns: ['dist', '.eslintrc.cjs'], 6 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 7 | settings: { react: { version: '18.2' } }, 8 | plugins: ['react-refresh'], 9 | rules: { 10 | 'react-refresh/only-export-components': [ 11 | 'warn', 12 | { allowConstantExport: true }, 13 | ], 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /frameworks-ui/tailwind-setup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind-setup", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev:css": "tailwindcss -i ./src/input.css -o ./src/output.css --watch", 8 | "dev:src": "vite src", 9 | "dev": "concurrently \"npm run dev:css\" \"npm run dev:src\"", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "concurrently": "^7.6.0", 17 | "tailwindcss": "^3.2.7", 18 | "vite": "^4.2.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /improvr/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-next/components/Paragraph/Paragraph.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import styles from "./Paragraph.module.scss"; 3 | 4 | const Paragraph = ({ 5 | as: Component = "span", 6 | children, 7 | size = "sm", 8 | weight = "regular", 9 | isHelpText, 10 | }) => { 11 | return ( 12 | 19 | {children} 20 | 21 | ); 22 | }; 23 | 24 | export default Paragraph; 25 | -------------------------------------------------------------------------------- /improvr/atoms/Button/Button.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import "./Button.css"; 3 | 4 | const Button = ({ children, type = "primary", className = "", onClick }) => { 5 | const typeClass = type ? `type-${type}` : ""; 6 | 7 | return ( 8 | 11 | ); 12 | }; 13 | 14 | Button.propTypes = { 15 | children: PropTypes.node.isRequired, 16 | onClick: PropTypes.func.isRequired, 17 | type: PropTypes.oneOf(["primary", "secondary"]).isRequired, 18 | className: PropTypes.string, 19 | }; 20 | 21 | export default Button; 22 | -------------------------------------------------------------------------------- /improvr/atoms/Icon/Icon.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import "./Icon.css"; 3 | 4 | const iconMap = { 5 | arrowDown: "🔽", 6 | grammar: "📖", 7 | translate: "🔤", 8 | close: "❌", 9 | copy: "📋", 10 | }; 11 | 12 | const Icon = ({ className, name, onClick }) => ( 13 | 17 | {iconMap[name]} 18 | 19 | ); 20 | 21 | Icon.propTypes = { 22 | className: PropTypes.string, 23 | name: PropTypes.oneOf(Object.keys(iconMap)).isRequired, 24 | onClick: PropTypes.func, 25 | }; 26 | 27 | export default Icon; 28 | -------------------------------------------------------------------------------- /improvr/molecules/ButtonIcon/ButtonIcon.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import Button from "../../atoms/Button"; 3 | import Icon from "../../atoms/Icon"; 4 | 5 | const ButtonIcon = ({ children, type, icon, onClick }) => { 6 | return ( 7 | 11 | ); 12 | }; 13 | 14 | ButtonIcon.propTypes = { 15 | children: PropTypes.node.isRequired, 16 | icon: PropTypes.string.isRequired, 17 | onClick: PropTypes.func.isRequired, 18 | type: PropTypes.oneOf(["primary", "secondary"]), 19 | }; 20 | 21 | export default ButtonIcon; 22 | -------------------------------------------------------------------------------- /fechas-javascript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fechas-javascript", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "fechas-javascript", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "dayjs": "^1.11.7" 13 | } 14 | }, 15 | "node_modules/dayjs": { 16 | "version": "1.11.7", 17 | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", 18 | "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /improvr-components/src/atoms/Button/Button.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import "./Button.css"; 3 | 4 | const Button = ({ children, type = "primary", className = "", onClick }) => { 5 | const typeClass = type ? `type-${type}` : ""; 6 | 7 | return ( 8 | 11 | ); 12 | }; 13 | 14 | Button.propTypes = { 15 | children: PropTypes.node.isRequired, 16 | onClick: PropTypes.func.isRequired, 17 | type: PropTypes.oneOf(["primary", "secondary"]).isRequired, 18 | className: PropTypes.string, 19 | }; 20 | 21 | export default Button; 22 | -------------------------------------------------------------------------------- /biblioteca-utilidades/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "biblioteca-utilidades", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "biblioteca-utilidades", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "lodash": "^4.17.21" 13 | } 14 | }, 15 | "node_modules/lodash": { 16 | "version": "4.17.21", 17 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 18 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /intro-to-mongo/index.js: -------------------------------------------------------------------------------- 1 | const dotenv = require("dotenv"); 2 | dotenv.config(); 3 | 4 | const express = require("express"); 5 | const mongo = require("./mongo"); 6 | 7 | const PORT = process.env.PORT; 8 | const app = express(); 9 | 10 | app.get("/", (req, res) => { 11 | res.send("API is running"); 12 | }); 13 | 14 | app.get("/posts", async (req, res) => { 15 | const posts = await mongo.getAll("posts"); 16 | res.json({ posts }); 17 | }); 18 | 19 | app.post("/create-post", (req, res) => { 20 | const post = {}; 21 | res.json({ post }); 22 | }); 23 | 24 | app.listen( 25 | PORT, 26 | console.log(`🌍 Server running on port http://localhost:${PORT}`) 27 | ); 28 | -------------------------------------------------------------------------------- /practica-blog-next/pages/_document.js: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from "next/document"; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /extendiendo-sass/styles/main.scss: -------------------------------------------------------------------------------- 1 | @use "base.scss"; 2 | 3 | main { 4 | padding: 0 20px; 5 | } 6 | 7 | $color-main: #0074d9; 8 | 9 | @mixin center($ancho, $alto) { 10 | position: absolute; 11 | top: 50%; 12 | left: 50%; 13 | transform: translate(-50%, -50%); 14 | width: $ancho; 15 | height: $alto; 16 | } 17 | 18 | .button { 19 | background: $color-main; 20 | color: white; 21 | padding: 16px 64px; 22 | border-radius: 8px; 23 | border: none; 24 | 25 | @include center(200px, 50px); 26 | 27 | @if $color-main == #0074d9 { 28 | &:hover { 29 | background-color: darkblue; 30 | } 31 | } 32 | } 33 | 34 | @for $i from 1 through 5 { 35 | .text-#{$i} { 36 | font-size: $i * 10px; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /introduccion-a-node/file-example.js: -------------------------------------------------------------------------------- 1 | // import fs from 'fs'; (ESM) 2 | const fs = require("fs"); // Common.js 3 | 4 | // Error first callback 5 | 6 | function writeFileCallback(error) { 7 | if (error) { 8 | console.error("Error al escribir el archivo", error); 9 | } else { 10 | console.log("El archivo se escribió correctamente"); 11 | } 12 | } 13 | 14 | fs.writeFile("logs.txt", "JaváScript", writeFileCallback); 15 | 16 | function readFileCallback(error, data) { 17 | if (error) { 18 | console.error("Error al leer el archivo", error); 19 | } else { 20 | console.log(`El archivo se leyó correctamente "${data}"`, data); 21 | } 22 | } 23 | 24 | fs.readFile("logs.txt", "utf8", readFileCallback); -------------------------------------------------------------------------------- /practica-blog/src/scripts/utils/humanize.js: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | import relativeTime from "dayjs/plugin/relativeTime.js"; 3 | 4 | import("dayjs/locale/es-us.js"); 5 | 6 | dayjs.locale("es-us"); 7 | dayjs.extend(relativeTime); 8 | 9 | export default function humanize(date) { 10 | const wrappedDate = dayjs(date); 11 | const daysDiff = Math.abs(wrappedDate.diff(Date.now(), "days")); 12 | 13 | const isCurrentYear = wrappedDate.year() === new Date().getFullYear(); 14 | 15 | if (!isCurrentYear) { 16 | return wrappedDate.format("MMMM DD, YYYY"); 17 | } else if (daysDiff <= 30) { 18 | return wrappedDate.fromNow(); 19 | } else { 20 | return wrappedDate.format("MMMM DD"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /practica-blog-next/components/Button/Button.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames/bind"; 2 | import styles from "./Button.module.scss"; 3 | 4 | // CSS modules 5 | // style { 6 | // button {}, 7 | // "button-primary" {}, 8 | // "button-secondary" {}, 9 | // } 10 | // styles["button-${type}"] 11 | 12 | // { 13 | // [styles["button-${type}"]]: type 14 | // } 15 | 16 | const cx = classNames.bind(styles); 17 | 18 | const Button = ({ children, type = "primary", onClick }) => { 19 | return ( 20 | 28 | ); 29 | }; 30 | 31 | export default Button; 32 | -------------------------------------------------------------------------------- /practica-blog-react/src/utils/humanize.js: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | import relativeTime from "dayjs/plugin/relativeTime.js"; 3 | 4 | await import("dayjs/locale/es-us.js"); 5 | 6 | dayjs.locale("es-us"); 7 | dayjs.extend(relativeTime); 8 | 9 | const humanize = (date) => { 10 | const wrappedDate = dayjs(date); 11 | const daysDiff = Math.abs(wrappedDate.diff(Date.now(), "days")); 12 | 13 | const isCurrentYear = wrappedDate.year() === new Date().getFullYear(); 14 | 15 | if (!isCurrentYear) { 16 | return wrappedDate.format("MMMM DD, YYYY"); 17 | } else if (daysDiff <= 30) { 18 | return wrappedDate.fromNow(); 19 | } else { 20 | return wrappedDate.format("MMMM DD"); 21 | } 22 | }; 23 | 24 | export default humanize; -------------------------------------------------------------------------------- /practica-blog/src/scripts/main.js: -------------------------------------------------------------------------------- 1 | import sortByDate from "./utils/sortByDate.js"; 2 | import humanizeDate from "./utils/humanizeDate.js"; 3 | 4 | function humanizeArticlesDate() { 5 | const $dates = document.querySelectorAll("time"); 6 | $dates.forEach(humanizeDate); 7 | } 8 | 9 | function sortArticlesByDate() { 10 | const $cards = document.querySelectorAll(".post-list .card"); 11 | const $cardsSorted = [...$cards].sort(sortByDate); 12 | const $postList = document.querySelector(".post-list"); 13 | 14 | [...$postList.children].forEach(($child) => $child.remove()); 15 | $postList.append(...$cardsSorted); 16 | } 17 | 18 | function main() { 19 | humanizeArticlesDate(); 20 | sortArticlesByDate(); 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /improvr/molecules/SplitButton/SplitButton.css: -------------------------------------------------------------------------------- 1 | .split-button-container { 2 | position: relative; 3 | display: inline-block; 4 | cursor: pointer; 5 | } 6 | 7 | .split-button { 8 | position: relative; 9 | user-select: none; 10 | } 11 | 12 | .split-button-select { 13 | right: 0; 14 | top: 0; 15 | bottom: 0; 16 | cursor: pointer; 17 | width: 25px; 18 | height: 34px; 19 | } 20 | 21 | .split-button-arrow { 22 | position: absolute; 23 | right: 0; 24 | top: 0; 25 | bottom: 0; 26 | z-index: 1; 27 | height: 100%; 28 | background: mediumblue; 29 | width: 30px; 30 | pointer-events: none; 31 | border-radius: 0 4px 4px 0; 32 | } 33 | 34 | .split-button-arrow:hover { 35 | background: color-mix(in srgb, mediumblue 80%, black 20%); 36 | } -------------------------------------------------------------------------------- /practica-blog/src/styles/settings.scss: -------------------------------------------------------------------------------- 1 | // Custom properties (CSS Variables) 2 | :root { 3 | --color-white: #fff; 4 | 5 | --color-black-pearl-50: #e4ebee; 6 | --color-black-pearl-100: #c9d6de; 7 | --color-black-pearl-400: #7799ac; 8 | --color-black-pearl-700: #3c5562; 9 | --color-black-pearl-800: #2c3d47; 10 | --color-black-pearl-900: #1b262c; 11 | 12 | --color-aquarius-50: #e2f5f7; 13 | --color-aquarius-100: #c5eaf0; 14 | --color-aquarius-700: #288996; 15 | --color-aquarius-600: #35b6c8; 16 | --color-aquarius-900: #0d2e32; 17 | 18 | --color-morrocan-blue-100: #b5dbf5; 19 | 20 | --container-max-width: 1180px; 21 | --container-padding: 0 24px; 22 | } 23 | 24 | // SASS Variables 25 | $breakpoint-large: 992px; 26 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/settings.scss: -------------------------------------------------------------------------------- 1 | // Custom properties (CSS Variables) 2 | :root { 3 | --color-white: #fff; 4 | 5 | --color-black-pearl-50: #e4ebee; 6 | --color-black-pearl-100: #c9d6de; 7 | --color-black-pearl-400: #7799ac; 8 | --color-black-pearl-700: #3c5562; 9 | --color-black-pearl-800: #2c3d47; 10 | --color-black-pearl-900: #1b262c; 11 | 12 | --color-aquarius-50: #e2f5f7; 13 | --color-aquarius-100: #c5eaf0; 14 | --color-aquarius-700: #288996; 15 | --color-aquarius-600: #35b6c8; 16 | --color-aquarius-900: #0d2e32; 17 | 18 | --color-morrocan-blue-100: #b5dbf5; 19 | 20 | --container-max-width: 1180px; 21 | --container-padding: 0 24px; 22 | } 23 | 24 | // SASS Variables 25 | $breakpoint-large: 992px; 26 | -------------------------------------------------------------------------------- /intro-a-react/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { Component } from "react"; 2 | import { Card } from "./Card"; 3 | 4 | class App extends Component { 5 | render() { 6 | const articles = [ 7 | { 8 | title: "Oi Mundo", 9 | text: "Como vai?", 10 | }, 11 | { 12 | title: "Hello", 13 | text: "How are you?", 14 | }, 15 | { 16 | title: "Hello", 17 | text: "How are you", 18 | }, 19 | { 20 | title: "Hej", 21 | text: "Värld", 22 | }, 23 | ]; 24 | 25 | return ( 26 | <> 27 | {articles.map(({ title, text }) => ( 28 | {text} 29 | ))} 30 | 31 | ); 32 | } 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/tags-filter.scss: -------------------------------------------------------------------------------- 1 | @use "../tools"; 2 | 3 | .tags-filter { 4 | display: flex; 5 | flex-wrap: wrap; 6 | justify-content: space-between; 7 | align-items: baseline; 8 | gap: 24px 0; 9 | 10 | @include tools.desktop { 11 | flex-wrap: nowrap; 12 | } 13 | } 14 | 15 | .tags-filter .filter-list { 16 | gap: 32px; 17 | } 18 | 19 | .filter-list { 20 | overflow-y: hidden; 21 | overflow-x: auto; 22 | height: 50px; 23 | } 24 | 25 | .filter { 26 | white-space: nowrap; 27 | } 28 | 29 | .is-active-filter .filter { 30 | background-color: var(--color-black-pearl-900); 31 | color: var(--color-aquarius-50); 32 | padding: 8px 12px; 33 | } 34 | 35 | .filter-list-scroll-hider { 36 | overflow-y: hidden; 37 | height: 40px; 38 | } 39 | -------------------------------------------------------------------------------- /intro-a-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "intro-a-react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "^18.0.28", 18 | "@types/react-dom": "^18.0.11", 19 | "@vitejs/plugin-react": "^4.0.0-beta.0", 20 | "eslint": "^8.38.0", 21 | "eslint-plugin-react": "^7.32.2", 22 | "eslint-plugin-react-hooks": "^4.6.0", 23 | "eslint-plugin-react-refresh": "^0.3.4", 24 | "vite": "^4.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /practica-blog-next/components/TagsFilter/TagsFilter.module.scss: -------------------------------------------------------------------------------- 1 | @use "../../styles/tools"; 2 | 3 | .tags-filter { 4 | display: flex; 5 | flex-wrap: wrap; 6 | justify-content: space-between; 7 | align-items: baseline; 8 | gap: 24px 0; 9 | 10 | @include tools.desktop { 11 | flex-wrap: nowrap; 12 | } 13 | } 14 | 15 | .tags-filter .filter-list { 16 | gap: 32px; 17 | } 18 | 19 | .filter-list { 20 | overflow-y: hidden; 21 | overflow-x: auto; 22 | height: 50px; 23 | } 24 | 25 | .filter { 26 | white-space: nowrap; 27 | } 28 | 29 | .is-active-filter .filter { 30 | background-color: var(--color-black-pearl-900); 31 | color: var(--color-aquarius-50); 32 | padding: 8px 12px; 33 | } 34 | 35 | .filter-list-scroll-hider { 36 | overflow-y: hidden; 37 | height: 40px; 38 | } 39 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/TagsFilter/TagsFilter.scss: -------------------------------------------------------------------------------- 1 | @use "../../styles/tools"; 2 | 3 | .tags-filter { 4 | display: flex; 5 | flex-wrap: wrap; 6 | justify-content: space-between; 7 | align-items: baseline; 8 | gap: 24px 0; 9 | 10 | @include tools.desktop { 11 | flex-wrap: nowrap; 12 | } 13 | } 14 | 15 | .tags-filter .filter-list { 16 | gap: 32px; 17 | } 18 | 19 | .filter-list { 20 | overflow-y: hidden; 21 | overflow-x: auto; 22 | height: 50px; 23 | } 24 | 25 | .filter { 26 | white-space: nowrap; 27 | } 28 | 29 | .is-active-filter .filter { 30 | background-color: var(--color-black-pearl-900); 31 | color: var(--color-aquarius-50); 32 | padding: 8px 12px; 33 | } 34 | 35 | .filter-list-scroll-hider { 36 | overflow-y: hidden; 37 | height: 40px; 38 | } 39 | -------------------------------------------------------------------------------- /intro-a-react/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /mongoose/index.js: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | dotenv.config(); 3 | 4 | import express from "express"; 5 | import mongoose from "mongoose"; 6 | 7 | import { postRouter } from "./posts/router.js"; 8 | 9 | const { PORT, MONGO_USERNAME, MONGO_PASSWORD, MONGO_HOSTNAME } = process.env; 10 | const MONGO_URI = `mongodb+srv://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}/?retryWrites=true&w=majority`; 11 | 12 | const app = express(); 13 | 14 | // Global Middlewares 15 | app.use(express.json()); 16 | 17 | // Routes 18 | app.get("/", (req, res) => res.send("API is running")); 19 | app.use("/posts", postRouter); 20 | 21 | app.listen(PORT, () => { 22 | console.log(`🌍 Server running on port http://localhost:${PORT}`); 23 | mongoose.connect(MONGO_URI, { 24 | dbName: "sample_training", 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /css-responsive/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CSS Responsive 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | Header 16 |
17 |
18 | Content 19 |
20 | 23 |
24 |
25 | Feature 26 |
27 |
28 | Feature 29 |
30 |
31 | Feature 32 |
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /improvr-components/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /practica-blog-next/utils/humanize.js: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | import relativeTime from "dayjs/plugin/relativeTime.js"; 3 | 4 | // IIFE > Inmediatly Invoked Function Expression 5 | (async () => { 6 | await import("dayjs/locale/es-us.js"); 7 | dayjs.locale("es-us"); 8 | })(); 9 | 10 | dayjs.extend(relativeTime); 11 | 12 | 13 | const humanize = (date) => { 14 | const wrappedDate = dayjs(date); 15 | const daysDiff = Math.abs(wrappedDate.diff(Date.now(), "days")); 16 | 17 | const isCurrentYear = wrappedDate.year() === new Date().getFullYear(); 18 | 19 | if (!isCurrentYear) { 20 | return wrappedDate.format("MMMM DD, YYYY"); 21 | } else if (daysDiff <= 30) { 22 | return wrappedDate.fromNow(); 23 | } else { 24 | return wrappedDate.format("MMMM DD"); 25 | } 26 | }; 27 | 28 | export default humanize; 29 | -------------------------------------------------------------------------------- /improvr-components/src/molecules/DropdownButton/DropdownButton.css: -------------------------------------------------------------------------------- 1 | .dropdown-button-container { 2 | position: relative; 3 | display: inline-block; 4 | cursor: pointer; 5 | } 6 | 7 | .dropdown-button { 8 | position: relative; 9 | user-select: none; 10 | } 11 | 12 | .dropdown-button-select { 13 | right: 0; 14 | top: 0; 15 | bottom: 0; 16 | cursor: pointer; 17 | width: 25px 18 | } 19 | 20 | .dropdown-button-arrow { 21 | position: absolute; 22 | right: 0; 23 | top: 0; 24 | bottom: 0; 25 | z-index: 1; 26 | height: 100%; 27 | background: mediumblue; 28 | width: 30px; 29 | pointer-events: none; 30 | display: inline-flex; 31 | align-items: center; 32 | justify-content: center; 33 | border-radius: 0 4px 4px 0; 34 | } 35 | 36 | .dropdown-button-arrow:hover { 37 | background: color-mix(in srgb, mediumblue 80%, black 20%); 38 | } -------------------------------------------------------------------------------- /practica-blog-next/styles/main.css: -------------------------------------------------------------------------------- 1 | /* settings */ 2 | :root { 3 | --color-white: #fff; 4 | 5 | --color-black-pearl-50: #e4ebee; 6 | --color-black-pearl-100: #c9d6de; 7 | --color-black-pearl-400: #7799ac; 8 | --color-black-pearl-700: #3c5562; 9 | --color-black-pearl-800: #2c3d47; 10 | --color-black-pearl-900: #1b262c; 11 | 12 | --color-aquarius-50: #e2f5f7; 13 | --color-aquarius-100: #c5eaf0; 14 | --color-aquarius-700: #288996; 15 | --color-aquarius-600: #35b6c8; 16 | --color-aquarius-900: #0d2e32; 17 | 18 | --color-morrocan-blue-100: #b5dbf5; 19 | 20 | --container-max-width: 1180px; 21 | --container-padding: 0 24px; 22 | } 23 | 24 | /* Generic */ 25 | a { 26 | text-decoration: none; 27 | } 28 | 29 | /* utilities */ 30 | .font-regular { 31 | font-weight: 400; 32 | } 33 | 34 | .font-bold { 35 | font-weight: 700; 36 | } -------------------------------------------------------------------------------- /introduccion-a-node/cli-example.js: -------------------------------------------------------------------------------- 1 | // console.log(process.argv); 2 | 3 | function printType(type) { 4 | if (type === "--dev" || type === "-D") { 5 | return "desarrollo"; 6 | } 7 | 8 | return "" 9 | } 10 | 11 | function installPackages(type, packages) { 12 | console.log(`Instalando \`${packages.join(", ")}\` de tipo \`${printType(type)}\``); 13 | } 14 | 15 | function removePackages(type, packages) { 16 | console.log(`Removiendo \`${packages.join(", ")}\` de tipo \`${printType(type)}\``); 17 | } 18 | 19 | // const params = process.argv 20 | // const action = params[2] 21 | // const type = params[3] 22 | // const packages = params[4] 23 | 24 | const [, , action, type, ...packages] = process.argv; 25 | 26 | if (action === "install") { 27 | installPackages(type, packages); 28 | } 29 | 30 | if (action === "remove") { 31 | removePackages(type, packages); 32 | } 33 | -------------------------------------------------------------------------------- /practica-blog-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "practica-blog-react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "classnames": "^2.3.2", 14 | "dayjs": "^1.11.7", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^18.0.28", 20 | "@types/react-dom": "^18.0.11", 21 | "@vitejs/plugin-react": "^4.0.0", 22 | "eslint": "^8.38.0", 23 | "eslint-plugin-react": "^7.32.2", 24 | "eslint-plugin-react-hooks": "^4.6.0", 25 | "eslint-plugin-react-refresh": "^0.3.4", 26 | "sass": "^1.62.1", 27 | "vite": "^4.3.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /practica-blog-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | Undefined Shell Blog 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /frameworks-ui/bootstrap-setup/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |

Hello, Bootstrap and Vite!

12 | 13 | 14 |
15 | ... 16 |
17 |
Card title
18 |

Some quick example text to build on the card title and make up the bulk of the card's content.

19 | Go somewhere 20 |
21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /fechas-javascript/index.js: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs" 2 | import relativeTime from "dayjs/plugin/relativeTime.js" 3 | 4 | await import("dayjs/locale/es-us.js") 5 | 6 | dayjs.locale("es-us") 7 | dayjs.extend(relativeTime) 8 | 9 | function humanize(date) { 10 | const wrappedDate = dayjs(date) 11 | const daysDiff = Math.abs(wrappedDate.diff(Date.now(), "days")); 12 | 13 | const isCurrentYear = wrappedDate.year() === new Date().getFullYear(); 14 | 15 | if(!isCurrentYear) { 16 | return wrappedDate.format("MMMM DD, YYYY") 17 | } else if(daysDiff <= 30) { 18 | return wrappedDate.fromNow(); 19 | } else { 20 | return wrappedDate.format("MMMM DD") 21 | } 22 | } 23 | 24 | console.log(humanize(Date.now())) 25 | console.log(humanize(dayjs().subtract(5, "days"))) 26 | console.log(humanize(dayjs().subtract(60, "days"))) 27 | console.log(humanize(dayjs().subtract(500, "days"))) 28 | console.log(humanize(dayjs().add(30, "days"))) 29 | console.log(humanize(dayjs().add(300, "days"))) -------------------------------------------------------------------------------- /css-flexbox-grid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSS Flexbox & Grid 6 | 7 | 8 | 9 |
10 |
Header
11 |
Main
12 |
Sidebar
13 |
Footer
14 |
15 |
16 |
1
17 |
2
18 |
3
19 |
4
20 |
5
21 |
6
22 |
7
23 |
8
24 |
9
25 |
10
26 |
11
27 |
12
28 |
13
29 |
14
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /extendiendo-sass/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Document 10 | 11 | 12 | 13 |
14 |

Hello world

15 |

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Laborum quisquam quis nihil quam eius voluptatem 16 | similique perferendis ex ad aut nostrum fugit, veritatis quas suscipit, praesentium quo? Facere, atque 17 | libero.

18 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quam provident eos alias ducimus quo, corporis 19 | voluptate consectetur laudantium voluptatem sequi temporibus nam cupiditate asperiores nihil quod illo, 20 | optio eligendi velit?

21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /improvr/atoms/Button/Button.css: -------------------------------------------------------------------------------- 1 | .button { 2 | border: 1px solid transparent; 3 | border-radius: 4px; 4 | padding: 5px 10px; 5 | cursor: pointer; 6 | display: inline-flex; 7 | gap: 5px; 8 | align-items: center; 9 | height: 34px; 10 | } 11 | 12 | .type-primary { 13 | background: mediumblue; 14 | color: white; 15 | } 16 | 17 | .type-primary:hover { 18 | background: color-mix(in srgb, mediumblue 80%, black 20%); 19 | } 20 | 21 | .type-primary:active { 22 | background: color-mix(in srgb, mediumblue 50%, black 50%); 23 | } 24 | 25 | .type-secondary { 26 | background: white; 27 | color: mediumblue; 28 | border: 1px solid mediumblue; 29 | } 30 | 31 | .type-secondary:hover { 32 | --hover-color: color-mix(in srgb, mediumblue 80%, black 20%); 33 | color: var(--hover-color); 34 | border: 1px solid var(--hover-color); 35 | } 36 | 37 | .type-secondary:active { 38 | --active-color: color-mix(in srgb, mediumblue 50%, black 50%); 39 | color: var(--active-color); 40 | border: 1px solid var(--active-color); 41 | } -------------------------------------------------------------------------------- /improvr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "improvr", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "storybook": "storybook dev -p 6006", 11 | "build-storybook": "storybook build" 12 | }, 13 | "dependencies": { 14 | "eslint": "8.49.0", 15 | "eslint-config-next": "13.4.19", 16 | "next": "13.4.19", 17 | "openai": "^4.6.0", 18 | "react": "18.2.0", 19 | "react-dom": "18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@storybook/addon-essentials": "^7.4.1", 23 | "@storybook/addon-interactions": "^7.4.1", 24 | "@storybook/addon-links": "^7.4.1", 25 | "@storybook/addon-onboarding": "^1.0.8", 26 | "@storybook/blocks": "^7.4.1", 27 | "@storybook/nextjs": "^7.4.1", 28 | "@storybook/react": "^7.4.1", 29 | "@storybook/testing-library": "^0.2.0", 30 | "eslint-plugin-storybook": "^0.6.13", 31 | "storybook": "^7.4.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /practica-blog/src/styles/components/button.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | display: inline-flex; 3 | padding: 12px 16px; 4 | align-items: center; 5 | gap: 8px; 6 | height: 56px; 7 | border-radius: 2px; 8 | cursor: pointer; 9 | border: 1px solid transparent; 10 | font-weight: 700; 11 | font-size: 15px; 12 | line-height: 25px; 13 | color: var(--color-aquarius-50); 14 | transition: background 0.2s ease-in-out; 15 | } 16 | 17 | .button-primary { 18 | background: var(--color-aquarius-600); 19 | 20 | &:hover { 21 | background: var(--color-aquarius-700); 22 | box-shadow: 0px 6px 10px rgba(44, 159, 175, 0.17); 23 | } 24 | 25 | &:disabled { 26 | background: var(--color-aquarius-200); 27 | } 28 | } 29 | 30 | .button-secondary { 31 | background: var(--color-black-pearl-900); 32 | 33 | &:hover { 34 | background: var(--color-black-pearl-800); 35 | box-shadow: 0px 6px 10px rgba(27, 38, 44, 0.16); 36 | } 37 | 38 | &:disabled { 39 | background: var(--color-black-pearl-200); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Button/Button.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | display: inline-flex; 3 | padding: 12px 16px; 4 | align-items: center; 5 | gap: 8px; 6 | height: 56px; 7 | border-radius: 2px; 8 | cursor: pointer; 9 | border: 1px solid transparent; 10 | font-weight: 700; 11 | font-size: 15px; 12 | line-height: 25px; 13 | color: var(--color-aquarius-50); 14 | transition: background 0.2s ease-in-out; 15 | } 16 | 17 | .button-primary { 18 | background: var(--color-aquarius-600); 19 | 20 | &:hover { 21 | background: var(--color-aquarius-700); 22 | box-shadow: 0px 6px 10px rgba(44, 159, 175, 0.17); 23 | } 24 | 25 | &:disabled { 26 | background: var(--color-aquarius-200); 27 | } 28 | } 29 | 30 | .button-secondary { 31 | background: var(--color-black-pearl-900); 32 | 33 | &:hover { 34 | background: var(--color-black-pearl-800); 35 | box-shadow: 0px 6px 10px rgba(27, 38, 44, 0.16); 36 | } 37 | 38 | &:disabled { 39 | background: var(--color-black-pearl-200); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /practica-blog-next/components/Button/Button.module.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | display: inline-flex; 3 | padding: 12px 16px; 4 | align-items: center; 5 | gap: 8px; 6 | height: 56px; 7 | border-radius: 2px; 8 | cursor: pointer; 9 | border: 1px solid transparent; 10 | font-weight: 700; 11 | font-size: 15px; 12 | line-height: 25px; 13 | color: var(--color-aquarius-50); 14 | transition: background 0.2s ease-in-out; 15 | } 16 | 17 | .button-primary { 18 | background: var(--color-aquarius-600); 19 | 20 | &:hover { 21 | background: var(--color-aquarius-700); 22 | box-shadow: 0px 6px 10px rgba(44, 159, 175, 0.17); 23 | } 24 | 25 | &:disabled { 26 | background: var(--color-aquarius-200); 27 | } 28 | } 29 | 30 | .button-secondary { 31 | background: var(--color-black-pearl-900); 32 | 33 | &:hover { 34 | background: var(--color-black-pearl-800); 35 | box-shadow: 0px 6px 10px rgba(27, 38, 44, 0.16); 36 | } 37 | 38 | &:disabled { 39 | background: var(--color-black-pearl-200); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /extendiendo-sass/styles/main.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | box-sizing: border-box; 6 | } 7 | 8 | * { 9 | box-sizing: inherit; 10 | } 11 | 12 | body { 13 | max-width: 800px; 14 | margin: 0 auto; 15 | background-color: whitesmoke; 16 | font-family: Arial, Helvetica, sans-serif; 17 | font-size: 16px; 18 | } 19 | 20 | main { 21 | padding: 0 20px; 22 | } 23 | 24 | .button { 25 | background: #0074d9; 26 | color: white; 27 | padding: 16px 64px; 28 | border-radius: 8px; 29 | border: none; 30 | position: absolute; 31 | top: 50%; 32 | left: 50%; 33 | transform: translate(-50%, -50%); 34 | width: 200px; 35 | height: 50px; 36 | } 37 | .button:hover { 38 | background-color: darkblue; 39 | } 40 | 41 | .text-1 { 42 | font-size: 10px; 43 | } 44 | 45 | .text-2 { 46 | font-size: 20px; 47 | } 48 | 49 | .text-3 { 50 | font-size: 30px; 51 | } 52 | 53 | .text-4 { 54 | font-size: 40px; 55 | } 56 | 57 | .text-5 { 58 | font-size: 50px; 59 | } 60 | 61 | /*# sourceMappingURL=main.css.map */ 62 | -------------------------------------------------------------------------------- /improvr-components/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import reactLogo from './assets/react.svg' 3 | import viteLogo from '/vite.svg' 4 | import './App.css' 5 | 6 | function App() { 7 | const [count, setCount] = useState(0) 8 | 9 | return ( 10 | <> 11 |
12 | 13 | Vite logo 14 | 15 | 16 | React logo 17 | 18 |
19 |

Vite + React

20 |
21 | 24 |

25 | Edit src/App.jsx and save to test HMR 26 |

27 |
28 |

29 | Click on the Vite and React logos to learn more 30 |

31 | 32 | ) 33 | } 34 | 35 | export default App 36 | -------------------------------------------------------------------------------- /css-flexbox-grid/src/styles/base.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-wrap: wrap; 4 | flex-direction: row; 5 | justify-content: center; 6 | align-items: center; 7 | align-content: space-around; 8 | border: 2px dashed rebeccapurple; 9 | height: 100%; 10 | } 11 | 12 | .item, .grid-item { 13 | border: 2px solid coral; 14 | height: 50px; 15 | width: 200px; 16 | background: papayawhip; 17 | font-family: Arial, Helvetica, sans-serif; 18 | font-weight: bold; 19 | text-align: center; 20 | color: coral; 21 | } 22 | 23 | .grid-item { 24 | width: auto; 25 | height: auto; 26 | } 27 | 28 | .grid-container { 29 | display: grid; 30 | grid-template-columns: repeat(4, 1fr); 31 | grid-template-rows: auto; 32 | grid-template-areas: 33 | "header header header header" 34 | "main main main sidebar" 35 | "footer footer footer footer"; 36 | 37 | height: 100%; 38 | border: 2px dashed Teal; 39 | } 40 | 41 | .item-a { 42 | grid-area: header; 43 | } 44 | .item-b { 45 | grid-area: main; 46 | 47 | } 48 | .item-c { 49 | grid-area: sidebar; 50 | } 51 | .item-d { 52 | grid-area: footer; 53 | } -------------------------------------------------------------------------------- /improvr/app/page.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState } from "react"; 4 | import Form from "@/organisms/Form"; 5 | 6 | import styles from "./page.module.css"; 7 | import Result from "@/organisms/Result"; 8 | 9 | export default function Home() { 10 | const [text, setText] = useState(""); 11 | const [lang, setLang] = useState("english"); 12 | const [result, setResult] = useState(null); 13 | 14 | const onTranslate = async () => { 15 | const response = await fetch(`/api/translate?lang=${lang}`, { 16 | method: "POST", 17 | body: JSON.stringify({ text }), 18 | headers: { 19 | "Content-Type": "application/json", 20 | }, 21 | }); 22 | 23 | const { translatedText } = await response.json(); 24 | setResult(translatedText); 25 | }; 26 | 27 | return ( 28 |
29 |
{}} 33 | onTranslate={onTranslate} 34 | onChangeLanguage={setLang} 35 | /> 36 | {result && } 37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /intro-a-express/index.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | 3 | const app = express(); 4 | 5 | app.get("/", (req, res) => { 6 | res.json({ message: "Hello Bootcamp JSON" }); 7 | }); 8 | 9 | app.get("/hello/:name", (req, res) => { 10 | res.json({ message: `Hello ${req.params.name}` }); 11 | }); 12 | 13 | app.get("/sum/:num1/:num2", (req, res) => { 14 | res.send(`${Number(req.params.num1) + Number(req.params.num2)}`); 15 | }); 16 | 17 | // Middleware 18 | app.use(express.json()); 19 | 20 | function fullnameMiddleware(req, res, next) { 21 | const { name, lastname } = req.body; 22 | if (!name || !lastname) { 23 | res.status(400).send("Falta el nombre o el apellido"); 24 | } 25 | 26 | req.fullname = `${name} ${lastname}`; 27 | next(); 28 | } 29 | 30 | app.get("/fullname", fullnameMiddleware, (req, res) => { 31 | const { name, lastname } = req.body; 32 | 33 | console.log(req.fullname); 34 | res.send(`Hello ${name} ${lastname}`); 35 | }); 36 | 37 | app.get("/form", (req, res) => { 38 | console.log(req.query); 39 | res.send("OK!"); 40 | }); 41 | 42 | app.listen(3000, () => console.log("🌍 Server running on port 3000")); 43 | -------------------------------------------------------------------------------- /practica-blog-next/pages/api/posts.js: -------------------------------------------------------------------------------- 1 | const apiUrl = process.env.API_URL || "https://dummyjson.com"; 2 | 3 | const calculateExtract = (text) => { 4 | const MAX_EXTRACT_LENGTH = 50; 5 | const extract = text.split(" ").slice(0, MAX_EXTRACT_LENGTH).join(" "); 6 | 7 | return `${extract} (...)`; 8 | }; 9 | 10 | const calculateTags = (text) => { 11 | const MAX_TAGS_LENGTH = 4; 12 | return text.slice(0, MAX_TAGS_LENGTH); 13 | }; 14 | 15 | const calculateReadTime = (text) => { 16 | const WORDS_PER_MINUTE = 200; 17 | const time = Math.ceil(text.split(" ")?.length / WORDS_PER_MINUTE); 18 | 19 | return `${time} min`; 20 | }; 21 | 22 | export default async function handler(req, res) { 23 | const { posts } = await fetch(`${apiUrl}/posts`).then((data) => data.json()); 24 | 25 | const mappedPosts = posts.map((post) => ({ 26 | unsplashId: "JSQkuSalhH4", 27 | unsplashAlt: "Imagen de un post", 28 | tags: calculateTags(post.tags), 29 | title: post.title, 30 | extract: calculateExtract(post.body), 31 | author: post.author, 32 | readTime: calculateReadTime(post.body), 33 | date: post.date, 34 | })); 35 | 36 | res.status(200).json(mappedPosts); 37 | } 38 | -------------------------------------------------------------------------------- /improvr/organisms/Form/Form.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | 3 | import Textarea from "../../atoms/Textarea"; 4 | import Card from "../../atoms/Card"; 5 | import SplitButton from "../../molecules/SplitButton"; 6 | import ButtonIcon from "../../molecules/ButtonIcon"; 7 | 8 | import "./Form.css"; 9 | 10 | const Form = ({ 11 | value, 12 | onChange, 13 | onGrammar, 14 | onTranslate, 15 | onChangeLanguage, 16 | }) => { 17 | return ( 18 | 19 |
20 | Improvr 21 | 22 |
23 | 24 | Grammar 25 | 26 | 27 |
28 |
29 |
30 | ); 31 | }; 32 | 33 | Form.propTypes = { 34 | text: PropTypes.string.isRequired, 35 | setText: PropTypes.func.isRequired, 36 | onGrammar: PropTypes.func.isRequired, 37 | onTranslate: PropTypes.func.isRequired, 38 | onChangeLanguage: PropTypes.func.isRequired, 39 | }; 40 | 41 | export default Form; 42 | -------------------------------------------------------------------------------- /practica-blog/README.md: -------------------------------------------------------------------------------- 1 | # Undefined Shell Blog 2 | 3 | ## ¿Cómo abordar un proyecto? 4 | 5 | 1. **Analizar la necesidad del proyecto**: Revisar si el proyecto cumple con las necesidades del usuario, preguntarse quien lo va a usar y cómo lo va a usar. 6 | 2. **Revisar la documentación del proyecto**: Si el proyecto tiene documentación, o un archivo de diseño, explorar todos los assets para ir armando un plan. 7 | 2. **Analizar como puedes dividir el problema:** Revisar si vas a empezar por la maquetación, si vas realizar el layout primero, que tecnologías vas a usar, que metolodogías vas a usar. Un elefante se come un mordisco a la vez. 8 | 3. **Empezar a trabajar en algo:** No tiene que ser perfecto para empezar, lo importante es empezar, siempre se puede cambiar después. Mejor hecho que perfecto. 9 | 4. **Poneser objetivos en pequeñas tareas**: Darle prioridad a las tareas y empezar una a la vez, muy relacionado con el punto 2, pero en un sentido ya más empirico. 10 | 5. **Refactorizar poco a poco**: Revisar que patrones ya existen en el proyecto y extraerlos para ir mejorando el código. 11 | 6. **Comunicar inconsistencias**: A veces podemos encontrar incosistencias en el código o en el diseño es importante preguntar porque está asi. -------------------------------------------------------------------------------- /css-responsive/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | height: 100%; 5 | box-sizing: border-box; 6 | } 7 | 8 | * { 9 | box-sizing: inherit; 10 | } 11 | 12 | body { 13 | background: whitesmoke; 14 | color: #333; 15 | font-size: 32px; 16 | font-family: Arial, Helvetica, sans-serif; 17 | } 18 | 19 | main { 20 | display: flex; 21 | flex-direction: column; 22 | } 23 | 24 | nav { 25 | display: grid; 26 | place-items: center; 27 | background: #2980b9; 28 | } 29 | 30 | header { 31 | background: #3498db; 32 | } 33 | 34 | section, 35 | header { 36 | display: flex; 37 | justify-content: center; 38 | align-items: center; 39 | min-height: 300px; 40 | } 41 | 42 | .content { 43 | background: #ecf0f1; 44 | } 45 | 46 | .signup { 47 | background: #95a5a6; 48 | } 49 | 50 | .feature { 51 | background: #e74c3c; 52 | } 53 | 54 | .feature.first { 55 | background: #e67e22; 56 | } 57 | 58 | .feature:last-child { 59 | background: #9b59b6; 60 | } 61 | 62 | @media screen and (min-width: 992px) { 63 | .features { 64 | display: flex; 65 | order: 1; 66 | } 67 | 68 | .feature { 69 | width: 100%; 70 | } 71 | 72 | .signup { 73 | min-height: auto; 74 | height: 100px; 75 | order: 2; 76 | } 77 | 78 | .content { 79 | order: 3; 80 | } 81 | 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /improvr/organisms/Result/Result.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | 3 | import "./Result.css"; 4 | 5 | import Card from "../../atoms/Card"; 6 | import Icon from "../../atoms/Icon"; 7 | import IconLabel from "../../molecules/IconLabel"; 8 | import ButtonIcon from "../../molecules/ButtonIcon"; 9 | 10 | const labelMap = { 11 | grammar: (lang) => `Corrected (${lang})`, 12 | translate: (lang) => `Translated (${lang})`, 13 | }; 14 | 15 | const Result = ({ text, type, lang = "English", onClose, onCopy }) => { 16 | return ( 17 | 18 |
19 |

{text}

20 |
21 | {labelMap[type](lang)} 22 | 23 | Copy 24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 | ); 32 | }; 33 | 34 | Result.propTypes = { 35 | text: PropTypes.string.isRequired, 36 | type: PropTypes.oneOf(["grammar", "translate"]).isRequired, 37 | lang: PropTypes.string, 38 | onClose: PropTypes.func.isRequired, 39 | onCopy: PropTypes.func.isRequired, 40 | }; 41 | 42 | export default Result; 43 | -------------------------------------------------------------------------------- /passport/index.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import passport from "passport"; 3 | import { BasicStrategy } from "passport-http"; 4 | import bcrypt from "bcrypt"; 5 | 6 | const app = express(); 7 | 8 | const users = [ 9 | { 10 | username: "admin", 11 | name: "Guillermo Rodas", 12 | email: "me@guillermorodas.com", 13 | password: "$2b$10$jTCd14vnB24Wy.f8BHr0SOCIjQgfEdN3aeZcbXdBLgNtIBDZ6iICm", 14 | }, 15 | ]; 16 | 17 | passport.use( 18 | new BasicStrategy(function (userid, password, done) { 19 | const user = users.find((user) => user.username === userid); 20 | 21 | if (!user) { 22 | return done(null, false); 23 | } 24 | 25 | if (bcrypt.compareSync(password, user.password)) { 26 | const { password, ...userWithoutPassword } = user; 27 | return done(null, userWithoutPassword); 28 | } else { 29 | done(null, false); 30 | } 31 | }) 32 | ); 33 | 34 | app.get("/public", (req, res) => { 35 | res.status(200).json({ message: "public!" }); 36 | }); 37 | 38 | app.get( 39 | "/private", 40 | passport.authenticate("basic", { session: false }), 41 | (req, res) => { 42 | res.status(200).json({ message: "private!", user: req.user }); 43 | } 44 | ); 45 | 46 | app.listen(3000, () => { 47 | console.log("🌍 Server is running on port 3000"); 48 | }); 49 | -------------------------------------------------------------------------------- /improvr-components/src/molecules/DropdownButton/DropdownButton.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import { useState } from "react"; 3 | import Button from "../../atoms/Button"; 4 | import "./DropdownButton.css"; 5 | 6 | const Icon = ({ className }) => 🔽; 7 | 8 | const DropdownButton = ({ onClick }) => { 9 | const [lang, setLang] = useState("english"); 10 | const [letter, ...word] = lang; 11 | 12 | return ( 13 |
14 | 18 | 29 | 30 |
31 | ); 32 | }; 33 | 34 | DropdownButton.propTypes = { 35 | onClick: PropTypes.func.isRequired, 36 | }; 37 | 38 | export default DropdownButton; 39 | -------------------------------------------------------------------------------- /improvr/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /improvr-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "improvr-components", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview", 11 | "storybook": "storybook dev -p 6006", 12 | "build-storybook": "storybook build" 13 | }, 14 | "dependencies": { 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0" 17 | }, 18 | "devDependencies": { 19 | "@storybook/addon-essentials": "^7.4.0", 20 | "@storybook/addon-interactions": "^7.4.0", 21 | "@storybook/addon-links": "^7.4.0", 22 | "@storybook/addon-onboarding": "^1.0.8", 23 | "@storybook/blocks": "^7.4.0", 24 | "@storybook/react": "^7.4.0", 25 | "@storybook/react-vite": "^7.4.0", 26 | "@storybook/testing-library": "^0.2.0", 27 | "@types/react": "^18.2.15", 28 | "@types/react-dom": "^18.2.7", 29 | "@vitejs/plugin-react": "^4.0.3", 30 | "eslint": "^8.45.0", 31 | "eslint-plugin-react": "^7.32.2", 32 | "eslint-plugin-react-hooks": "^4.6.0", 33 | "eslint-plugin-react-refresh": "^0.4.3", 34 | "eslint-plugin-storybook": "^0.6.13", 35 | "prop-types": "^15.8.1", 36 | "storybook": "^7.4.0", 37 | "vite": "^4.4.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /intro-to-mongo/mongo.js: -------------------------------------------------------------------------------- 1 | // Load env variables 2 | const dotenv = require("dotenv"); 3 | const { query } = require("express"); 4 | dotenv.config(); 5 | 6 | const { MongoClient, ServerApiVersion } = require("mongodb"); 7 | 8 | const { MONGO_USERNAME, MONGO_PASSWORD, MONGO_HOSTNAME } = process.env; 9 | const uri = `mongodb+srv://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}/?retryWrites=true&w=majority`; 10 | 11 | // Create a MongoClient with a MongoClientOptions object to set the Stable API version 12 | const client = new MongoClient(uri, { 13 | serverApi: { 14 | version: ServerApiVersion.v1, 15 | strict: true, 16 | deprecationErrors: true, 17 | }, 18 | }); 19 | 20 | const getDB = async () => { 21 | try { 22 | await client.connect(); 23 | return client.db("sample_training"); 24 | } catch (error) { 25 | console.error("Coudn't connect to the db", { cause: error }); 26 | } 27 | }; 28 | 29 | const getAll = async (collectionName, query = {}) => { 30 | try { 31 | const database = await getDB(); 32 | return await database.collection(collectionName).find(query).limit(10).toArray(); 33 | } catch (error) { 34 | console.error(`Coudn't get all ${collectionName} with query ${query}`, { 35 | cause: error, 36 | }); 37 | } finally { 38 | await client.close(); 39 | } 40 | }; 41 | 42 | module.exports = { 43 | getAll, 44 | }; 45 | -------------------------------------------------------------------------------- /introducción-a-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Esto es una página web muy cool 7 | 8 | 9 | 10 | 11 |
12 | 13 |

Hello, I'm Guillermo Rodas,

14 |

I help developers to improve their skills while creating quality products.

15 | 16 |
17 |

I'm a Full-stack JavaScript Developer from Colombia living in Sweden.

18 |

Organizer of CSS Community Dev, and CSS Conf Colombia.

19 |

Google Developer Expert in Web Tech, and affiliated 20 | Twitch Streamer.

21 | 22 |

El Bootcamp que estoy liderando

23 | 24 |

🦄 Semana 1

25 | 26 |

Configuración del ambiente de desarrollo (Prework)

27 |
    28 |
  1. Instalando Ubuntu en Windows 10/11
  2. 29 |
  3. Instalación de Git
  4. 30 |
  5. Configuración de las llaves SSH
  6. 31 |
  7. Creando una cuenta de GitHub
  8. 32 |
  9. Instalación de Node.js y Yarn
  10. 33 |
  11. Primeros pasos con VS Code
  12. 34 |
35 | 36 | Mentoring 37 | Es la imagen de un gato 38 | 39 | 40 | -------------------------------------------------------------------------------- /improvr/molecules/SplitButton/SplitButton.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import { useState } from "react"; 3 | import Button from "../../atoms/Button"; 4 | import Icon from "../../atoms/Icon"; 5 | 6 | import "./SplitButton.css"; 7 | 8 | const SplitButton = ({ onClick, onChange }) => { 9 | const [lang, setLang] = useState("english"); 10 | const [letter, ...word] = lang; 11 | 12 | return ( 13 |
14 | 18 | 33 | 34 |
35 | ); 36 | }; 37 | 38 | SplitButton.propTypes = { 39 | onClick: PropTypes.func.isRequired, 40 | onChange: PropTypes.func.isRequired, 41 | }; 42 | 43 | export default SplitButton; 44 | -------------------------------------------------------------------------------- /intro-a-react/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /improvr-components/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-react/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/TagsFilter/TagsFilter.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { useState } from "react"; 3 | import "./TagsFilter.scss"; 4 | 5 | const Filter = ({ children, href = "#", isActive, onClick }) => { 6 | return ( 7 |
  • 12 | { 16 | event.preventDefault(); 17 | onClick(children); 18 | }} 19 | > 20 | {children} 21 | 22 |
  • 23 | ); 24 | }; 25 | 26 | const TagsFilter = ({ filters = [] }) => { 27 | const [firstFilter] = filters; 28 | const [activeFilter, setActiveFilter] = useState(firstFilter.name); 29 | 30 | return ( 31 | 48 | ); 49 | }; 50 | 51 | export default TagsFilter; 52 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Card/Card.scss: -------------------------------------------------------------------------------- 1 | @use "../../styles/tools"; 2 | 3 | .card { 4 | display: flex; 5 | flex-direction: column; 6 | gap: 16px 0; 7 | padding: 16px 16px 32px; 8 | box-shadow: 0px 6px 16px rgba(27, 91, 100, 0.25); 9 | background: var(--color-white); 10 | } 11 | 12 | .card-content { 13 | display: flex; 14 | flex-direction: column; 15 | gap: 8px 0; 16 | } 17 | 18 | .card img { 19 | object-fit: cover; 20 | aspect-ratio: 2/1; 21 | height: 200px; 22 | 23 | @include tools.desktop { 24 | height: 220px; 25 | } 26 | } 27 | 28 | .card section { 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: space-between; 32 | gap: 8px 0; 33 | height: 100%; 34 | } 35 | 36 | .card header { 37 | display: flex; 38 | flex-direction: column; 39 | align-items: flex-start; 40 | gap: 16px 0; 41 | } 42 | 43 | .card footer { 44 | display: flex; 45 | justify-content: space-between; 46 | align-items: center; 47 | } 48 | 49 | .card-tags { 50 | display: flex; 51 | gap: 0 12px; 52 | } 53 | 54 | @include tools.desktop { 55 | .card.is-extended { 56 | background: var(--color-aquarius-100); 57 | flex-direction: row; 58 | grid-column: 1 / 4; 59 | padding: 48px; 60 | gap: 48px; 61 | 62 | & > img { 63 | width: 660px; 64 | height: auto; 65 | } 66 | 67 | & > section { 68 | gap: 12px 0; 69 | } 70 | } 71 | 72 | .card.is-reversed { 73 | flex-direction: row-reverse; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /improvr/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /improvr-components/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | button:hover { 51 | border-color: #646cff; 52 | } 53 | button:focus, 54 | button:focus-visible { 55 | outline: 4px auto -webkit-focus-ring-color; 56 | } 57 | 58 | @media (prefers-color-scheme: light) { 59 | :root { 60 | color: #213547; 61 | background-color: #ffffff; 62 | } 63 | a:hover { 64 | color: #747bff; 65 | } 66 | button { 67 | background-color: #f9f9f9; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /practica-blog-next/components/Card/Card.module.scss: -------------------------------------------------------------------------------- 1 | @import "@/styles/tools.scss"; 2 | 3 | .card { 4 | display: flex; 5 | flex-direction: column; 6 | gap: 16px 0; 7 | padding: 16px 16px 32px; 8 | box-shadow: 0px 6px 16px rgba(27, 91, 100, 0.25); 9 | background: var(--color-white); 10 | } 11 | 12 | .card-content { 13 | display: flex; 14 | flex-direction: column; 15 | gap: 8px 0; 16 | } 17 | 18 | .card img { 19 | object-fit: cover; 20 | aspect-ratio: 2/1; 21 | height: 200px; 22 | 23 | @include desktop { 24 | height: 220px; 25 | } 26 | } 27 | 28 | .card section { 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: space-between; 32 | gap: 8px 0; 33 | height: 100%; 34 | } 35 | 36 | .card header { 37 | display: flex; 38 | flex-direction: column; 39 | align-items: flex-start; 40 | gap: 16px 0; 41 | } 42 | 43 | .card footer { 44 | display: flex; 45 | justify-content: space-between; 46 | align-items: center; 47 | } 48 | 49 | .card-tags { 50 | display: flex; 51 | flex-wrap: wrap; 52 | gap: 10px 12px; 53 | } 54 | 55 | @include desktop { 56 | .card.is-extended { 57 | background: var(--color-aquarius-100); 58 | flex-direction: row; 59 | grid-column: 1 / 4; 60 | padding: 48px; 61 | gap: 48px; 62 | 63 | & > img { 64 | width: 660px; 65 | height: auto; 66 | } 67 | 68 | & > section { 69 | gap: 12px 0; 70 | } 71 | } 72 | 73 | .card.is-reversed { 74 | flex-direction: row-reverse; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /html-semantico/cv.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Esto es una página web muy cool 7 | 8 | 9 | 10 | 11 |
    12 |

    Biografía

    13 |
    14 |

    Hello, I'm Guillermo Rodas,

    15 |

    I help developers to improve their skills while creating quality products.

    16 | 17 |
    18 |

    I'm a Full-stack JavaScript Developer from Colombia living in Sweden. 19 |

    20 |

    Organizer of CSS Community Dev, and CSS Conf Colombia.

    21 |

    Google Developer Expert in Web Tech, and affiliated 23 | Twitch Streamer.

    24 |
    25 | 26 |
    27 |

    El Bootcamp que estoy liderando

    28 | 29 |

    🦄 Semana 1

    30 | 31 |

    Configuración del ambiente de desarrollo (Prework)

    32 |
      33 |
    1. Instalando Ubuntu en Windows 10/11
    2. 34 |
    3. Instalación de Git
    4. 35 |
    5. Configuración de las llaves SSH
    6. 36 |
    7. Creando una cuenta de GitHub
    8. 37 |
    9. Instalación de Node.js y Yarn
    10. 38 |
    11. Primeros pasos con VS Code
    12. 39 |
    40 |
    41 |
    42 | 43 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /mongoose/posts/router.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { postModel } from "./model.js"; 3 | import crypto from "crypto"; 4 | 5 | export const postRouter = express.Router(); 6 | 7 | // CRUD: Create, Read, Update, Delete 8 | 9 | // Create 10 | postRouter.post("/", async (req, res) => { 11 | const permalink = crypto.randomBytes(16).toString("base64Url"); 12 | const date = new Date().toISOString(); 13 | const postToSave = { ...req.body, date, permalink }; 14 | 15 | const createdPost = await postModel.create(postToSave); 16 | res.status(201).json({ post: createdPost }); 17 | }); 18 | 19 | // Read All 20 | postRouter.get("/", async (req, res) => { 21 | // mongosse sort desc by date 22 | const posts = await postModel.find({}).sort({ date: -1 }).limit(10); 23 | res.status(200).json({ posts }); 24 | }); 25 | 26 | // Read 27 | postRouter.get("/:permalink", async (req, res) => { 28 | const post = await postModel.findOne({ permalink: req.params.permalink }); 29 | res.status(200).json({ post }); 30 | }); 31 | 32 | // Update 33 | postRouter.patch("/:permalink", async (req, res) => { 34 | const permalink = req.params.permalink; 35 | const data = req.body; 36 | 37 | const updatedPost = await postModel.findOneAndUpdate({ permalink }, data, { 38 | new: true, 39 | }); 40 | 41 | res.status(200).json({ post: updatedPost }); 42 | }); 43 | 44 | // Delete 45 | postRouter.delete("/:permalink", async (req, res) => { 46 | const deletedPost = await postModel.findOneAndDelete({ 47 | permalink: req.params.permalink, 48 | }); 49 | res.status(200).json({ post: deletedPost }); 50 | }); 51 | -------------------------------------------------------------------------------- /practica-blog-react/src/components/Card/Card.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import Tag from "../Tag"; 3 | import "./Card.scss"; 4 | import Author from "../Author/Author"; 5 | import Paragraph from "../Paragraph/Paragraph"; 6 | import Time from "../Time/Time"; 7 | 8 | const Card = ({ 9 | unsplashId, 10 | unsplashAlt, 11 | tags, 12 | title, 13 | extract, 14 | date, 15 | author, 16 | readTime, 17 | isExtended = false, 18 | isReversed = false, 19 | }) => { 20 | return ( 21 |
    27 | {unsplashAlt} 31 |
    32 |
    33 |
    34 |
    35 | {tags?.map((tag, index) => ( 36 | 37 | {tag} 38 | 39 | ))} 40 |
    41 |

    {title}

    42 | 43 |
    44 | {extract} 45 |
    46 |
    47 | 48 | 49 | {readTime} 50 | 51 |
    52 |
    53 |
    54 | ); 55 | }; 56 | 57 | export default Card; 58 | -------------------------------------------------------------------------------- /practica-blog-next/components/TagsFilter/TagsFilter.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { useState } from "react"; 3 | import styles from "./TagsFilter.module.scss"; 4 | import Paragraph from "../Paragraph/Paragraph"; 5 | 6 | const Filter = ({ children, href = "#", isActive, onClick }) => { 7 | return ( 8 |
  • 13 | { 17 | event.preventDefault(); 18 | onClick(children); 19 | }} 20 | > 21 | 22 | {children} 23 | 24 | 25 |
  • 26 | ); 27 | }; 28 | 29 | const TagsFilter = ({ filters = [] }) => { 30 | const [firstFilter] = filters; 31 | const [activeFilter, setActiveFilter] = useState(firstFilter.name); 32 | 33 | return ( 34 | 51 | ); 52 | }; 53 | 54 | export default TagsFilter; 55 | -------------------------------------------------------------------------------- /intro-a-react/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | 23 | a:hover { 24 | color: #535bf2; 25 | } 26 | 27 | body { 28 | margin: 0; 29 | display: flex; 30 | place-items: center; 31 | min-width: 320px; 32 | min-height: 100vh; 33 | } 34 | 35 | h1 { 36 | font-size: 3.2em; 37 | line-height: 1.1; 38 | } 39 | 40 | button { 41 | border-radius: 8px; 42 | border: 1px solid transparent; 43 | padding: 0.6em 1.2em; 44 | font-size: 1em; 45 | font-weight: 500; 46 | font-family: inherit; 47 | background-color: #1a1a1a; 48 | cursor: pointer; 49 | transition: border-color 0.25s; 50 | } 51 | 52 | button:hover { 53 | border-color: #646cff; 54 | } 55 | 56 | button:focus, 57 | button:focus-visible { 58 | outline: 4px auto -webkit-focus-ring-color; 59 | } 60 | 61 | @media (prefers-color-scheme: light) { 62 | :root { 63 | color: #213547; 64 | background-color: #ffffff; 65 | } 66 | 67 | a:hover { 68 | color: #747bff; 69 | } 70 | 71 | button { 72 | background-color: #f9f9f9; 73 | } 74 | } 75 | 76 | .post { 77 | border: 2px solid tomato; 78 | margin: 30px; 79 | padding: 20px; 80 | border-radius: 8px; 81 | } -------------------------------------------------------------------------------- /practica-blog/src/styles/components/card.scss: -------------------------------------------------------------------------------- 1 | @use "../tools"; 2 | 3 | .card { 4 | display: flex; 5 | flex-direction: column; 6 | gap: 16px 0; 7 | padding: 16px 16px 32px; 8 | box-shadow: 0px 6px 16px rgba(27, 91, 100, 0.25); 9 | background: var(--color-white); 10 | } 11 | 12 | .card-content { 13 | display: flex; 14 | flex-direction: column; 15 | gap: 8px 0; 16 | } 17 | 18 | .card img { 19 | object-fit: cover; 20 | aspect-ratio: 2/1; 21 | height: 200px; 22 | 23 | @include tools.desktop { 24 | height: 220px; 25 | } 26 | } 27 | 28 | .card section { 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: space-between; 32 | gap: 8px 0; 33 | height: 100%; 34 | } 35 | 36 | .card header { 37 | display: flex; 38 | flex-direction: column; 39 | align-items: flex-start; 40 | gap: 16px 0; 41 | } 42 | 43 | .card footer { 44 | display: flex; 45 | justify-content: space-between; 46 | align-items: center; 47 | } 48 | 49 | .help-text { 50 | color: var(--color-black-pearl-400); 51 | } 52 | 53 | // FIXME: card-extended, review how can we implement 54 | // this with container queries or be explicit about it. 55 | @include tools.desktop { 56 | // .card-extended 57 | .card:nth-child(4n) { 58 | background: var(--color-aquarius-100); 59 | flex-direction: row; 60 | grid-column: 1 / 4; 61 | padding: 48px; 62 | gap: 48px; 63 | 64 | & > img { 65 | width: 660px; 66 | height: auto; 67 | } 68 | 69 | & > section { 70 | gap: 12px 0; 71 | } 72 | } 73 | 74 | //.card-extended.is-reversed 75 | .card:nth-child(8n){ 76 | flex-direction: row-reverse; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /formularios-html/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | * { 6 | box-sizing: inherit; 7 | } 8 | 9 | body { 10 | color: #333; 11 | background-color: #fafafa; 12 | } 13 | 14 | .page { 15 | max-width: 800px; 16 | margin: 100px auto; 17 | padding: 0 40px; 18 | font-family: Arial, Helvetica, sans-serif; 19 | } 20 | 21 | 22 | .form-group { 23 | margin: 20px 0; 24 | } 25 | 26 | label, input { 27 | vertical-align: middle; 28 | } 29 | 30 | label, input:not([type="radio"], [type="checkbox"]) { 31 | width: 100%; 32 | } 33 | 34 | textarea { 35 | display: block; 36 | width: 100%; 37 | resize: vertical; 38 | } 39 | 40 | label, legend { 41 | font-weight: bold; 42 | text-transform: uppercase; 43 | font-size: 14px; 44 | color: #444; 45 | } 46 | 47 | input[type="text"], input[type="email"], textarea { 48 | background: white; 49 | border: 1px solid lightgray; 50 | border-radius: 4px; 51 | padding: 8px 10px; 52 | color: #333; 53 | } 54 | 55 | .help { 56 | font-size: 12px; 57 | margin-top: 10px; 58 | color: gray; 59 | } 60 | 61 | button { 62 | padding: 16px 60px; 63 | text-transform: uppercase; 64 | font-weight: bold; 65 | border: 1px solid #713f12; 66 | background: #eab308; 67 | color: #333; 68 | text-shadow: -1px -1px 0 rgba(255, 255, 255, 0.5); 69 | border-radius: 8px; 70 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5); 71 | cursor: pointer; 72 | } 73 | 74 | button:hover { 75 | background: #facc15; 76 | } 77 | 78 | button:active { 79 | background: #ca8a04; 80 | box-shadow: -1px -1px 0 rgba(0, 0, 0, 0.5); 81 | } 82 | 83 | form { 84 | accent-color: #eab308; 85 | } 86 | 87 | input:focus-visible, textarea:focus-visible { 88 | border: 1px solid #eab308; 89 | outline: 3px solid #facc15; 90 | } 91 | -------------------------------------------------------------------------------- /practica-blog-next/components/Card/Card.jsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames/bind"; 2 | 3 | import Tag from "@/components/Tag"; 4 | import Author from "@/components/Author"; 5 | import Paragraph from "@/components/Paragraph"; 6 | import Time from "@/components/Time"; 7 | import Heading from "@/components/Heading" 8 | 9 | import styles from "./Card.module.scss"; 10 | 11 | const cx = classNames.bind(styles); 12 | 13 | const Card = ({ 14 | unsplashId, 15 | unsplashAlt, 16 | tags, 17 | title, 18 | extract, 19 | date, 20 | author, 21 | readTime, 22 | isExtended = false, 23 | isReversed = false, 24 | }) => { 25 | return ( 26 |
    32 | {unsplashAlt} 36 |
    37 |
    38 |
    39 |
    40 | {tags?.map((tag, index) => ( 41 | 42 | {tag} 43 | 44 | ))} 45 |
    46 | {title} 47 | 48 |
    49 | {extract} 50 |
    51 |
    52 | 53 | 54 | {readTime} 55 | 56 |
    57 |
    58 |
    59 | ); 60 | }; 61 | 62 | export default Card; 63 | -------------------------------------------------------------------------------- /practica-blog-next/styles/objects.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | .main-container { 4 | padding: var(--container-padding); 5 | @include tools.container-width; 6 | } 7 | 8 | .nav-list { 9 | display: flex; 10 | justify-content: flex-start; 11 | align-items: baseline; 12 | flex-wrap: wrap; 13 | gap: 24px; 14 | width: 100%; 15 | } 16 | 17 | .post-list-container { 18 | display: flex; 19 | flex-direction: column; 20 | gap: 48px 0; 21 | 22 | @include tools.desktop { 23 | padding: 0; 24 | } 25 | } 26 | 27 | .post-list { 28 | display: grid; 29 | gap: 32px 0; 30 | 31 | @include tools.desktop { 32 | grid-template-columns: repeat(3, 1fr); 33 | grid-auto-rows: minmax(560px, auto) minmax(430px, auto); 34 | gap: 80px 24px; 35 | } 36 | } 37 | 38 | .main-navbar { 39 | display: flex; 40 | align-items: center; 41 | justify-content: space-between; 42 | flex-direction: column; 43 | padding: 20px 0; 44 | 45 | @include tools.container-width; 46 | 47 | @include tools.desktop { 48 | flex-direction: row; 49 | } 50 | } 51 | 52 | .featured-posts { 53 | display: flex; 54 | flex-direction: column; 55 | align-items: flex-end; 56 | gap: 24px 0; 57 | margin-bottom: 90px; 58 | } 59 | 60 | .featured-posts article { 61 | height: 630px; 62 | width: 100%; 63 | background-color: var(--color-aquarius-900); 64 | } 65 | 66 | .featured-posts .button-container { 67 | display: flex; 68 | gap: 32px; 69 | } 70 | 71 | .featured-posts button { 72 | width: 54px; 73 | height: 42px; 74 | font-size: 0; 75 | border: none; 76 | background-color: var(--color-aquarius-600); 77 | } 78 | 79 | body > footer { 80 | height: 290px; 81 | width: 100%; 82 | background-color: var(--color-black-pearl-900); 83 | padding: var(--container-padding); 84 | margin-top: 90px; 85 | } 86 | -------------------------------------------------------------------------------- /practica-blog/src/styles/objects.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | .main-container { 4 | padding: var(--container-padding); 5 | @include tools.container-width; 6 | } 7 | 8 | .nav-list { 9 | display: flex; 10 | justify-content: flex-start; 11 | align-items: baseline; 12 | flex-wrap: wrap; 13 | gap: 24px; 14 | width: 100%; 15 | } 16 | 17 | .post-list-container { 18 | display: flex; 19 | flex-direction: column; 20 | gap: 48px 0; 21 | 22 | @include tools.desktop { 23 | padding: 0; 24 | } 25 | } 26 | 27 | .post-list { 28 | display: grid; 29 | gap: 32px 0; 30 | 31 | @include tools.desktop { 32 | grid-template-columns: repeat(3, 1fr); 33 | grid-auto-rows: minmax(560px, auto) minmax(430px, auto); 34 | gap: 80px 24px; 35 | } 36 | } 37 | 38 | .main-navbar { 39 | display: flex; 40 | align-items: center; 41 | justify-content: space-between; 42 | flex-direction: column; 43 | padding: 20px 0; 44 | 45 | @include tools.container-width; 46 | 47 | @include tools.desktop { 48 | flex-direction: row; 49 | } 50 | } 51 | 52 | .featured-posts { 53 | display: flex; 54 | flex-direction: column; 55 | align-items: flex-end; 56 | gap: 24px 0; 57 | margin-bottom: 90px; 58 | } 59 | 60 | .featured-posts article { 61 | height: 630px; 62 | width: 100%; 63 | background-color: var(--color-aquarius-900); 64 | } 65 | 66 | .featured-posts .button-container { 67 | display: flex; 68 | gap: 32px; 69 | } 70 | 71 | .featured-posts button { 72 | width: 54px; 73 | height: 42px; 74 | font-size: 0; 75 | border: none; 76 | background-color: var(--color-aquarius-600); 77 | } 78 | 79 | body > footer { 80 | height: 290px; 81 | width: 100%; 82 | background-color: var(--color-black-pearl-900); 83 | padding: var(--container-padding); 84 | margin-top: 90px; 85 | } 86 | -------------------------------------------------------------------------------- /practica-blog-react/src/styles/objects.scss: -------------------------------------------------------------------------------- 1 | @use "tools"; 2 | 3 | .main-container { 4 | padding: var(--container-padding); 5 | @include tools.container-width; 6 | } 7 | 8 | .nav-list { 9 | display: flex; 10 | justify-content: flex-start; 11 | align-items: baseline; 12 | flex-wrap: wrap; 13 | gap: 24px; 14 | width: 100%; 15 | } 16 | 17 | .post-list-container { 18 | display: flex; 19 | flex-direction: column; 20 | gap: 48px 0; 21 | 22 | @include tools.desktop { 23 | padding: 0; 24 | } 25 | } 26 | 27 | .post-list { 28 | display: grid; 29 | gap: 32px 0; 30 | 31 | @include tools.desktop { 32 | grid-template-columns: repeat(3, 1fr); 33 | grid-auto-rows: minmax(560px, auto) minmax(430px, auto); 34 | gap: 80px 24px; 35 | } 36 | } 37 | 38 | .main-navbar { 39 | display: flex; 40 | align-items: center; 41 | justify-content: space-between; 42 | flex-direction: column; 43 | padding: 20px 0; 44 | 45 | @include tools.container-width; 46 | 47 | @include tools.desktop { 48 | flex-direction: row; 49 | } 50 | } 51 | 52 | .featured-posts { 53 | display: flex; 54 | flex-direction: column; 55 | align-items: flex-end; 56 | gap: 24px 0; 57 | margin-bottom: 90px; 58 | } 59 | 60 | .featured-posts article { 61 | height: 630px; 62 | width: 100%; 63 | background-color: var(--color-aquarius-900); 64 | } 65 | 66 | .featured-posts .button-container { 67 | display: flex; 68 | gap: 32px; 69 | } 70 | 71 | .featured-posts button { 72 | width: 54px; 73 | height: 42px; 74 | font-size: 0; 75 | border: none; 76 | background-color: var(--color-aquarius-600); 77 | } 78 | 79 | body > footer { 80 | height: 290px; 81 | width: 100%; 82 | background-color: var(--color-black-pearl-900); 83 | padding: var(--container-padding); 84 | margin-top: 90px; 85 | } 86 | -------------------------------------------------------------------------------- /improvr/app/api/translate/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import OpenAI from "openai"; 3 | 4 | const openai = new OpenAI({ 5 | apiKey: process.env.OPENAI_API_KEY, 6 | }); 7 | 8 | function buildMessage(text, lang) { 9 | return [ 10 | { 11 | role: "system", 12 | content: ` 13 | You are proficient in every language, possessing superior translation skills, enabling you to translate from any language to another seamlessly as a native speaker. Your task is to translate the following text, delimited by triple backticks, into ${lang}. 14 | 15 | Keep the meaning the same. If possible, retain the structure of the paragraphs. 16 | 17 | If the original text is in the same language as the target language, simply repeat the original text. 18 | 19 | Output the answer without additional context, explanation, or extra wording, just the corrected text itself. Don't use any punctuation, especially no quotes or backticks, around the text. 20 | `, 21 | }, 22 | { 23 | role: "user", 24 | content: ` 25 | Text: 26 | \`\`\` 27 | ${text} 28 | \`\`\` 29 | `, 30 | }, 31 | ]; 32 | } 33 | 34 | export async function POST(request) { 35 | const { searchParams } = new URL(request.url); 36 | const lang = searchParams.get("lang"); 37 | const { text } = await request.json(); 38 | 39 | try { 40 | const response = await openai.chat.completions.create({ 41 | model: "gpt-3.5-turbo", 42 | messages: buildMessage(text, lang), 43 | temperature: 0, 44 | max_tokens: 500, 45 | }); 46 | 47 | const translatedText = response.choices?.[0].message?.content?.trim(); 48 | 49 | return NextResponse.json({ translatedText }); 50 | } catch (error) { 51 | console.error(error); 52 | return NextResponse.error(error); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /practica-blog-next/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 18 | 19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 20 | 21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 22 | 23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 24 | 25 | ## Learn More 26 | 27 | To learn more about Next.js, take a look at the following resources: 28 | 29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 31 | 32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 33 | 34 | ## Deploy on Vercel 35 | 36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 37 | 38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 39 | -------------------------------------------------------------------------------- /html-semantico/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HTML Semántico 7 | 8 | 18 | 19 | 20 | 21 |
    22 |
    23 |

    HTML Semántico

    24 | 31 |
    32 | 33 |
    34 |
    35 |

    HTML Semántico

    36 |

    Por Guillermo Rodas. Publicado

    37 |
    38 | 39 |

    Esta es una página web de ejemplo que explica el marcado semántico de HTML5.

    40 | 41 |
    42 |

    El esquema del documento

    43 |

    HTML5 incluye varios elementos de "contenido de sección" que afectan el contorno del documento.

    44 | 45 |
    46 | Diagrama del uso de elemenos semánticos 47 |
    48 | Elementos semánticos en HTML 49 |
    50 |
    51 | 52 |

    Encabezados

    53 |

    El elemento <header> es uno de esos elementos que "crea secciones"

    54 | 55 |

    Pie de paginas

    56 |

    Asi mismo el elemento <footer>.

    57 |
    58 | 59 | 60 |
    61 |

    HTML Semántico en línea

    62 |

    El elemento <time> es semántico, pero no crea un sección de contenido.

    63 |
    64 | 65 |
    66 |

    Este articulo falso fue escrito por alguien.

    67 | 68 |
    69 | Por favor contacte a Guillermo para preguntas sobre el articulo. 70 |
    71 |
    72 |
    73 | 74 |
    75 |

    © 2023

    76 |
    77 |
    78 | 79 | 80 | -------------------------------------------------------------------------------- /practica-blog-react/src/App.jsx: -------------------------------------------------------------------------------- 1 | import Card from "./components/Card/Card"; 2 | import Link from "./components/Link/Link"; 3 | import Button from "./components/Button"; 4 | import TagsFilter from "./components/TagsFilter"; 5 | 6 | import articles from "./data/articles.json"; 7 | import filters from "./data/filters.json"; 8 | 9 | const isExtended = (index) => (index + 1) % 4 === 0; 10 | const isReversed = (index) => (index + 1) % 8 === 0; 11 | 12 | function App() { 13 | return ( 14 | <> 15 |
    16 |
    17 | Logo de Undefined Shell 21 | 37 |
    38 |
    39 |
    40 |
    41 |
    42 | 43 | 44 |
    45 |
    46 |
    47 | 48 |
    49 | {articles.map((article, index) => ( 50 | 56 | ))} 57 |
    58 |
    59 |
    60 |
    61 |
    62 | 63 | ); 64 | } 65 | 66 | export default App; 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /formularios-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Formularios HTML 7 | 8 | 9 | 10 | 11 | 12 |
    13 |

    Contacto

    14 | 15 |
    16 | 17 | 18 |
    19 |
    20 | 21 | 22 |
    23 |
    24 |
    25 | Presupuesto 26 | 27 | 28 | 29 | 30 | 31 |
    32 |
    Este presupuesto es la base no el total.
    33 |
    34 |
    35 | 36 | 43 |
    44 |
    45 | 46 | 47 |
    Escribe una descripción del proyecto en al menos 500 palabras.
    48 |
    49 |
    50 | 54 |
    55 | 56 | 57 |
    58 | 59 | 60 | -------------------------------------------------------------------------------- /practica-blog-next/pages/index.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | import Card from "@/components/Card/Card"; 4 | import Link from "@/components/Link/Link"; 5 | import Button from "@/components/Button"; 6 | import TagsFilter from "@/components/TagsFilter"; 7 | 8 | import filters from "@/data/filters.json"; 9 | 10 | const isExtended = (index) => (index + 1) % 4 === 0; 11 | const isReversed = (index) => (index + 1) % 8 === 0; 12 | 13 | function Home() { 14 | const [articles, setArticles] = useState([]); 15 | 16 | useEffect(() => { 17 | async function fetchPosts() { 18 | const jsonResponse = await fetch("/api/posts").then((data) => data.json()); 19 | 20 | setArticles(jsonResponse); 21 | } 22 | 23 | fetchPosts(); 24 | }, []); 25 | 26 | return ( 27 | <> 28 |
    29 |
    30 | Logo de Undefined Shell 34 | 50 |
    51 |
    52 |
    53 |
    54 |
    55 | 56 | 57 |
    58 |
    59 |
    60 | 61 |
    62 | {articles.map((article, index) => ( 63 | 69 | ))} 70 |
    71 |
    72 |
    73 |
    74 |
    75 | 76 | ); 77 | } 78 | 79 | export default Home; 80 | -------------------------------------------------------------------------------- /scripts/staleprs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Parse command line arguments 4 | DRY_RUN=true 5 | DAYS_OLD=30 6 | while (( "$#" )); do 7 | case "$1" in 8 | --repo) 9 | REPO="$2" 10 | shift 2 11 | ;; 12 | --execute) 13 | DRY_RUN=false 14 | shift 1 15 | ;; 16 | --days-old) 17 | if [[ $2 =~ ^[0-9]+$ ]] ; then 18 | DAYS_OLD="$2" 19 | else 20 | echo "Error: days-old should be an integer." 21 | exit 1 22 | fi 23 | shift 2 24 | ;; 25 | *) 26 | echo "Error: Invalid argument" 27 | echo "Usage: ./staleprs.sh --repo / [--days-old ] [--execute]" 28 | exit 1 29 | esac 30 | done 31 | 32 | # Check if necessary parameters are set 33 | if [[ -z "$REPO" ]]; then 34 | echo "Error: Missing arguments" 35 | echo "Usage: ./staleprs.sh --repo / [--days-old ] [--execute]" 36 | exit 1 37 | fi 38 | 39 | # Get the current date timestamp 40 | current_date=$(date +%s) 41 | 42 | # List all open PRs in your repository 43 | PRs=$(gh pr list -R "$REPO" -s open --json number,createdAt -L 200 -q '.[] | "\(.number) \(.createdAt)"') 44 | 45 | # Loop through all open PRs 46 | while read -r line; do 47 | # Get PR number and creation date 48 | PR_NUMBER=$(echo $line | cut -d' ' -f1) 49 | PR_CREATED_AT=$(echo $line | cut -d' ' -f2) 50 | 51 | # Convert the creation date to a format that macOS's date command can understand 52 | # This removes the 'Z' at the end and replaces the 'T' with a space 53 | PR_CREATED_AT=$(echo $PR_CREATED_AT | sed -e 's/Z$//' -e 's/T/ /') 54 | 55 | # Get the PR creation date timestamp 56 | pr_date=$(date -j -f "%Y-%m-%d %H:%M:%S" "$PR_CREATED_AT" +%s) 57 | 58 | # Calculate the age of the PR in days 59 | pr_age=$(( (current_date - pr_date) / 86400 )) 60 | 61 | # If the PR is older than the specified number of days 62 | if [ "$pr_age" -gt "$DAYS_OLD" ]; then 63 | # Get the labels of the PR 64 | labels=$(gh pr view "$PR_NUMBER" -R "$REPO" --json labels -q '.labels[]?.name' 2>/dev/null) 65 | 66 | # Check if the PR already has the "stale" label 67 | if [[ $labels =~ "stale" ]]; then 68 | continue 69 | fi 70 | 71 | if $DRY_RUN; then 72 | # Print the PR number (dry run) 73 | echo "Would have added the 'stale' label to PR #$PR_NUMBER." 74 | else 75 | # Add the 'stale' label to the PR 76 | gh pr edit "$PR_NUMBER" -R "$REPO" --add-label stale 77 | echo "Added the 'stale' label to PR #$PR_NUMBER." 78 | fi 79 | fi 80 | done <<< "$PRs" 81 | -------------------------------------------------------------------------------- /javascript-algorithms/README.md: -------------------------------------------------------------------------------- 1 | ## Bubble Sort (Ordenamiento de burbuja) 2 | 3 | El algoritmo de ordenación "Bubble Sort" es uno de los algoritmos de ordenación más simples. El concepto principal detrás de Bubble Sort es repetidamente "burbujear" o "flotar" el elemento más grande de la lista al final, hasta que toda la lista esté ordenada. 4 | 5 | ### Intrucciones 6 | 7 | 1. Comienza en el primer elemento de la lista con el siguiente. 8 | 2. Si el elemento actual es mayor que el siguiente, intercambia sus posiciones. 9 | 3. Avanza al siguiente elemento y repite el proceso hasta el final de la lista. 10 | 4. Al final del primer paso, el elemento más grande estará en la última posición de la lista. 11 | 5. Repite todo el proceso para la lista, excluyendo el último elemento. 12 | 6. Continúa repitiendo el proceso, excluyendo cada vez un elemento más (desde el final), hasta que no haya más elementos que comprobar. 13 | 14 | ### Psudocódigo 15 | 16 | ``` 17 | funcion ordenamientoBurbuja(lista) 18 | swapped = true 19 | mientras swapped 20 | swapped = false 21 | para i = 0 hasta longitud de lista - 1 22 | si lista[i] > lista[i + 1] 23 | lista[i], lista[i + 1] = lista[i + 1], lista[i] 24 | swapped = true 25 | fin si 26 | fin para 27 | fin mientras 28 | ``` 29 | 30 | https://www.toptal.com/developers/sorting-algorithms 31 | 32 | ## Binary Search (Busqueda Binaria) 33 | 34 | La búsqueda binaria es un algoritmo eficiente para encontrar un elemento en una lista ordenada. Supone que la lista ya está ordenada y la divide repetidamente a la mitad hasta que encuentra el elemento o reduce el tamaño del segmento a cero. 35 | 36 | ### Instrucciones 37 | 38 | 1. Compara el elemento con el valor del elemento central de la lista. 39 | 2. Si el elemento es igual al valor del elemento central, se ha encontrado el elemento buscado y el proceso termina. 40 | 3. Si el valor del elemento central es mayor que el elemento, se toma la mitad inferior de la lista y se repite el proceso desde el paso 1. 41 | 4. Si el valor del elemento central es menor que el elemento, se toma la mitad superior de la lista y se repite el proceso desde el paso 1. 42 | 5. Si el elemento no se encuentra en la lista, se devuelve un mensaje de error. 43 | 44 | ### Psudocódigo 45 | 46 | ``` 47 | función busquedaBinaria(lista, elemento) 48 | primero = 0 49 | ultimo = longitud de lista - 1 50 | mientras primero <= ultimo 51 | medio = (primero + ultimo) / 2 52 | si lista[medio] == elemento 53 | retornar medio 54 | sino si lista[medio] < elemento 55 | primero = medio + 1 56 | sino 57 | ultimo = medio - 1 58 | fin si 59 | fin mientras 60 | retornar -1 61 | fin función 62 | ``` 63 | 64 | https://www.youtube.com/watch?v=KXJSjte_OAI 65 | -------------------------------------------------------------------------------- /improvr/app/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --max-width: 1100px; 3 | --border-radius: 12px; 4 | --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', 5 | 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', 6 | 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; 7 | 8 | --foreground-rgb: 0, 0, 0; 9 | --background-start-rgb: 214, 219, 220; 10 | --background-end-rgb: 255, 255, 255; 11 | 12 | --primary-glow: conic-gradient( 13 | from 180deg at 50% 50%, 14 | #16abff33 0deg, 15 | #0885ff33 55deg, 16 | #54d6ff33 120deg, 17 | #0071ff33 160deg, 18 | transparent 360deg 19 | ); 20 | --secondary-glow: radial-gradient( 21 | rgba(255, 255, 255, 1), 22 | rgba(255, 255, 255, 0) 23 | ); 24 | 25 | --tile-start-rgb: 239, 245, 249; 26 | --tile-end-rgb: 228, 232, 233; 27 | --tile-border: conic-gradient( 28 | #00000080, 29 | #00000040, 30 | #00000030, 31 | #00000020, 32 | #00000010, 33 | #00000010, 34 | #00000080 35 | ); 36 | 37 | --callout-rgb: 238, 240, 241; 38 | --callout-border-rgb: 172, 175, 176; 39 | --card-rgb: 180, 185, 188; 40 | --card-border-rgb: 131, 134, 135; 41 | } 42 | 43 | @media (prefers-color-scheme: dark) { 44 | :root { 45 | --foreground-rgb: 255, 255, 255; 46 | --background-start-rgb: 0, 0, 0; 47 | --background-end-rgb: 0, 0, 0; 48 | 49 | --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); 50 | --secondary-glow: linear-gradient( 51 | to bottom right, 52 | rgba(1, 65, 255, 0), 53 | rgba(1, 65, 255, 0), 54 | rgba(1, 65, 255, 0.3) 55 | ); 56 | 57 | --tile-start-rgb: 2, 13, 46; 58 | --tile-end-rgb: 2, 5, 19; 59 | --tile-border: conic-gradient( 60 | #ffffff80, 61 | #ffffff40, 62 | #ffffff30, 63 | #ffffff20, 64 | #ffffff10, 65 | #ffffff10, 66 | #ffffff80 67 | ); 68 | 69 | --callout-rgb: 20, 20, 20; 70 | --callout-border-rgb: 108, 108, 108; 71 | --card-rgb: 100, 100, 100; 72 | --card-border-rgb: 200, 200, 200; 73 | } 74 | } 75 | 76 | * { 77 | box-sizing: border-box; 78 | padding: 0; 79 | margin: 0; 80 | } 81 | 82 | html, 83 | body { 84 | max-width: 100vw; 85 | overflow-x: hidden; 86 | } 87 | 88 | body { 89 | color: rgb(var(--foreground-rgb)); 90 | background: linear-gradient( 91 | to bottom, 92 | transparent, 93 | rgb(var(--background-end-rgb)) 94 | ) 95 | rgb(var(--background-start-rgb)); 96 | } 97 | 98 | a { 99 | color: inherit; 100 | text-decoration: none; 101 | } 102 | 103 | @media (prefers-color-scheme: dark) { 104 | html { 105 | color-scheme: dark; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /scripts/closeprs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Parse command line arguments 4 | DRY_RUN=true 5 | DAYS_OLD=30 6 | while (( "$#" )); do 7 | case "$1" in 8 | --repo) 9 | REPO="$2" 10 | shift 2 11 | ;; 12 | --max-files) 13 | if [[ $2 =~ ^[0-9]+$ ]] ; then 14 | MAX_FILES="$2" 15 | else 16 | echo "Error: max-files should be an integer." 17 | exit 1 18 | fi 19 | shift 2 20 | ;; 21 | --execute) 22 | DRY_RUN=false 23 | shift 1 24 | ;; 25 | --days-old) 26 | if [[ $2 =~ ^[0-9]+$ ]] ; then 27 | DAYS_OLD="$2" 28 | else 29 | echo "Error: days-old should be an integer." 30 | exit 1 31 | fi 32 | shift 2 33 | ;; 34 | *) 35 | echo "Error: Invalid argument" 36 | echo "Usage: ./closeprs.sh --repo / --max-files [--days-old ] [--execute]" 37 | exit 1 38 | esac 39 | done 40 | 41 | # Check if necessary parameters are set 42 | if [[ -z "$REPO" || -z "$MAX_FILES" ]]; then 43 | echo "Error: Missing arguments" 44 | echo "Usage: ./closeprs.sh --repo / --max-files [--days-old ] [--execute]" 45 | exit 1 46 | fi 47 | 48 | # Get the current date timestamp 49 | current_date=$(date +%s) 50 | 51 | # List all open PRs in your repository 52 | PRs=$(gh pr list -R "$REPO" -s open --json number,createdAt -L 200 -q '.[] | "\(.number) \(.createdAt)"') 53 | 54 | # Loop through all open PRs 55 | while read -r line; do 56 | # Get PR number and creation date 57 | PR_NUMBER=$(echo $line | cut -d' ' -f1) 58 | PR_CREATED_AT=$(echo $line | cut -d' ' -f2) 59 | 60 | # Convert the creation date to a format that macOS's date command can understand 61 | # This removes the 'Z' at the end and replaces the 'T' with a space 62 | PR_CREATED_AT=$(echo $PR_CREATED_AT | sed -e 's/Z$//' -e 's/T/ /') 63 | 64 | # Get the PR creation date timestamp 65 | pr_date=$(date -j -f "%Y-%m-%d %H:%M:%S" "$PR_CREATED_AT" +%s) 66 | 67 | # Calculate the age of the PR in days 68 | pr_age=$(( (current_date - pr_date) / 86400 )) 69 | 70 | # If the PR is older than the specified number of days 71 | if [ "$pr_age" -gt "$DAYS_OLD" ]; then 72 | # Get the count of changed files in the PR 73 | FILES_CHANGED_COUNT=$(gh pr diff "$PR_NUMBER" -R "$REPO" | grep 'diff --git' | wc -l || echo "0") 74 | 75 | # If the number of modified files is less than or equal to the maximum allowed 76 | if [ "${FILES_CHANGED_COUNT:-0}" -le "$MAX_FILES" ]; then 77 | if $DRY_RUN; then 78 | # Print the PR number (dry run) 79 | echo "Would have closed PR #$PR_NUMBER as it modifies $FILES_CHANGED_COUNT file(s)." 80 | else 81 | # Close the PR 82 | gh pr close "$PR_NUMBER" -R "$REPO" 83 | echo "Closed PR #$PR_NUMBER as it modifies $FILES_CHANGED_COUNT file(s)." 84 | fi 85 | fi 86 | fi 87 | done <<< "$PRs" 88 | -------------------------------------------------------------------------------- /intro-a-react/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /improvr-components/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /biblioteca-utilidades/index.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash" 2 | 3 | const entries = [ 4 | { 5 | titulo: "Introducción a HTML5", 6 | descripcion: 7 | "En este artículo se explica qué es HTML5 y cómo funciona. También se detallan las principales novedades y mejoras respecto a HTML4.", 8 | fecha: "2022-01-15", 9 | autor: "Juan Pérez", 10 | tags: ["HTML5", "Web", "Desarrollo"], 11 | }, 12 | { 13 | titulo: "Cómo diseñar una web responsive", 14 | descripcion: 15 | "En este artículo se explican las claves para diseñar una web responsive, es decir, que se adapte a diferentes tamaños de pantalla. Se detallan las herramientas y técnicas más útiles.", 16 | fecha: "2022-02-02", 17 | autor: "María García", 18 | tags: ["Responsive Design", "Web", "Diseño"], 19 | }, 20 | { 21 | titulo: "Introducción a CSS3", 22 | descripcion: 23 | "En este artículo se explica qué es CSS3 y cómo funciona. También se detallan las principales novedades y mejoras respecto a CSS2.", 24 | fecha: "2022-02-15", 25 | autor: "Pedro González", 26 | tags: ["CSS3", "Web", "Desarrollo"], 27 | }, 28 | { 29 | titulo: "Cómo optimizar el rendimiento de una web", 30 | descripcion: 31 | "En este artículo se explican las claves para optimizar el rendimiento de una web, es decir, para que cargue más rápido y sea más eficiente. Se detallan las herramientas y técnicas más útiles.", 32 | fecha: "2022-03-02", 33 | autor: "Ana Rodríguez", 34 | tags: ["Optimización", "Web", "Desarrollo"], 35 | }, 36 | { 37 | titulo: "Cómo crear una página web desde cero", 38 | descripcion: 39 | "En este artículo se explican los pasos para crear una página web desde cero, desde la elección del nombre de dominio hasta la publicación en Internet. Se detallan las herramientas y técnicas más útiles.", 40 | fecha: "2022-03-15", 41 | autor: "Juan Pérez", 42 | tags: ["Web", "Desarrollo"], 43 | }, 44 | { 45 | titulo: "Cómo usar jQuery en una web", 46 | descripcion: 47 | "En este artículo se explica qué es jQuery y cómo se puede utilizar en una web para añadir interactividad y dinamismo. Se detallan los principales métodos y funciones.", 48 | fecha: "2022-04-02", 49 | autor: "María García", 50 | tags: ["jQuery", "Web", "Desarrollo"], 51 | }, 52 | { 53 | titulo: "Cómo crear un diseño atractivo para una web", 54 | descripcion: 55 | "En este artículo se explican las claves para crear un diseño atractivo y efectivo para una web, desde la elección de colores hasta la disposición de los elementos. Se detallan las herramientas y técnicas más útiles.", 56 | fecha: "2022-04-15", 57 | autor: "Pedro González", 58 | tags: ["Diseño", "Web", "Desarrollo"], 59 | }, 60 | ]; 61 | 62 | const entriesGrouppedByAuthor = _.groupBy(entries, "autor") 63 | // console.log(entriesByAuthor) 64 | 65 | function filterByCss3Tag(entry) { 66 | return _.includes(entry.tags, "CSS3") 67 | } 68 | 69 | const entriesFilteredByCss3Tag = _.filter(entries, filterByCss3Tag) 70 | // console.log(entriesFilteredByCss3Tag) 71 | 72 | const entriesMappedByTitle = _.map(entries, "titulo") 73 | // console.log(entriesMappedByTitle) 74 | 75 | const entriesOrderedByDate = _.orderBy(entries, ["fecha", "titulo"], ["desc", "asc"]) 76 | // console.log(entriesOrderedByDate) 77 | 78 | function countTags(acc, entry) { 79 | return acc + entry.tags.length 80 | } 81 | 82 | const countEntriesTags = _.reduce(entries, countTags, 0) 83 | // console.log(countEntriesTags) 84 | 85 | const mergedEntries = _.merge(entries[0], entries[1]) 86 | // console.log(mergedEntries) 87 | 88 | const pickedTitleTagsEntry = _.pick(entries[0], ["titulo", "tags"]) 89 | // console.log(pickedTitleTagsEntry) 90 | 91 | const omittedDescriptionEntry = _.omit(entries[1], ["descripcion"]) 92 | // console.log(omittedDescriptionEntry) 93 | 94 | const hasDate = _.has(entries[2], "fecha") 95 | // console.log(hasDate) 96 | 97 | function mapFirstTitle (entries) { 98 | return _.first(_.map(entries, "titulo")) 99 | } 100 | 101 | const invertedTitleByEntry = _.invert(_.mapValues(_.groupBy(entries, "autor"), mapFirstTitle)) 102 | // console.log(invertedTitleByEntry) -------------------------------------------------------------------------------- /practica-blog-next/data/articles.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "unsplashId": "JSQkuSalhH4", 4 | "unsplashAlt": "Imagen de un post", 5 | "tags": ["Design", "Tokens"], 6 | "title": "La evolución de los Design Tokens", 7 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 8 | "author": "Guillermo Rodas", 9 | "readTime": "7 min", 10 | "date": "2023-05-04" 11 | }, 12 | { 13 | "unsplashId": "VPkkplpaLLI", 14 | "unsplashAlt": "Imagen de un post", 15 | "tags": ["Web Components", "JavaScript"], 16 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 17 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 18 | "author": "Guillermo Rodas", 19 | "readTime": "7 min", 20 | "date": "2023-05-04" 21 | }, 22 | { 23 | "unsplashId": "JSQkuSalhH4", 24 | "unsplashAlt": "Imagen de un post", 25 | "tags": ["Web Components", "JavaScript"], 26 | "title": "La evolución de los Design Tokens", 27 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 28 | "author": "Guillermo Rodas", 29 | "readTime": "7 min", 30 | "date": "2023-05-04" 31 | }, 32 | { 33 | "unsplashId": "VPkkplpaLLI", 34 | "unsplashAlt": "Imagen de un post", 35 | "tags": ["Web Components", "JavaScript"], 36 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 37 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 38 | "author": "Guillermo Rodas", 39 | "readTime": "7 min", 40 | "date": "2023-05-04" 41 | }, 42 | { 43 | "unsplashId": "JSQkuSalhH4", 44 | "unsplashAlt": "Imagen de un post", 45 | "tags": ["Web Components", "JavaScript"], 46 | "title": "La evolución de los Design Tokens", 47 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 48 | "author": "Guillermo Rodas", 49 | "readTime": "7 min", 50 | "date": "2023-05-04" 51 | }, 52 | { 53 | "unsplashId": "VPkkplpaLLI", 54 | "unsplashAlt": "Imagen de un post", 55 | "tags": ["Web Components", "JavaScript"], 56 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 57 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 58 | "author": "Guillermo Rodas", 59 | "readTime": "7 min", 60 | "date": "2023-05-04" 61 | }, 62 | { 63 | "unsplashId": "JSQkuSalhH4", 64 | "unsplashAlt": "Imagen de un post", 65 | "tags": ["Web Components", "JavaScript"], 66 | "title": "La evolución de los Design Tokens", 67 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 68 | "author": "Guillermo Rodas", 69 | "readTime": "7 min", 70 | "date": "2023-05-04" 71 | }, 72 | { 73 | "unsplashId": "VPkkplpaLLI", 74 | "unsplashAlt": "Imagen de un post", 75 | "tags": ["Web Components", "JavaScript"], 76 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 77 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 78 | "author": "Guillermo Rodas", 79 | "readTime": "7 min", 80 | "date": "2023-05-04" 81 | } 82 | ] 83 | -------------------------------------------------------------------------------- /practica-blog-react/src/data/articles.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "unsplashId": "JSQkuSalhH4", 4 | "unsplashAlt": "Imagen de un post", 5 | "tags": ["Design", "Tokens"], 6 | "title": "La evolución de los Design Tokens", 7 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 8 | "author": "Guillermo Rodas", 9 | "readTime": "7 min", 10 | "date": "2023-05-04" 11 | }, 12 | { 13 | "unsplashId": "VPkkplpaLLI", 14 | "unsplashAlt": "Imagen de un post", 15 | "tags": ["Web Components", "JavaScript"], 16 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 17 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 18 | "author": "Guillermo Rodas", 19 | "readTime": "7 min", 20 | "date": "2023-05-04" 21 | }, 22 | { 23 | "unsplashId": "JSQkuSalhH4", 24 | "unsplashAlt": "Imagen de un post", 25 | "tags": ["Web Components", "JavaScript"], 26 | "title": "La evolución de los Design Tokens", 27 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 28 | "author": "Guillermo Rodas", 29 | "readTime": "7 min", 30 | "date": "2023-05-04" 31 | }, 32 | { 33 | "unsplashId": "VPkkplpaLLI", 34 | "unsplashAlt": "Imagen de un post", 35 | "tags": ["Web Components", "JavaScript"], 36 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 37 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 38 | "author": "Guillermo Rodas", 39 | "readTime": "7 min", 40 | "date": "2023-05-04" 41 | }, 42 | { 43 | "unsplashId": "JSQkuSalhH4", 44 | "unsplashAlt": "Imagen de un post", 45 | "tags": ["Web Components", "JavaScript"], 46 | "title": "La evolución de los Design Tokens", 47 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 48 | "author": "Guillermo Rodas", 49 | "readTime": "7 min", 50 | "date": "2023-05-04" 51 | }, 52 | { 53 | "unsplashId": "VPkkplpaLLI", 54 | "unsplashAlt": "Imagen de un post", 55 | "tags": ["Web Components", "JavaScript"], 56 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 57 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 58 | "author": "Guillermo Rodas", 59 | "readTime": "7 min", 60 | "date": "2023-05-04" 61 | }, 62 | { 63 | "unsplashId": "JSQkuSalhH4", 64 | "unsplashAlt": "Imagen de un post", 65 | "tags": ["Web Components", "JavaScript"], 66 | "title": "La evolución de los Design Tokens", 67 | "extract": "Han pasado muchos meses desde que escribí mi primer artículo en ,español sobre Design Tokens, y desde entonces no solo han evolucionado, sino que cada vez se adaptan y se vuelven una parte fundamental de un sistema de diseño. Hoy les quiero compartir los puntos clave de esta evolución.", 68 | "author": "Guillermo Rodas", 69 | "readTime": "7 min", 70 | "date": "2023-05-04" 71 | }, 72 | { 73 | "unsplashId": "VPkkplpaLLI", 74 | "unsplashAlt": "Imagen de un post", 75 | "tags": ["Web Components", "JavaScript"], 76 | "title": "Estático, dinámico, single-page, multiple-page y JAMstack", 77 | "extract": "\n\t Hoy en día escuchamos términos como páginas estáticas, dinámicas, SPA, Muti-páginas y, recientemente, el término JAMStack. ¿Qué significa todo esto? ¿Por qué es importante entender las diferencias? A medida que se va adquiriendo experiencia, nos damos cuenta de que no existe una \"navaja suiza\" para la web.\n\t ", 78 | "author": "Guillermo Rodas", 79 | "readTime": "7 min", 80 | "date": "2023-05-04" 81 | } 82 | ] 83 | -------------------------------------------------------------------------------- /javascript-algorithms/books.js: -------------------------------------------------------------------------------- 1 | const books = [ 2 | { 3 | author: "J.K. Rowling", 4 | title: "Harry Potter y la piedra filosofal", 5 | year: 1997, 6 | }, 7 | { author: "George Orwell", title: "1984", year: 1949 }, 8 | { 9 | author: "J.R.R. Tolkien", 10 | title: "El señor de los anillos", 11 | year: 1954, 12 | }, 13 | { 14 | author: "Agatha Christie", 15 | title: "Diez negritos", 16 | year: 1939, 17 | }, 18 | { 19 | author: "Jane Austen", 20 | title: "Orgullo y prejuicio", 21 | year: 1813, 22 | }, 23 | { 24 | author: "Mark Twain", 25 | title: "Las aventuras de Tom Sawyer", 26 | year: 1876, 27 | }, 28 | { 29 | author: "Charles Dickens", 30 | title: "Historia de dos ciudades", 31 | year: 1859, 32 | }, 33 | { author: "Leo Tolstoy", title: "Guerra y paz", year: 1869 }, 34 | { 35 | author: "Ernest Hemingway", 36 | title: "El viejo y el mar", 37 | year: 1952, 38 | }, 39 | { 40 | author: "F. Scott Fitzgerald", 41 | title: "El gran Gatsby", 42 | year: 1925, 43 | }, 44 | { 45 | author: "Gabriel García Márquez", 46 | title: "Cien años de soledad", 47 | year: 1967, 48 | }, 49 | { 50 | author: "Mario Vargas Llosa", 51 | title: "La ciudad y los perros", 52 | year: 1963, 53 | }, 54 | { author: "Julio Cortázar", title: "Rayuela", year: 1963 }, 55 | { 56 | author: "Isabel Allende", 57 | title: "La casa de los espíritus", 58 | year: 1982, 59 | }, 60 | { 61 | author: "Miguel de Cervantes", 62 | title: "Don Quijote de la Mancha", 63 | year: 1605, 64 | }, 65 | { 66 | author: "J.K. Rowling", 67 | title: "Harry Potter y la cámara secreta", 68 | year: 1998, 69 | }, 70 | { 71 | author: "George Orwell", 72 | title: "Rebelión en la granja", 73 | year: 1945, 74 | }, 75 | { author: "J.R.R. Tolkien", title: "El hobbit", year: 1937 }, 76 | { 77 | author: "Agatha Christie", 78 | title: "Asesinato en el Orient Express", 79 | year: 1934, 80 | }, 81 | { 82 | author: "Jane Austen", 83 | title: "Sentido y sensibilidad", 84 | year: 1811, 85 | }, 86 | { 87 | author: "Mark Twain", 88 | title: "Las aventuras de Huckleberry Finn", 89 | year: 1884, 90 | }, 91 | { author: "Charles Dickens", title: "Oliver Twist", year: 1837 }, 92 | { author: "Leo Tolstoy", title: "Anna Karenina", year: 1877 }, 93 | { 94 | author: "Ernest Hemingway", 95 | title: "Por quién doblan las campanas", 96 | year: 1940, 97 | }, 98 | { 99 | author: "F. Scott Fitzgerald", 100 | title: "A este lado del paraíso", 101 | year: 1920, 102 | }, 103 | { 104 | author: "Gabriel García Márquez", 105 | title: "El amor en los tiempos del cólera", 106 | year: 1985, 107 | }, 108 | { 109 | author: "Mario Vargas Llosa", 110 | title: "Conversación en la catedral", 111 | year: 1969, 112 | }, 113 | { 114 | author: "Julio Cortázar", 115 | title: "Final del juego", 116 | year: 1956, 117 | }, 118 | { author: "Isabel Allende", title: "Eva Luna", year: 1987 }, 119 | { 120 | author: "Miguel de Cervantes", 121 | title: "Novelas ejemplares", 122 | year: 1613, 123 | }, 124 | { 125 | author: "J.K. Rowling", 126 | title: "Harry Potter y el prisionero de Azkaban", 127 | year: 1999, 128 | }, 129 | { 130 | author: "George Orwell", 131 | title: "Homenaje a Cataluña", 132 | year: 1938, 133 | }, 134 | { author: "J.R.R. Tolkien", title: "Silmarillion", year: 1977 }, 135 | { 136 | author: "Agatha Christie", 137 | title: "El misterioso caso de Styles", 138 | year: 1920, 139 | }, 140 | { author: "Jane Austen", title: "Emma", year: 1815 }, 141 | { 142 | author: "Mark Twain", 143 | title: "Un yanqui en la corte del rey Arturo", 144 | year: 1889, 145 | }, 146 | { 147 | author: "Charles Dickens", 148 | title: "David Copperfield", 149 | year: 1849, 150 | }, 151 | { author: "Leo Tolstoy", title: "Resurrección", year: 1899 }, 152 | { 153 | author: "Ernest Hemingway", 154 | title: "Adiós a las armas", 155 | year: 1929, 156 | }, 157 | { 158 | author: "F. Scott Fitzgerald", 159 | title: "Tiempos difíciles", 160 | year: 1934, 161 | }, 162 | { 163 | author: "Gabriel García Márquez", 164 | title: "Crónica de una muerte anunciada", 165 | year: 1981, 166 | }, 167 | { 168 | author: "Mario Vargas Llosa", 169 | title: "La tía Julia y el escribidor", 170 | year: 1977, 171 | }, 172 | { author: "Julio Cortázar", title: "Los premios", year: 1960 }, 173 | { author: "Isabel Allende", title: "Paula", year: 1994 }, 174 | { 175 | author: "Miguel de Cervantes", 176 | title: "La Galatea", 177 | year: 1585, 178 | }, 179 | { 180 | author: "J.K. Rowling", 181 | title: "Harry Potter y el cáliz de fuego", 182 | year: 2000, 183 | }, 184 | { 185 | author: "George Orwell", 186 | title: "La hija del clérigo", 187 | year: 1935, 188 | }, 189 | { 190 | author: "J.R.R. Tolkien", 191 | title: "Los hijos de Húrin", 192 | year: 2007, 193 | }, 194 | { 195 | author: "Agatha Christie", 196 | title: "Matar es fácil", 197 | year: 1939, 198 | }, 199 | ]; 200 | 201 | export default books; 202 | --------------------------------------------------------------------------------