├── 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 | {humanize(children)}
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 | {humanize(children)}
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 |
12 | {children}
13 |
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 |
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 |
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 |
12 | Platzi Master Technical coach November 2020
13 | Women Developer Academy Europe Speaker mentor October 2021
14 |
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 |
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 |
9 | {children}
10 |
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 |
8 |
9 | {children}{" "}
10 |
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 |
9 | {children}
10 |
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 |
26 | {children}
27 |
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 | Navbar
14 |
17 |
20 |
23 |
24 |
27 |
30 |
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 |
Primary button
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 | Vajmo!
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 |
19 | Vite + React
20 |
21 |
setCount((count) => count + 1)}>
22 | count is {count}
23 |
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 |
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 |
15 | Translate to ({letter.toUpperCase()}
16 | {word})
17 |
18 | setLang(event.currentTarget.value)}
22 | >
23 | English
24 | Spanish
25 | French
26 | German
27 | Swedish
28 |
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 |
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 | Instalando Ubuntu en Windows 10/11
29 | Instalación de Git
30 | Configuración de las llaves SSH
31 | Creando una cuenta de GitHub
32 | Instalación de Node.js y Yarn
33 | Primeros pasos con VS Code
34 |
35 |
36 | Mentoring
37 |
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 |
15 | Translate to ({letter.toUpperCase()}
16 | {word})
17 |
18 | {
22 | const { value } = event.currentTarget;
23 | setLang(value);
24 | onChange(value);
25 | }}
26 | >
27 | English
28 | Spanish
29 | French
30 | German
31 | Swedish
32 |
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 |
32 |
33 |
34 | {filters.map(({ name, href }, index) => (
35 |
41 | {name}
42 |
43 | ))}
44 |
45 |
46 |
47 |
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 | Instalando Ubuntu en Windows 10/11
34 | Instalación de Git
35 | Configuración de las llaves SSH
36 | Creando una cuenta de GitHub
37 | Instalación de Node.js y Yarn
38 | Primeros pasos con VS Code
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 |
31 |
32 |
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 |
35 |
36 |
37 | {filters.map(({ name, href }, index) => (
38 |
44 | {name}
45 |
46 | ))}
47 |
48 |
49 |
50 |
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 |
36 |
37 |
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 |
25 |
30 |
31 |
32 |
33 |
34 |
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 |
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 |
72 |
73 |
74 |
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 |
21 |
22 |
23 |
24 | Inicio
25 |
26 |
27 | Suscribirse
28 |
29 |
30 | Undefined Academy
31 |
32 |
33 | Discord
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Atras
43 | Adelante
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 |
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 |
34 |
35 |
36 |
37 | Inicio
38 |
39 |
40 | Suscribirse
41 |
42 |
43 | Undefined Academy
44 |
45 |
46 | Discord
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Atras
56 | Adelante
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 |
--------------------------------------------------------------------------------