├── .editorconfig
├── .env
├── .env.example
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .netlify
└── edge-functions-import-map.json
├── .npmrc
├── .prettierrc.js
├── .stackblitzrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── README.md
├── bun.lockb
├── jsconfig.json
├── next-env.d.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── public
├── favicon.svg
├── gifts
│ ├── Hack4U-mini.webp
│ ├── Hack4U.webp
│ ├── codely-small.webp
│ ├── codely.webp
│ ├── codigo-sostenible-small.webp
│ ├── codigo-sostenible.webp
│ ├── cupon-github-small.webp
│ ├── cupon-github.webp
│ ├── el-programador-pragmatico.webp
│ ├── fazt-mini.webp
│ ├── fazt.webp
│ ├── keep-coding-clock.webp
│ ├── keep-coding-job.webp
│ ├── keep-coding-mini.webp
│ ├── keep-coding-module.webp
│ ├── keychron-small.webp
│ ├── keychron.webp
│ ├── lemon-code-devops.webp
│ ├── lemon-code-frontend.webp
│ ├── lemon-code-small.webp
│ ├── mac-mini-small.webp
│ ├── mac-mini.webp
│ ├── platzi-planes-small.webp
│ ├── platzi-planes.webp
│ ├── scrimba-small.webp
│ ├── scrimba.webp
│ ├── supermaven-small.webp
│ ├── supermaven.webp
│ ├── this-is-fine-small.webp
│ └── this-is-fine.webp
├── img
│ ├── autentia.svg
│ ├── gifts
│ │ ├── amautas.png
│ │ ├── codely.png
│ │ ├── dondominio.png
│ │ ├── elsa.png
│ │ ├── javier.png
│ │ └── libro-git.png
│ ├── speakers
│ │ ├── anon.jpg
│ │ ├── carmen.jpg
│ │ ├── cloudinary.jpg
│ │ ├── codely-agenda.jpg
│ │ ├── david.jpg
│ │ ├── dawntraoz.jpg
│ │ ├── debbie.jpg
│ │ ├── dotcsv.jpg
│ │ ├── east.jpg
│ │ ├── fazt.jpg
│ │ ├── fernando-rodriguez.jpg
│ │ ├── fernando.jpg
│ │ ├── freddyVega.jpg
│ │ ├── frr149.jpg
│ │ ├── grimerloner.jpg
│ │ ├── javi.jpg
│ │ ├── javier.jpg
│ │ ├── malt.jpg
│ │ ├── midudev.jpg
│ │ ├── nerea.jpg
│ │ ├── pablokbs.jpg
│ │ ├── patoDev.jpg
│ │ ├── rafa.jpg
│ │ ├── rauchg.jpg
│ │ ├── s4vitar.jpg
│ │ ├── sorteo.png
│ │ └── teffcode.jpg
│ ├── sponsors
│ │ └── keepcoding.webp
│ └── tickets-effect
│ │ ├── bg.png
│ │ ├── gradient.png
│ │ └── noise.png
├── og-image.jpg
├── regalo-libro-git.png
└── stickers
│ ├── cloudinary.png
│ ├── glasses.png
│ ├── keep-coding.png
│ ├── libro-git.png
│ ├── malt.svg
│ ├── mario.png
│ ├── midu-angry.png
│ ├── midu-boss.png
│ ├── midu-f.png
│ ├── midu-hype.png
│ ├── midu-love.png
│ ├── midu-lul.png
│ ├── midu-not-like-this.png
│ ├── midu-snif.png
│ ├── midu-wink.png
│ ├── midu-wow.png
│ ├── midu-wtf.png
│ ├── midu.png
│ ├── midu.svg
│ ├── start.png
│ ├── this-is-fine-normal.png
│ ├── this-is-fine.png
│ ├── vercel.png
│ ├── vercel.svg
│ └── yeah.png
├── src
├── components
│ ├── Avatar.jsx
│ ├── Background.jsx
│ ├── Button.tsx
│ ├── Card.jsx
│ ├── CohereLogo.jsx
│ ├── Container3D.tsx
│ ├── Countdown.jsx
│ ├── Header.tsx
│ ├── HeaderIndex.jsx
│ ├── HideContentBox.tsx
│ ├── LinearCard.jsx
│ ├── Logo.jsx
│ ├── Meteor.tsx
│ ├── MeteorLanguages.tsx
│ ├── Modal.tsx
│ ├── Mouse.jsx
│ ├── ShareTicketButton.jsx
│ ├── Speakers.tsx
│ ├── Stars.tsx
│ ├── Ticket.tsx
│ ├── TicketGradient.tsx
│ ├── TicketPlatinum.tsx
│ ├── Tooltip.tsx
│ ├── TwitchBlock.jsx
│ ├── TwitchIcon.jsx
│ ├── TwitchLogo.jsx
│ ├── TypeBadge.jsx
│ ├── icons
│ │ ├── index.ts
│ │ ├── languages
│ │ │ ├── angular.tsx
│ │ │ ├── astro.tsx
│ │ │ ├── bun.tsx
│ │ │ ├── c.tsx
│ │ │ ├── csharp.tsx
│ │ │ ├── css.tsx
│ │ │ ├── dart.tsx
│ │ │ ├── deno.tsx
│ │ │ ├── firebase.tsx
│ │ │ ├── flutter.tsx
│ │ │ ├── github.tsx
│ │ │ ├── golang.tsx
│ │ │ ├── html.tsx
│ │ │ ├── index.ts
│ │ │ ├── intellij.tsx
│ │ │ ├── java.tsx
│ │ │ ├── javascript.tsx
│ │ │ ├── linux.tsx
│ │ │ ├── markdown.tsx
│ │ │ ├── mysql.tsx
│ │ │ ├── nestjs.tsx
│ │ │ ├── next.tsx
│ │ │ ├── node.tsx
│ │ │ ├── npm.tsx
│ │ │ ├── nuxt.tsx
│ │ │ ├── php.tsx
│ │ │ ├── pnpm.tsx
│ │ │ ├── preact.tsx
│ │ │ ├── python.tsx
│ │ │ ├── qwik.tsx
│ │ │ ├── react.tsx
│ │ │ ├── ruby.tsx
│ │ │ ├── rust.tsx
│ │ │ ├── scala.tsx
│ │ │ ├── solid.tsx
│ │ │ ├── svelte.tsx
│ │ │ ├── tailwind.tsx
│ │ │ ├── typescript.tsx
│ │ │ ├── vim.tsx
│ │ │ ├── vite.tsx
│ │ │ ├── vscode.tsx
│ │ │ └── vue.tsx
│ │ ├── navbar
│ │ │ ├── discord.tsx
│ │ │ ├── gift.tsx
│ │ │ ├── index.ts
│ │ │ ├── schedule.tsx
│ │ │ ├── speakers.tsx
│ │ │ └── sponsors.tsx
│ │ ├── sponsors
│ │ │ ├── cloudinary.tsx
│ │ │ ├── codely.tsx
│ │ │ ├── don-dominio.tsx
│ │ │ ├── index.ts
│ │ │ ├── infojobs.tsx
│ │ │ ├── keepcode.tsx
│ │ │ ├── lemon-horizontal.tsx
│ │ │ ├── lemon-vertical.tsx
│ │ │ ├── malt.tsx
│ │ │ ├── platzi.tsx
│ │ │ ├── scrimba.tsx
│ │ │ └── strapi.tsx
│ │ ├── stickers
│ │ │ ├── don-dominio.tsx
│ │ │ ├── index.tsx
│ │ │ ├── lemon-code.tsx
│ │ │ ├── platzi.tsx
│ │ │ └── twitch.tsx
│ │ ├── ticket.tsx
│ │ └── twitch.tsx
│ ├── logos
│ │ ├── codely.tsx
│ │ ├── dondominio.tsx
│ │ ├── lemoncode.tsx
│ │ └── midudev.tsx
│ ├── magicui
│ │ ├── MagicCard.tsx
│ │ ├── Marquee.tsx
│ │ └── RadialGradient.tsx
│ └── utilities
│ │ └── timezone.ts
├── flavors
│ └── data.tsx
├── hooks
│ └── useRemainingTime.ts
├── lib
│ ├── supabase.js
│ └── utils.ts
├── pages
│ ├── _app.js
│ ├── _document.js
│ ├── api
│ │ ├── auth
│ │ │ └── callback.js
│ │ ├── number.js
│ │ ├── special-ticket
│ │ │ └── twitch.ts
│ │ └── twitch
│ │ │ └── signin.ts
│ ├── index.js
│ └── ticket.js
├── sections
│ ├── agenda.tsx
│ ├── gifts.tsx
│ ├── layout.tsx
│ ├── sponsors.tsx
│ └── ticket-home.tsx
├── store
│ └── index.js
└── styles
│ └── globals.css
├── tailwind.config.js
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = tab
7 | tab_width = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_SUPABASE_URL=https://ljizvfycxyxnupniyyxb.supabase.co
2 | NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxqaXp2ZnljeHl4bnVwbml5eXhiIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTU0MDgwNDQsImV4cCI6MTk3MDk4NDA0NH0.J8-KVtrZNxWIWMIdEm00WLHp1OTrFc4mMC3RVZK12cM
3 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | PUBLIC_SUPABASE_URL=
2 | PUBLIC_SUPABASE_ANON_KEY=
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 | .output/
3 | node_modules/
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es2022": true,
4 | "node": true,
5 | "browser": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:@typescript-eslint/eslint-recommended",
10 | "plugin:@typescript-eslint/recommended",
11 | "eslint-config-prettier",
12 | "standard"
13 | ],
14 | "parser": "@typescript-eslint/parser",
15 | "parserOptions": {
16 | "ecmaVersion": "latest",
17 | "sourceType": "module"
18 | },
19 | "rules": {
20 | "space-before-function-paren": "off",
21 | "no-unused-vars": "warn",
22 | "@typescript-eslint/no-explicit-any": "warn",
23 | "@typescript-eslint/no-unused-vars": [
24 | "warn",
25 | {
26 | "argsIgnorePattern": "^_",
27 | "varsIgnorePattern": "^_",
28 | "caughtErrorsIgnorePattern": "^_"
29 | }
30 | ],
31 | "no-multiple-empty-lines": "off",
32 | "no-tabs": "off",
33 | "indent": [
34 | "warn",
35 | "tab"
36 | ],
37 | "quotes": [
38 | "warn",
39 | "single"
40 | ],
41 | "jsx-quotes": [
42 | "warn",
43 | "prefer-single"
44 | ],
45 | "eol-last": "off"
46 | }
47 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | .output/
4 | .env
5 | .env.local
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 |
17 | # environment variables
18 | .env.production
19 | .env.local
20 |
21 | # macOS-specific files
22 | .DS_Store
23 | package-lock.json
24 |
25 | # pnpm
26 | pnpm-lock.yaml
27 | # Local Netlify folder
28 | .netlify
29 | .next/
30 |
--------------------------------------------------------------------------------
/.netlify/edge-functions-import-map.json:
--------------------------------------------------------------------------------
1 | { "imports": { "netlify:edge": "https://edge.netlify.com/v1/index.ts" } }
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # Expose Astro dependencies for `pnpm` users
2 | shamefully-hoist=true
3 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 100,
3 | semi: false,
4 | singleQuote: true,
5 | jsxSingleQuote: true,
6 | tabWidth: 2,
7 | trailingComma: 'none',
8 | useTabs: true,
9 | overrides: [
10 | {
11 | files: ['*.json', '*.md', '*.toml', '*.yml'],
12 | options: {
13 | useTabs: false
14 | }
15 | }
16 | ],
17 | endOfLine: 'lf'
18 | }
19 |
--------------------------------------------------------------------------------
/.stackblitzrc:
--------------------------------------------------------------------------------
1 | {
2 | "startCommand": "npm start",
3 | "env": {
4 | "ENABLE_CJS_IMPORTS": true
5 | }
6 | }
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.codeActionsOnSave": {
3 | "source.fixAll.eslint": "explicit"
4 | },
5 | "editor.detectIndentation": false,
6 | "editor.insertSpaces": false,
7 | "eslint.validate": [
8 | "javascript",
9 | "javascriptreact",
10 | "astro", // Enable .astro
11 | "typescript", // Enable .ts
12 | "typescriptreact" // Enable .tsx
13 | ],
14 | "javascript.format.insertSpaceBeforeFunctionParenthesis": true
15 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # miduConf
2 |
3 | ## Descripción del Proyecto
4 |
5 | Este proyecto es el código fuente del sitio web oficial de **miduConf**, una conferencia de programación y desarrollo web en español que se celebrará el **12 de septiembre de 2024**. El sitio web se desarrolla utilizando Next.js y tiene como objetivo informar a los asistentes y a la comunidad en general sobre los detalles de la conferencia, incluidos los oradores, el horario, los regalos y sorteos, y cómo registrarse para el evento.
6 |
7 | ## Prerrequisitos
8 |
9 | - Node.js >= v18.17.0
10 | - npm
11 |
12 | ## Instalación y Configuración
13 |
14 | 1. Clona el repositorio.
15 | 2. Ejecuta `npm install --legacy-peer-deps` para instalar las dependencias.
16 | 3. Ejecuta `npm run dev` para iniciar el servidor de desarrollo.
17 |
18 | ## Cómo Probar el Proyecto
19 |
20 | Para probar el proyecto, sigue estos pasos:
21 |
22 | 1. Ejecuta `npm run test` para ejecutar las pruebas unitarias (si las hay).
23 | 2. Abre el navegador y navega a `http://localhost:3000`.
24 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/bun.lockb
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./src/*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | transpilePackages: ['geist'],
5 | experimental: {
6 | esmExternals: false // THIS IS THE FLAG THAT MATTERS
7 | },
8 | async rewrites() {
9 | return [
10 | {
11 | source: '/ticket/:username',
12 | destination: '/?ticket=:username'
13 | },
14 | {
15 | source: '/ticket/:username/:hash',
16 | destination: '/?ticket=:username'
17 | }
18 | ]
19 | }
20 | }
21 |
22 | module.exports = nextConfig
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@floating-ui/react": "^0.26.22",
4 | "@midudev/tailwind-animations": "0.0.7",
5 | "@supabase/auth-helpers-nextjs": "0.10.0",
6 | "@supabase/auth-helpers-react": "0.5.0",
7 | "@supabase/supabase-js": "2.45.0",
8 | "@tabler/icons-react": "3.11.0",
9 | "atropos": "2.0.2",
10 | "autoprefixer": "10.4.19",
11 | "canvas-confetti": "^1.9.3",
12 | "eslint": "9.8.0",
13 | "eslint-config-next": "14.2.5",
14 | "flowbite": "2.4.1",
15 | "geist": "1.3.1",
16 | "html-to-image": "1.11.11",
17 | "next": "14.2.5",
18 | "postcss": "8.4.40",
19 | "react": "18.3.1",
20 | "react-dom": "18.3.1",
21 | "zustand": "4.5.4"
22 | },
23 | "devDependencies": {
24 | "@types/react": "18.3.3",
25 | "@typescript-eslint/eslint-plugin": "8.0.0",
26 | "clsx": "2.1.1",
27 | "eslint-config-prettier": "9.1.0",
28 | "standard": "17.1.0",
29 | "tailwind-merge": "2.4.0",
30 | "tailwindcss": "3.4.7",
31 | "tailwindcss-textshadow": "2.1.3",
32 | "typescript": "5.5.4"
33 | },
34 | "name": "miduconf.com",
35 | "private": true,
36 | "scripts": {
37 | "build": "next build",
38 | "dev": "next dev",
39 | "lint": "next lint",
40 | "lint:eslint": "npm run lint",
41 | "start": "next start"
42 | },
43 | "version": "0.1.0"
44 | }
45 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/public/gifts/Hack4U-mini.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/Hack4U-mini.webp
--------------------------------------------------------------------------------
/public/gifts/Hack4U.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/Hack4U.webp
--------------------------------------------------------------------------------
/public/gifts/codely-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/codely-small.webp
--------------------------------------------------------------------------------
/public/gifts/codely.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/codely.webp
--------------------------------------------------------------------------------
/public/gifts/codigo-sostenible-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/codigo-sostenible-small.webp
--------------------------------------------------------------------------------
/public/gifts/codigo-sostenible.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/codigo-sostenible.webp
--------------------------------------------------------------------------------
/public/gifts/cupon-github-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/cupon-github-small.webp
--------------------------------------------------------------------------------
/public/gifts/cupon-github.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/cupon-github.webp
--------------------------------------------------------------------------------
/public/gifts/el-programador-pragmatico.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/el-programador-pragmatico.webp
--------------------------------------------------------------------------------
/public/gifts/fazt-mini.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/fazt-mini.webp
--------------------------------------------------------------------------------
/public/gifts/fazt.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/fazt.webp
--------------------------------------------------------------------------------
/public/gifts/keep-coding-clock.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keep-coding-clock.webp
--------------------------------------------------------------------------------
/public/gifts/keep-coding-job.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keep-coding-job.webp
--------------------------------------------------------------------------------
/public/gifts/keep-coding-mini.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keep-coding-mini.webp
--------------------------------------------------------------------------------
/public/gifts/keep-coding-module.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keep-coding-module.webp
--------------------------------------------------------------------------------
/public/gifts/keychron-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keychron-small.webp
--------------------------------------------------------------------------------
/public/gifts/keychron.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/keychron.webp
--------------------------------------------------------------------------------
/public/gifts/lemon-code-devops.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/lemon-code-devops.webp
--------------------------------------------------------------------------------
/public/gifts/lemon-code-frontend.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/lemon-code-frontend.webp
--------------------------------------------------------------------------------
/public/gifts/lemon-code-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/lemon-code-small.webp
--------------------------------------------------------------------------------
/public/gifts/mac-mini-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/mac-mini-small.webp
--------------------------------------------------------------------------------
/public/gifts/mac-mini.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/mac-mini.webp
--------------------------------------------------------------------------------
/public/gifts/platzi-planes-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/platzi-planes-small.webp
--------------------------------------------------------------------------------
/public/gifts/platzi-planes.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/platzi-planes.webp
--------------------------------------------------------------------------------
/public/gifts/scrimba-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/scrimba-small.webp
--------------------------------------------------------------------------------
/public/gifts/scrimba.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/scrimba.webp
--------------------------------------------------------------------------------
/public/gifts/supermaven-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/supermaven-small.webp
--------------------------------------------------------------------------------
/public/gifts/supermaven.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/supermaven.webp
--------------------------------------------------------------------------------
/public/gifts/this-is-fine-small.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/this-is-fine-small.webp
--------------------------------------------------------------------------------
/public/gifts/this-is-fine.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/gifts/this-is-fine.webp
--------------------------------------------------------------------------------
/public/img/gifts/amautas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/amautas.png
--------------------------------------------------------------------------------
/public/img/gifts/codely.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/codely.png
--------------------------------------------------------------------------------
/public/img/gifts/dondominio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/dondominio.png
--------------------------------------------------------------------------------
/public/img/gifts/elsa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/elsa.png
--------------------------------------------------------------------------------
/public/img/gifts/javier.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/javier.png
--------------------------------------------------------------------------------
/public/img/gifts/libro-git.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/gifts/libro-git.png
--------------------------------------------------------------------------------
/public/img/speakers/anon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/anon.jpg
--------------------------------------------------------------------------------
/public/img/speakers/carmen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/carmen.jpg
--------------------------------------------------------------------------------
/public/img/speakers/cloudinary.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/cloudinary.jpg
--------------------------------------------------------------------------------
/public/img/speakers/codely-agenda.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/codely-agenda.jpg
--------------------------------------------------------------------------------
/public/img/speakers/david.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/david.jpg
--------------------------------------------------------------------------------
/public/img/speakers/dawntraoz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/dawntraoz.jpg
--------------------------------------------------------------------------------
/public/img/speakers/debbie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/debbie.jpg
--------------------------------------------------------------------------------
/public/img/speakers/dotcsv.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/dotcsv.jpg
--------------------------------------------------------------------------------
/public/img/speakers/east.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/east.jpg
--------------------------------------------------------------------------------
/public/img/speakers/fazt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/fazt.jpg
--------------------------------------------------------------------------------
/public/img/speakers/fernando-rodriguez.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/fernando-rodriguez.jpg
--------------------------------------------------------------------------------
/public/img/speakers/fernando.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/fernando.jpg
--------------------------------------------------------------------------------
/public/img/speakers/freddyVega.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/freddyVega.jpg
--------------------------------------------------------------------------------
/public/img/speakers/frr149.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/frr149.jpg
--------------------------------------------------------------------------------
/public/img/speakers/grimerloner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/grimerloner.jpg
--------------------------------------------------------------------------------
/public/img/speakers/javi.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/javi.jpg
--------------------------------------------------------------------------------
/public/img/speakers/javier.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/javier.jpg
--------------------------------------------------------------------------------
/public/img/speakers/malt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/malt.jpg
--------------------------------------------------------------------------------
/public/img/speakers/midudev.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/midudev.jpg
--------------------------------------------------------------------------------
/public/img/speakers/nerea.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/nerea.jpg
--------------------------------------------------------------------------------
/public/img/speakers/pablokbs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/pablokbs.jpg
--------------------------------------------------------------------------------
/public/img/speakers/patoDev.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/patoDev.jpg
--------------------------------------------------------------------------------
/public/img/speakers/rafa.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/rafa.jpg
--------------------------------------------------------------------------------
/public/img/speakers/rauchg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/rauchg.jpg
--------------------------------------------------------------------------------
/public/img/speakers/s4vitar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/s4vitar.jpg
--------------------------------------------------------------------------------
/public/img/speakers/sorteo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/sorteo.png
--------------------------------------------------------------------------------
/public/img/speakers/teffcode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/speakers/teffcode.jpg
--------------------------------------------------------------------------------
/public/img/sponsors/keepcoding.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/sponsors/keepcoding.webp
--------------------------------------------------------------------------------
/public/img/tickets-effect/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/tickets-effect/bg.png
--------------------------------------------------------------------------------
/public/img/tickets-effect/gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/tickets-effect/gradient.png
--------------------------------------------------------------------------------
/public/img/tickets-effect/noise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/img/tickets-effect/noise.png
--------------------------------------------------------------------------------
/public/og-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/og-image.jpg
--------------------------------------------------------------------------------
/public/regalo-libro-git.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/regalo-libro-git.png
--------------------------------------------------------------------------------
/public/stickers/cloudinary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/cloudinary.png
--------------------------------------------------------------------------------
/public/stickers/glasses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/glasses.png
--------------------------------------------------------------------------------
/public/stickers/keep-coding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/keep-coding.png
--------------------------------------------------------------------------------
/public/stickers/libro-git.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/libro-git.png
--------------------------------------------------------------------------------
/public/stickers/malt.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/stickers/mario.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/mario.png
--------------------------------------------------------------------------------
/public/stickers/midu-angry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-angry.png
--------------------------------------------------------------------------------
/public/stickers/midu-boss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-boss.png
--------------------------------------------------------------------------------
/public/stickers/midu-f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-f.png
--------------------------------------------------------------------------------
/public/stickers/midu-hype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-hype.png
--------------------------------------------------------------------------------
/public/stickers/midu-love.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-love.png
--------------------------------------------------------------------------------
/public/stickers/midu-lul.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-lul.png
--------------------------------------------------------------------------------
/public/stickers/midu-not-like-this.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-not-like-this.png
--------------------------------------------------------------------------------
/public/stickers/midu-snif.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-snif.png
--------------------------------------------------------------------------------
/public/stickers/midu-wink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-wink.png
--------------------------------------------------------------------------------
/public/stickers/midu-wow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-wow.png
--------------------------------------------------------------------------------
/public/stickers/midu-wtf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu-wtf.png
--------------------------------------------------------------------------------
/public/stickers/midu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/midu.png
--------------------------------------------------------------------------------
/public/stickers/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/start.png
--------------------------------------------------------------------------------
/public/stickers/this-is-fine-normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/this-is-fine-normal.png
--------------------------------------------------------------------------------
/public/stickers/this-is-fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/this-is-fine.png
--------------------------------------------------------------------------------
/public/stickers/vercel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/vercel.png
--------------------------------------------------------------------------------
/public/stickers/vercel.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/stickers/yeah.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/midudev/miduconf-website/90e5a674c7fc649e80c2b3cb78a00f6614c56a59/public/stickers/yeah.png
--------------------------------------------------------------------------------
/src/components/Avatar.jsx:
--------------------------------------------------------------------------------
1 | import { useId } from 'react'
2 | import { DEVS } from './SelectFighter'
3 |
4 | export function Avatar ({ team }) {
5 | const id = useId()
6 |
7 | const dev = DEVS[team].find((dev) => dev.id === team)
8 | const src = `img/capitanes-tr/${dev.img}`
9 | const alt = `${dev.name} avatar`
10 |
11 | return (
12 |
13 |
18 | {dev.name}
19 |
20 |
21 |

22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Background.jsx:
--------------------------------------------------------------------------------
1 | export const Background = () => (
2 | <>
3 |
4 |
15 | >
16 | )
17 |
--------------------------------------------------------------------------------
/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils'
2 | import { ComponentPropsWithoutRef } from 'react'
3 |
4 | type Props = {
5 | as?: C
6 | children: React.ReactNode
7 | className?: string
8 | variant?: 'primary' | 'secondary'
9 | disabled?: boolean
10 | } & ComponentPropsWithoutRef
11 |
12 | export const Button = ({
13 | as,
14 | children,
15 | variant = 'primary',
16 | disabled,
17 | ...restOfProps
18 | }: Props) => {
19 | const As = as ?? 'button'
20 |
21 | const variantStyle = {
22 | primary: 'bg-button text-white shadow-button hover:shadow-button-hover hover:scale-110 ',
23 | secondary:
24 | 'border border-midu-primary/40 bg-[#121226] hover:bg-[#1A1A2E] hover:border-midu-primary/60'
25 | }
26 |
27 | return (
28 |
38 | {children}
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Card.jsx:
--------------------------------------------------------------------------------
1 | const background =
2 | 'linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(255, 255, 255, 0.0) 0%, rgba(143, 143, 143, 0.67) 50%, rgba(0, 0, 0, 0) 100%)'
3 |
4 | export function Card() {
5 | return (
6 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/Container3D.tsx:
--------------------------------------------------------------------------------
1 | import Atropos from 'atropos/react'
2 | import { useEffect, useState } from 'react'
3 |
4 | interface Props {
5 | children: React.ReactNode
6 | }
7 |
8 | export const Container3D = ({ children }: Props) => {
9 | const [isMobile, setIsMobile] = useState(false)
10 |
11 | useEffect(() => {
12 | const mediaQuery = window.matchMedia('(max-width: 768px)')
13 | setIsMobile(mediaQuery.matches)
14 |
15 | const handleMediaQueryChange = (e) => {
16 | setIsMobile(e.matches)
17 | }
18 |
19 | mediaQuery.addEventListener('change', handleMediaQueryChange)
20 |
21 | return () => {
22 | mediaQuery.removeEventListener('change', handleMediaQueryChange)
23 | }
24 | }, [])
25 |
26 | return (
27 |
28 |
29 |
30 | {isMobile ? (
31 | <>{children}>
32 | ) : (
33 |
38 | {children}
39 |
40 | )}
41 |
42 |
43 |
44 | )
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/Countdown.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { useRemainingTime } from '../hooks/useRemainingTime'
3 |
4 | const LITERALS = ['Días', null, 'Horas', null, 'Minutos', null, 'Segundos']
5 |
6 | export function Countdown() {
7 | const { seconds, minutes, hours, days } = useRemainingTime(new Date(1726153200000), {
8 | fillingZeros: true
9 | })
10 | const [show, setShow] = useState(false)
11 |
12 | useEffect(() => {
13 | // solo en client side para evitar problemas de hidratacion
14 | setShow(true)
15 | }, [])
16 |
17 | const showValue = (value) => {
18 | if (value === null) return ':'
19 | if (show) return value
20 | return '00'
21 | }
22 |
23 | return (
24 | <>
25 |
26 | {[days, null, hours, null, minutes, null, seconds].map((value, index) => {
27 | return (
28 |
29 |
30 | {showValue(value)}
31 |
32 | {value === null ? ' ' : LITERALS[index]}
33 |
34 |
35 |
36 | )
37 | })}
38 |
39 | >
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Header.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { MiduLogo } from '@/components/logos/midudev'
4 | import { NavbarIcons } from '@/components/icons/navbar'
5 | import { Button } from '@/components/Button'
6 | import { useId, useState } from 'react'
7 | import { cn } from '@/lib/utils'
8 |
9 | export function Header() {
10 | const [isNavbarOpen, setIsNavbarOpen] = useState(false)
11 | const navbarId = useId()
12 |
13 | return (
14 |
15 |
16 |
22 |
23 |
24 |
50 |
51 |
62 |
89 |
90 |
91 |
92 | )
93 | }
94 |
95 | const NAV_ITEMS = [
96 | {
97 | href: '/#speakers',
98 | title: 'Speakers',
99 | Icon: NavbarIcons.SpeakersIcon
100 | },
101 | {
102 | href: '/#sponsors',
103 | title: 'Patrocinadores',
104 | Icon: NavbarIcons.SponsorsIcon
105 | },
106 | {
107 | href: '/#regalos',
108 | title: 'Regalos',
109 | Icon: NavbarIcons.GiftIcon
110 | },
111 | {
112 | href: '/#agenda',
113 | title: 'Agenda',
114 | Icon: NavbarIcons.ScheduleIcon
115 | }
116 | ]
117 |
--------------------------------------------------------------------------------
/src/components/HeaderIndex.jsx:
--------------------------------------------------------------------------------
1 | export const HeaderIndex = () => {
2 | return (
3 |
76 | )
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/HideContentBox.tsx:
--------------------------------------------------------------------------------
1 | interface Props {
2 | title: string
3 | subtitle?: string
4 | BgIcon?: React.ComponentType>
5 | }
6 |
7 | export function HideContentBox({ title, subtitle, BgIcon }: Props) {
8 | return (
9 |
10 |
11 |
12 |
{title}
13 | {subtitle && (
14 |
15 | {subtitle}
16 |
17 | )}
18 | {BgIcon && (
19 |
20 | )}
21 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/LinearCard.jsx:
--------------------------------------------------------------------------------
1 | import { inter } from '../pages'
2 |
3 | export function LinearCard ({ className, children, title }) {
4 | return (
5 |
6 |
7 | {title}
8 |
9 |
10 | {children}
11 |
12 |
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Logo.jsx:
--------------------------------------------------------------------------------
1 | export function Logo() {
2 | return (
3 |
6 |
7 | midu
8 |
9 | Conf
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/Meteor.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx'
2 | import { CSSProperties, useEffect, useState } from 'react'
3 |
4 | interface MeteorsProps {
5 | number?: number
6 | }
7 |
8 | export const Meteors = ({ number = 20 }: MeteorsProps) => {
9 | const [meteorStyles, setMeteorStyles] = useState>([])
10 |
11 | useEffect(() => {
12 | const styles = [...new Array(number)].map(() => ({
13 | top: -5,
14 | left: Math.floor(Math.random() * 100) + '%',
15 | animationDelay: Math.random() * 0.6 + 0.2 + 's',
16 | animationDuration: Math.floor(Math.random() * 8 + 2) + 's'
17 | }))
18 |
19 | setMeteorStyles(styles)
20 | }, [number])
21 |
22 | return (
23 | <>
24 | {[...meteorStyles].map((style, idx) => (
25 | // Meteor Head
26 |
33 | {/* Meteor Tail */}
34 |
44 |
45 | ))}
46 | >
47 | )
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/MeteorLanguages.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import clsx from 'clsx'
4 | import { useEffect, useRef, useState } from 'react'
5 |
6 | interface MeteorsProps {
7 | number?: number
8 | }
9 |
10 | export const Meteors = ({ number = 5 }: MeteorsProps) => {
11 | const [meteorStyles, setMeteorStyles] = useState([])
12 | const ref = useRef(null)
13 |
14 | useEffect(() => {
15 | // get height of container using ref
16 | const height = ref.current.clientHeight
17 |
18 | const styles = [...new Array(number)].map(() => ({
19 | head: {
20 | top: Math.floor(Math.random() * height) + 'px',
21 | left: Math.floor(Math.random() * window.innerWidth) + 'px',
22 | animationDelay: Math.random() * 1 + 0.2 + 's',
23 | animationDuration: Math.floor(Math.random() * 8 + 2) + 's'
24 | },
25 | tail: {
26 | background: `linear-gradient(to right, ${
27 | Math.random() < 0.5 ? '#0099FF' : '#DEF2FF'
28 | }, transparent)`
29 | }
30 | }))
31 |
32 | setMeteorStyles(styles)
33 | }, [number])
34 |
35 | return (
36 |
40 | {[...meteorStyles].map(({ head, tail }, idx) => (
41 | // Meteor Head
42 |
49 | {/* Meteor Tail */}
50 |
54 |
55 | ))}
56 |
57 | )
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/Modal.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | interface Props {
4 | isOpen?: boolean
5 | onClose: () => void
6 | children: React.ReactNode
7 | }
8 |
9 | export function Modal({ isOpen = false, onClose, children }: Props) {
10 | if (!isOpen) return null
11 |
12 | return (
13 | <>
14 |
15 |
51 | >
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/Mouse.jsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useEffect, useState } from 'react'
4 |
5 | export default function MouseEffect () {
6 | const [{ x, y }, setCursorPosition] = useState({ x: 0, y: 0 })
7 |
8 | useEffect(() => {
9 | const handleMouseMove = (event) => {
10 | const { clientX, clientY } = event
11 | setCursorPosition({ x: clientX, y: clientY })
12 | }
13 |
14 | window.addEventListener('mousemove', handleMouseMove)
15 |
16 | return () => {
17 | window.removeEventListener('mousemove', handleMouseMove)
18 | }
19 | }, [])
20 |
21 | if (x !== 0 && y !== 0) {
22 | return (
23 |
29 | )
30 | }
31 | return null
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/ShareTicketButton.jsx:
--------------------------------------------------------------------------------
1 | export function ShareTicketButton ({ children, size = 'small' }) {
2 | return (
3 |
8 |
9 |
16 | {children}
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Speakers.tsx:
--------------------------------------------------------------------------------
1 | const SPEAKERS = [
2 | {
3 | name: 'Guillermo Rauch',
4 | title: 'CEO @ Vercel',
5 | twitter: 'rauchg',
6 | img: 'rauchg',
7 | country: '🇦🇷'
8 | },
9 | {
10 | name: 'Carmen Ansio',
11 | title: 'Design Engineer @ LottieFiles',
12 | twitter: 'carmenansio',
13 | img: 'carmen',
14 | country: '🇪🇸'
15 | },
16 | {
17 | name: 'DotCSV',
18 | title: 'Divulgador de IA',
19 | twitter: 'dotcsv',
20 | img: 'dotcsv',
21 | country: '🇮🇨'
22 | },
23 | {
24 | name: 'Alba Silvente',
25 | title: 'FullStack @ StoryBlok',
26 | twitter: 'dawntraoz',
27 | img: 'dawntraoz',
28 | country: '🇪🇸'
29 | },
30 | {
31 | name: 'Pelado Nerd',
32 | title: 'Divulgador DevOps',
33 | twitter: 'pablokbs',
34 | img: 'pablokbs',
35 | country: '🇦🇷'
36 | },
37 | {
38 | name: 'Fazt',
39 | title: 'Creador de contenido',
40 | twitter: 'FaztTech',
41 | img: 'fazt',
42 | country: '🇵🇪'
43 | },
44 | {
45 | name: 'Estefany Aguilar',
46 | title: 'Sr. Frontend Dev @ Platzi',
47 | twitter: 'teffcode',
48 | img: 'teffcode',
49 | country: '🇨🇴'
50 | },
51 | {
52 | name: 'S4vitar',
53 | title: 'Hack4u CEO & Founder',
54 | twitter: 's4vitar',
55 | img: 's4vitar',
56 | country: '🇪🇸'
57 | },
58 | {
59 | name: 'Freddy Vega',
60 | title: 'CEO @ Platzi',
61 | twitter: 'freddier',
62 | img: 'freddyVega',
63 | country: '🇨🇴'
64 | },
65 | {
66 | name: 'PatoDev',
67 | title: 'Media Developer @ Cloudinary',
68 | twitter: 'devpato',
69 | img: 'patoDev',
70 | country: '🇺🇸'
71 | },
72 | {
73 | name: 'Grimerloner',
74 | title: 'Músico y Productor',
75 | instagram: 'grimerloner',
76 | img: 'grimerloner',
77 | country: '🇪🇸'
78 | },
79 | {
80 | name: 'Fernando Rodríguez',
81 | title: 'Co-Founder @ KeepCoding',
82 | twitter: 'frr149',
83 | img: 'fernando-rodriguez',
84 | country: '🇪🇸'
85 | },
86 | {
87 | name: 'Javier Ferrer',
88 | title: 'Co-Founder @ Codely',
89 | twitter: 'CodelyTV',
90 | img: 'javi',
91 | country: '🇪🇸'
92 | },
93 | {
94 | name: 'Rafa Gomez',
95 | title: 'Co-Founder @ Codely',
96 | twitter: 'CodelyTV',
97 | img: 'rafa',
98 | country: '🇪🇸'
99 | }
100 | ]
101 |
102 | interface Props {
103 | name: string
104 | title: string
105 | twitter?: string
106 | img: string
107 | country: string
108 | instagram?: string
109 | }
110 |
111 | function Speaker({ name, title, twitter, img, country, instagram }: Props) {
112 | return (
113 |
114 |
115 |
116 |
121 |
126 |
127 |
152 |
156 |
157 |
158 | )
159 | }
160 |
161 | export function Speakers() {
162 | return (
163 |
167 |
168 | Sobre nuestros speakers
169 |
170 |
171 | Divulgadores y profesionales de programación y la tecnología.
172 |
173 |
174 | {SPEAKERS.map((speaker) => (
175 |
176 | ))}
177 |
178 |
179 | )
180 | }
181 |
--------------------------------------------------------------------------------
/src/components/Stars.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | const NUM_STARS = 150
4 |
5 | export function Stars() {
6 | const divRef = useRef(null)
7 |
8 | useEffect(() => {
9 | const stars = divRef.current
10 | if (!stars) return
11 |
12 | divRef.current.querySelectorAll('div').forEach((star) => {
13 | const size = Math.random() > 0.5 ? 1 : 2
14 | star.style.width = `${size}px`
15 | star.style.height = `${size}px`
16 | star.style.opacity = `${Math.random()}`
17 | star.style.top = `${Math.random() * 100}vh`
18 | star.style.left = `${Math.random() * 100}vw`
19 | })
20 | }, [])
21 |
22 | return (
23 |
24 | {Array.from({ length: NUM_STARS }, (_, i) => i).map((i) => (
25 |
26 | ))}
27 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/Tooltip.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useRef, useState } from 'react'
4 | import {
5 | useFloating,
6 | autoUpdate,
7 | offset,
8 | flip,
9 | shift,
10 | useHover,
11 | useRole,
12 | useInteractions,
13 | FloatingArrow,
14 | arrow,
15 | type Placement
16 | } from '@floating-ui/react'
17 | import { cn } from '@/lib/utils'
18 |
19 | interface Props {
20 | children: React.ReactNode
21 | text: React.ReactNode
22 | tooltipPosition?: Placement
23 | offsetNumber?: number
24 | tooltipClassName?: string
25 | }
26 |
27 | export function Tooltip({
28 | children,
29 | text,
30 | tooltipPosition = 'bottom',
31 | offsetNumber = 12,
32 | tooltipClassName = ''
33 | }: Props) {
34 | const [isOpen, setIsOpen] = useState(false)
35 | const arrowRef = useRef(null)
36 |
37 | const { refs, floatingStyles, context } = useFloating({
38 | open: isOpen,
39 | onOpenChange: setIsOpen,
40 | middleware: [
41 | offset(offsetNumber),
42 | flip(),
43 | shift(),
44 | arrow({
45 | element: arrowRef
46 | })
47 | ],
48 | whileElementsMounted: autoUpdate,
49 | placement: tooltipPosition
50 | })
51 |
52 | const hover = useHover(context, { move: true })
53 | const role = useRole(context, {
54 | role: 'tooltip'
55 | })
56 |
57 | const { getReferenceProps, getFloatingProps } = useInteractions([hover, role])
58 |
59 | return (
60 | <>
61 |
62 | {children}
63 |
64 | {isOpen && (
65 |
74 | {text}
75 |
84 |
85 | )}
86 | >
87 | )
88 | }
89 |
--------------------------------------------------------------------------------
/src/components/TwitchBlock.jsx:
--------------------------------------------------------------------------------
1 | import { interTight } from '../pages'
2 | import { TwitchLogo } from './TwitchLogo'
3 |
4 | export function TwitchBlock () {
5 | return (
6 |
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/TwitchIcon.jsx:
--------------------------------------------------------------------------------
1 | export const TwitchIcon = ({ className = 'w-20 h-20' }) => {
2 | return (
3 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/TwitchLogo.jsx:
--------------------------------------------------------------------------------
1 | export function TwitchLogo({ className }) {
2 | return (
3 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/TypeBadge.jsx:
--------------------------------------------------------------------------------
1 | import { IconRun } from '@tabler/icons-react'
2 |
3 | const types = {
4 | sprint: {
5 | name: 'Sprint',
6 | icon: IconRun,
7 | className: 'bg-yellow-900 text-yellow-300'
8 | }
9 | }
10 |
11 | export const TypeBadge = ({ name }) => {
12 | const info = types[name]
13 |
14 | if (!info) return null
15 |
16 | return (
17 |
18 |
19 | {info[name]}
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/icons/index.ts:
--------------------------------------------------------------------------------
1 | export { TicketIcon } from './ticket'
2 | export { TwitchIcon } from './twitch'
3 |
--------------------------------------------------------------------------------
/src/components/icons/languages/angular.tsx:
--------------------------------------------------------------------------------
1 | export function AngularIcon({ className = '', ...props }) {
2 | return (
3 |
95 | )
96 | }
97 |
--------------------------------------------------------------------------------
/src/components/icons/languages/astro.tsx:
--------------------------------------------------------------------------------
1 | export function AstroIcon({ className = '', ...props }) {
2 | return (
3 |
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/icons/languages/csharp.tsx:
--------------------------------------------------------------------------------
1 | export function CSharpIcon({ className = '', ...props }) {
2 | return (
3 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/icons/languages/css.tsx:
--------------------------------------------------------------------------------
1 | export function CSSIcon({ className = '', ...props }) {
2 | return (
3 |
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/icons/languages/dart.tsx:
--------------------------------------------------------------------------------
1 | export function DartIcon({ className = '', ...props }) {
2 | return (
3 |
63 | )
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/icons/languages/deno.tsx:
--------------------------------------------------------------------------------
1 | export function DenoIcon({ className = '', ...props }) {
2 | return (
3 |
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/icons/languages/github.tsx:
--------------------------------------------------------------------------------
1 | export function GithubIcon({ className = '', ...props }) {
2 | return (
3 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/icons/languages/html.tsx:
--------------------------------------------------------------------------------
1 | export function HtmlIcon({ className = '', ...props }) {
2 | return (
3 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/icons/languages/index.ts:
--------------------------------------------------------------------------------
1 | import { AngularIcon } from './angular'
2 | import { AstroIcon } from './astro'
3 | import { BunIcon } from './bun'
4 | import { CIcon } from './c'
5 | import { CSharpIcon } from './csharp'
6 | import { CSSIcon } from './css'
7 | import { DartIcon } from './dart'
8 | import { DenoIcon } from './deno'
9 | import { FirebaseIcon } from './firebase'
10 | import { FlutterIcon } from './flutter'
11 | import { GithubIcon } from './github'
12 | import { GolangIcon } from './golang'
13 | import { HtmlIcon } from './html'
14 | import { IntellijIcon } from './intellij'
15 | import { JavaIcon } from './java'
16 | import { JavaScriptIcon } from './javascript'
17 | import { LinuxIcon } from './linux'
18 | import { Markdown } from './markdown'
19 | import { MySQLIcon } from './mysql'
20 | import { NestJSIcon } from './nestjs'
21 | import { NextIcon } from './next'
22 | import { NodeIcon } from './node'
23 | import { NpmIcon } from './npm'
24 | import { NuxtIcon } from './nuxt'
25 | import { PhpIcon } from './php'
26 | import { PnpmIcon } from './pnpm'
27 | import { PreactIcon } from './preact'
28 | import { PythonIcon } from './python'
29 | import { QwikIcon } from './qwik'
30 | import { ReactIcon } from './react'
31 | import { RubyIcon } from './ruby'
32 | import { RustIcon } from './rust'
33 | import { ScalaIcon } from './scala'
34 | import { SolidIcon } from './solid'
35 | import { SvelteIcon } from './svelte'
36 | import { TailwindIcon } from './tailwind'
37 | import { TypeScriptIcon } from './typescript'
38 | import { VimIcon } from './vim'
39 | import { ViteIcon } from './vite'
40 | import { VSCodeIcon } from './vscode'
41 | import { VueIcon } from './vue'
42 |
43 | export const FLAVORS_ICONS = {
44 | javascript: JavaScriptIcon,
45 | typescript: TypeScriptIcon,
46 | html: HtmlIcon,
47 | css: CSSIcon,
48 | react: ReactIcon,
49 | vue: VueIcon,
50 | angular: AngularIcon,
51 | svelte: SvelteIcon,
52 | preact: PreactIcon,
53 | solid: SolidIcon,
54 | astro: AstroIcon,
55 | node: NodeIcon,
56 | deno: DenoIcon,
57 | bun: BunIcon,
58 | npm: NpmIcon,
59 | github: GithubIcon,
60 | next: NextIcon,
61 | nuxt: NuxtIcon,
62 | vite: ViteIcon,
63 | vscode: VSCodeIcon,
64 | python: PythonIcon,
65 | qwik: QwikIcon,
66 | dart: DartIcon,
67 | flutter: FlutterIcon,
68 | firebase: FirebaseIcon,
69 | nestjs: NestJSIcon,
70 | golang: GolangIcon,
71 | php: PhpIcon,
72 | mysql: MySQLIcon,
73 | java: JavaIcon,
74 | csharp: CSharpIcon,
75 | scala: ScalaIcon,
76 | vim: VimIcon,
77 | intellij: IntellijIcon,
78 | rust: RustIcon,
79 | markdown: Markdown,
80 | linux: LinuxIcon,
81 | ruby: RubyIcon,
82 | tailwind: TailwindIcon,
83 | c: CIcon,
84 | pnpm:PnpmIcon
85 | }
86 |
--------------------------------------------------------------------------------
/src/components/icons/languages/javascript.tsx:
--------------------------------------------------------------------------------
1 | export const JavaScriptIcon = ({ className = '', ...props }) => {
2 | return (
3 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/icons/languages/markdown.tsx:
--------------------------------------------------------------------------------
1 | export function Markdown({ className = '', ...props }) {
2 | return (
3 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/icons/languages/next.tsx:
--------------------------------------------------------------------------------
1 | export function NextIcon({ className = '', ...props }) {
2 | return (
3 |
64 | )
65 | }
66 |
--------------------------------------------------------------------------------
/src/components/icons/languages/node.tsx:
--------------------------------------------------------------------------------
1 | export function NodeIcon({ className = '', ...props }) {
2 | return (
3 |
104 | )
105 | }
106 |
--------------------------------------------------------------------------------
/src/components/icons/languages/npm.tsx:
--------------------------------------------------------------------------------
1 | export function NpmIcon({ className = '', ...props }) {
2 | return (
3 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/icons/languages/nuxt.tsx:
--------------------------------------------------------------------------------
1 | export function NuxtIcon({ className = '', ...props }) {
2 | return (
3 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/icons/languages/php.tsx:
--------------------------------------------------------------------------------
1 | export function PhpIcon({ className = '', ...props }) {
2 | return (
3 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/icons/languages/pnpm.tsx:
--------------------------------------------------------------------------------
1 | export function PnpmIcon({ className = '', ...props }) {
2 | return (
3 |
81 | )
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/icons/languages/preact.tsx:
--------------------------------------------------------------------------------
1 | export function PreactIcon({ className = '', ...props }) {
2 | return (
3 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/icons/languages/svelte.tsx:
--------------------------------------------------------------------------------
1 | export function SvelteIcon({ className = '', ...props }) {
2 | return (
3 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/icons/languages/tailwind.tsx:
--------------------------------------------------------------------------------
1 | export function TailwindIcon({ className = '', ...props }) {
2 | return (
3 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/icons/languages/typescript.tsx:
--------------------------------------------------------------------------------
1 | export function TypeScriptIcon({ className = '', ...props }) {
2 | return (
3 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/icons/languages/vue.tsx:
--------------------------------------------------------------------------------
1 | export function VueIcon({ className = '', ...props }) {
2 | return (
3 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/discord.tsx:
--------------------------------------------------------------------------------
1 | export function DiscordLogo({ className = '', ...props }) {
2 | return (
3 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/gift.tsx:
--------------------------------------------------------------------------------
1 | export function GiftIcon({ className = '', ...props }) {
2 | return (
3 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/index.ts:
--------------------------------------------------------------------------------
1 | import { DiscordLogo } from './discord'
2 | import { GiftIcon } from './gift'
3 | import { ScheduleIcon } from './schedule'
4 | import { SpeakersIcon } from './speakers'
5 | import { SponsorsIcon } from './sponsors'
6 |
7 | export const NavbarIcons = {
8 | GiftIcon,
9 | ScheduleIcon,
10 | SpeakersIcon,
11 | SponsorsIcon,
12 | DiscordLogo
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/schedule.tsx:
--------------------------------------------------------------------------------
1 | export const ScheduleIcon = ({ className = '', ...props }) => (
2 |
27 | )
28 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/speakers.tsx:
--------------------------------------------------------------------------------
1 | export function SpeakersIcon({ className = '', ...props }) {
2 | return (
3 |
48 | )
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/icons/navbar/sponsors.tsx:
--------------------------------------------------------------------------------
1 | export function SponsorsIcon({ className = '', ...props }) {
2 | return (
3 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/cloudinary.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils'
2 |
3 | export function CloudinaryIcon({ className = '', ...props }) {
4 | return (
5 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/codely.tsx:
--------------------------------------------------------------------------------
1 | export function CodelyIcon({ className = '', ...props }) {
2 | return (
3 |
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/index.ts:
--------------------------------------------------------------------------------
1 | import { DonDominioIcon } from './don-dominio'
2 | import { KeepCodingIcon } from './keepcode'
3 | import { PlatziIcon } from './platzi'
4 | import { InfoJobsIcon } from './infojobs'
5 | import { CloudinaryIcon } from './cloudinary'
6 | import { LemonCodeHorizontalIcon } from './lemon-horizontal'
7 | import { LemonCodeVerticalIcon } from './lemon-vertical'
8 | import { MaltIcon } from './malt'
9 | import { CodelyIcon } from './codely'
10 | import { Scrimba } from './scrimba'
11 | import { Strapi } from './strapi'
12 |
13 | export const SponsorIcons = {
14 | platzi: PlatziIcon,
15 | donDominio: DonDominioIcon,
16 | keepCoding: KeepCodingIcon,
17 | infoJobs: InfoJobsIcon,
18 | cloudinary: CloudinaryIcon,
19 | lemonCodeHorizontal: LemonCodeHorizontalIcon,
20 | lemonCodeVertical: LemonCodeVerticalIcon,
21 | malt: MaltIcon,
22 | codely: CodelyIcon,
23 | scrimba: Scrimba,
24 | strapi: Strapi
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/infojobs.tsx:
--------------------------------------------------------------------------------
1 | export function InfoJobsIcon({ className = '', ...props }) {
2 | return (
3 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/keepcode.tsx:
--------------------------------------------------------------------------------
1 | export function KeepCodingIcon({ className = '', ...props }) {
2 | return (
3 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/lemon-vertical.tsx:
--------------------------------------------------------------------------------
1 | export function LemonCodeVerticalIcon({ className = '', ...props }) {
2 | return (
3 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/malt.tsx:
--------------------------------------------------------------------------------
1 | export const MaltIcon = ({ className, ...props }) => (
2 |
15 | )
16 |
--------------------------------------------------------------------------------
/src/components/icons/sponsors/platzi.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils'
2 |
3 | export function PlatziIcon({ className = '', ...props }) {
4 | return (
5 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/icons/stickers/don-dominio.tsx:
--------------------------------------------------------------------------------
1 | export function DonDominio({ className = '', ...props }) {
2 | return (
3 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/icons/stickers/index.tsx:
--------------------------------------------------------------------------------
1 | import { DonDominio } from './don-dominio'
2 | import { LemonCode } from './lemon-code'
3 | import { Platzi } from './platzi'
4 | import { Twitch } from './twitch'
5 |
6 | export const Stickers = {
7 | Glasses: ({ className }) =>
,
8 | MiduWink: ({ className }) =>
,
9 | MiduBoss: ({ className }) =>
,
10 | MiduHype: ({ className }) =>
,
11 | MiduWtf: ({ className }) =>
,
12 | MiduF: ({ className }) =>
,
13 | MiduNotLikeThis: ({ className }) => (
14 |
15 | ),
16 | MiduAngry: ({ className }) =>
,
17 | MiduLul: ({ className }) =>
,
18 | MiduSnif: ({ className }) =>
,
19 | MiduWow: ({ className }) =>
,
20 | MiduLove: ({ className }) =>
,
21 | Twitch,
22 | Platzi,
23 | LemonCode,
24 | DonDominio,
25 | ThisIsFine: ({ className }) => (
26 |
27 | ),
28 | Start: ({ className }) =>
,
29 | Midu: ({ className }) =>
,
30 | KeepCoding: ({ className }) => (
31 |
32 | ),
33 | Cloudinary: ({ className }) => (
34 |
35 | ),
36 | Mario: ({ className }) =>
,
37 | LibroGit: ({ className }) =>
,
38 | Vercel: ({ className }) =>
,
39 | Malt: ({ className }) =>
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/icons/stickers/platzi.tsx:
--------------------------------------------------------------------------------
1 | export function Platzi({ className = '', ...props }) {
2 | return (
3 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/icons/stickers/twitch.tsx:
--------------------------------------------------------------------------------
1 | export function Twitch({ className = '', ...props }) {
2 | return (
3 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/icons/ticket.tsx:
--------------------------------------------------------------------------------
1 | export function TicketIcon({ className = '', ...props }) {
2 | return (
3 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/icons/twitch.tsx:
--------------------------------------------------------------------------------
1 | export function TwitchIcon({ className = '', ...props }) {
2 | return (
3 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/logos/codely.tsx:
--------------------------------------------------------------------------------
1 | export const Codely = ({ className }) => (
2 |
35 | )
36 |
--------------------------------------------------------------------------------
/src/components/logos/dondominio.tsx:
--------------------------------------------------------------------------------
1 | export const DonDominio = ({ className, fill = '#A9AAAC' }) => (
2 |
26 | )
27 |
--------------------------------------------------------------------------------
/src/components/logos/midudev.tsx:
--------------------------------------------------------------------------------
1 | export const MiduLogo = ({ className = '', ...props }) => (
2 |
32 | )
33 |
--------------------------------------------------------------------------------
/src/components/magicui/Marquee.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils'
2 | import { Children, ReactNode, cloneElement } from 'react'
3 |
4 | interface MarqueeProps {
5 | className?: string
6 | reverse?: boolean
7 | pauseOnHover?: boolean
8 | children?: ReactNode
9 | [key: string]: unknown
10 | size?: string
11 | }
12 |
13 | export const Marquee = ({
14 | className,
15 | reverse,
16 | pauseOnHover = false,
17 | size = 'small',
18 | children,
19 | ...props
20 | }: MarqueeProps) => {
21 | return (
22 |
28 |
35 | {children}
36 | {size !== 'large' && Children.map(children, (child) => cloneElement(child as any))}
37 |
38 |
39 | )
40 | }
41 |
42 | export default Marquee
43 |
--------------------------------------------------------------------------------
/src/components/magicui/RadialGradient.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react'
2 |
3 | type Type = 'circle' | 'ellipse'
4 |
5 | type Origin = 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top left' | 'top right' | 'bottom left' | 'bottom right'
6 |
7 | interface RadialProps {
8 | /**
9 | * The type of radial gradient
10 | * @default circle
11 | * @type string
12 | */
13 | type?: Type
14 | /**
15 | * The color to transition from
16 | * @default #00000000
17 | * @type string
18 | * */
19 | from?: string
20 |
21 | /**
22 | * The color to transition to
23 | * @default #290A5C
24 | * @type string
25 | * */
26 | to?: string
27 |
28 | /**
29 | * The size of the gradient in pixels
30 | * @default 300
31 | * @type number
32 | * */
33 | size?: number
34 |
35 | /**
36 | * The origin of the gradient
37 | * @default center
38 | * @type string
39 | * */
40 | origin?: Origin
41 |
42 | /**
43 | * The class name to apply to the gradient
44 | * @default ""
45 | * @type string
46 | * */
47 | className?: string
48 | }
49 |
50 | export const RadialGradient = ({
51 | type = 'circle',
52 | from = 'rgba(120,119,198,0.3)',
53 | to = 'hsla(0, 0%, 0%, 0)',
54 | size = 300,
55 | origin = 'center',
56 | className
57 | }: RadialProps) => {
58 | const styles: CSSProperties = {
59 | position: 'absolute',
60 | pointerEvents: 'none',
61 | inset: 0,
62 | backgroundImage: `radial-gradient(${type} ${size}px at ${origin}, ${from}, ${to})`
63 | }
64 |
65 | return
66 | }
67 |
--------------------------------------------------------------------------------
/src/components/utilities/timezone.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Mapeo de Abreviaturas de Zonas Horarias
3 |
4 | Este objeto proporciona abreviaturas para zonas horarias globales, facilitando la gestión y visualización de información de tiempo en diversas regiones. Incluye zonas horarias para América del Norte, Europa, Asia, Australia, África y Sudamérica, además de otras zonas globales significativas.
5 |
6 | Cada entrada vincula un identificador de zona horaria IANA con su abreviatura común.
7 |
8 | Fuente de algunos datos de zona horaria: https://www.healthstream.com/hlchelp/Administrator/Classes/HLC_Time_Zone_Abbreviations.htm
9 |
10 | */
11 | const timeZoneAbbreviations: { [key: string]: string } = {
12 | // North America, including specific zones for Mexico
13 | 'America/New_York': 'ET', // Eastern Time
14 | 'America/Chicago': 'CT', // Central Time
15 | 'America/Denver': 'MT', // Mountain Time
16 | 'America/Phoenix': 'MST', // Mountain Time (no DST)
17 | 'America/Los_Angeles': 'PT', // Pacific Time
18 | 'America/Anchorage': 'AKST', // Alaska Time
19 | 'America/Honolulu': 'HST', // Hawaii Time
20 | 'America/Mexico_City': 'CST', // Central Standard Time (Mexico)
21 | 'America/Chihuahua': 'MST', // Mountain Standard Time (Mexico)
22 | 'America/Mazatlan': 'MST', // Mountain Standard Time (Mexico Pacific Coast)
23 | 'America/Merida': 'CST', // Central Standard Time (Mexico)
24 | 'America/Monterrey': 'CST', // Central Standard Time (Mexico)
25 | 'America/Tijuana': 'PST', // Pacific Standard Time (Mexico)
26 | 'America/Cancun': 'EST', // Eastern Standard Time (Mexico)
27 |
28 | // Europe
29 | 'Europe/London': 'GMT', // British Time (GMT/BST)
30 | 'Europe/Berlin': 'CET', // Central European Time
31 | 'Europe/Paris': 'CET', // Central European Time (France)
32 | 'Europe/Moscow': 'MSK', // Moscow Time
33 | 'Europe/Athens': 'EET', // Eastern European Time
34 |
35 | // Asia
36 | 'Asia/Tokyo': 'JST', // Japan Standard Time
37 | 'Asia/Hong_Kong': 'HKT', // Hong Kong Time
38 | 'Asia/Singapore': 'SGT', // Singapore Time
39 | 'Asia/Calcutta': 'IST', // Indian Standard Time
40 | 'Asia/Bangkok': 'ICT', // Indochina Time
41 | 'Asia/Shanghai': 'CST', // China Standard Time
42 | 'Asia/Seoul': 'KST', // Korea Standard Time
43 |
44 | // Australia
45 | 'Australia/Sydney': 'AEDT', // Australian Eastern Daylight Time
46 | 'Australia/Adelaide': 'ACDT', // Australian Central Daylight Time
47 | 'Australia/Perth': 'AWST', // Australian Western Time
48 | 'Australia/Brisbane': 'AEST', // Australian Eastern Standard Time (no DST)
49 |
50 | // Africa
51 | 'Africa/Johannesburg': 'SAST', // South African Standard Time
52 | 'Africa/Cairo': 'EET', // Eastern European Time (Egypt)
53 | 'Africa/Lagos': 'WAT', // West Africa Time
54 |
55 | // South America, for countries with one time zone we use the country code to improve readability
56 | 'America/Sao_Paulo': 'BRT', // Brasilia Time
57 | 'America/Buenos_Aires': 'ARG', // Argentine Time
58 | 'America/Lima': 'PE', // Peruvian Time
59 | 'America/Bogota': 'COL', // Colombian Time
60 | 'America/Caracas': 'VE', // Venezuelan Standard Time
61 | 'America/Montevideo': 'UY', // Uruguayan Time
62 | 'America/Santiago': 'CL', // Chilean Time
63 |
64 | // Additional Global Time Zones
65 | 'Pacific/Auckland': 'NZDT', // New Zealand Daylight Time
66 | 'Atlantic/Reykjavik': 'GMT', // Iceland Time
67 | 'Pacific/Fiji': 'FJT', // Fiji Time
68 | 'Pacific/Tongatapu': 'TOT', // Tonga Time
69 | 'Etc/UTC': 'UTC', // Coordinated Universal Time
70 | 'America/St_Johns': 'NST', // Newfoundland Time
71 | 'Asia/Kathmandu': 'NPT', // Nepal Time
72 | 'Asia/Yerevan': 'AMT', // Armenia Time
73 | 'Asia/Baku': 'AZT', // Azerbaijan Time
74 | 'Asia/Karachi': 'PKT' // Pakistan Standard Time
75 | } as const
76 |
77 | export function formatEventTimeWithTimeZoneName(timestamp: number, timeZone: string): string {
78 | const formattedTime = new Intl.DateTimeFormat('es-ES', {
79 | hour: 'numeric',
80 | minute: 'numeric',
81 | hour12: false,
82 | timeZone
83 | }).format(new Date(timestamp))
84 |
85 | const timeZoneName =
86 | timeZoneAbbreviations[timeZone] ||
87 | new Intl.DateTimeFormat('es-ES', {
88 | timeZone,
89 | timeZoneName: 'short'
90 | })
91 | .formatToParts(new Date(timestamp))
92 | .find((part) => part.type === 'timeZoneName')?.value
93 |
94 | return `${formattedTime} ${timeZoneName}`
95 | }
96 |
--------------------------------------------------------------------------------
/src/hooks/useRemainingTime.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | type RemainingDate = {
4 | days: T
5 | hours: T
6 | minutes: T
7 | seconds: T
8 | }
9 |
10 | const localeDate = (date?: Date) => {
11 | const d = date || new Date()
12 | return new Date(d.toLocaleString('en-US'))
13 | }
14 |
15 | const mapValues = (object: { [key: string]: unknown }, iterator: (key: unknown) => void) => {
16 | return Object.keys(object).reduce((acc, key) => {
17 | acc[key] = iterator(object[key])
18 | return acc
19 | }, {})
20 | }
21 |
22 | const alwaysPositive = (value: number) => Math.max(0, value)
23 |
24 | const getRemainingTime = (targetDate: Date) => {
25 | const currentDate = localeDate()
26 | const diff = targetDate.getTime() - currentDate.getTime()
27 | const days = alwaysPositive(Math.floor(diff / (1000 * 60 * 60 * 24)))
28 | const hours = alwaysPositive(Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)))
29 |
30 | const minutes = alwaysPositive(Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)))
31 |
32 | const seconds = alwaysPositive(Math.floor((diff % (1000 * 60)) / 1000))
33 | return { days, hours, minutes, seconds }
34 | }
35 |
36 | const fillZeros = (remainingDate: RemainingDate) => {
37 | return mapValues(remainingDate, (value) => `${value}`.padStart(2, '0')) as RemainingDate
38 | }
39 |
40 | export const useRemainingTime = (targetDate: Date, { fillingZeros = true }) => {
41 | const [remainingDate, setRemainingDate] = useState(getRemainingTime(targetDate))
42 |
43 | const { seconds, minutes, hours, days } = remainingDate
44 | const countdownEnded = days === 0 && hours === 0 && minutes === 0 && seconds === 0
45 |
46 | useEffect(() => {
47 | const timer =
48 | !countdownEnded &&
49 | setInterval(() => {
50 | setRemainingDate(getRemainingTime(targetDate))
51 | }, 1000)
52 |
53 | if (countdownEnded) clearInterval(timer)
54 |
55 | return () => clearInterval(timer)
56 | }, [countdownEnded, targetDate])
57 |
58 | const remainingDateToReturn = fillingZeros ? fillZeros(remainingDate) : remainingDate
59 |
60 | return { ...remainingDateToReturn, countdownEnded }
61 | }
62 |
--------------------------------------------------------------------------------
/src/lib/supabase.js:
--------------------------------------------------------------------------------
1 | import { createClient } from '@supabase/supabase-js'
2 |
3 | export const supabase = createClient(
4 | process.env.NEXT_PUBLIC_SUPABASE_URL,
5 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
6 | )
7 |
8 | const supabaseAcademyURL = 'https://vvimuilmzwgmuyepndjd.supabase.co'
9 | export const supabaseAdminAcademy = createClient(
10 | supabaseAcademyURL,
11 | process.env.SUPABASE_ACADEMY_ADMIN_KEY
12 | )
13 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import clsx, { ClassValue } from 'clsx'
2 | import { twMerge } from 'tailwind-merge'
3 |
4 | export function cn (...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/src/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '@/styles/globals.css'
2 |
3 | import { createPagesBrowserClient } from '@supabase/auth-helpers-nextjs'
4 | import { SessionContextProvider } from '@supabase/auth-helpers-react'
5 | import { useState } from 'react'
6 |
7 | export default function App ({ Component, pageProps }) {
8 | // Create a new supabase browser client on every first render.
9 | const [supabaseClient] = useState(() => createPagesBrowserClient())
10 |
11 | return (
12 |
16 |
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/src/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 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/src/pages/api/auth/callback.js:
--------------------------------------------------------------------------------
1 | import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
2 |
3 | const handler = async (req, res) => {
4 | try {
5 | const { code } = req.query
6 |
7 | if (code) {
8 | const supabase = createPagesServerClient({ req, res })
9 | await supabase.auth.exchangeCodeForSession(String(code))
10 | }
11 |
12 | res.redirect('/ticket')
13 | } catch (e) {
14 | console.error(e)
15 | }
16 | }
17 |
18 | export default handler
19 |
--------------------------------------------------------------------------------
/src/pages/api/number.js:
--------------------------------------------------------------------------------
1 | import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
2 |
3 | export default async function handler (req, res) {
4 | const supabase = createPagesServerClient({ req, res })
5 |
6 | // count number of tickets
7 | const { count: number } = await supabase.from('ticket').select('*', { count: 'exact' })
8 |
9 | return res.status(200).json({ number: number + 1 })
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import { GeistSans } from 'geist/font/sans'
2 |
3 | import { Background } from '@/components/Background'
4 | import { Button } from '@/components/Button'
5 | import { TicketIcon } from '@/components/icons'
6 | import { MiduLogo } from '@/components/logos/midudev'
7 | import { Meteors } from '@/components/MeteorLanguages'
8 | import { Modal } from '@/components/Modal'
9 | import { Speakers } from '@/components/Speakers'
10 | import { Stars } from '@/components/Stars'
11 | import { Agenda } from '@/sections/agenda'
12 | import { Gifts } from '@/sections/gifts'
13 | import { Layout } from '@/sections/layout'
14 | import { Sponsors } from '@/sections/sponsors'
15 | import { TicketHome } from '@/sections/ticket-home'
16 | import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
17 | import { useState } from 'react'
18 |
19 | const PREFIX_CDN = 'https://ljizvfycxyxnupniyyxb.supabase.co/storage/v1/object/public/tickets'
20 |
21 | const title = 'miduConf - La conferencia de programación y desarrollo'
22 | const description =
23 | 'Conferencia de programación y tecnología para el día del programador y la programadora'
24 | const defaultOgImage = '/og-image.jpg'
25 | const url = 'https://miduconf.com'
26 |
27 | export default function Home({
28 | username,
29 | flavor,
30 | ticketNumber,
31 | burst,
32 | material,
33 | stickers,
34 | twitchTier,
35 | noUser
36 | }) {
37 | const [showNoUserModal, setShowNoUserModal] = useState(noUser)
38 |
39 | const ogImage = username
40 | ? `${PREFIX_CDN}/ticket-${ticketNumber}.jpg?c=${burst}`
41 | : `${url}${defaultOgImage}`
42 |
43 | const metadata = {
44 | title,
45 | description,
46 | ogImage,
47 | url
48 | }
49 |
50 | return (
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ¡Gracias por disfrutar la miduConf 2024!
60 |
61 |
62 | Volvemos en el año que viene con más y mejores charlas y sorteos.
63 |
64 |
65 | Pero el 1 de marzo de 2025 tenemos nueva conferencia:
66 |
67 |
68 |
69 |
77 |
78 |
79 |
80 |
81 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | setShowNoUserModal(false)}>
97 |
98 |
99 | No hay ningún Ticket asociado a tu cuenta
100 |
101 |
102 | ¡Nos vemos este año para celebrar la MiduConf 2025!
103 |
104 |
105 |
106 | )
107 | }
108 |
109 | export const getServerSideProps = async (ctx) => {
110 | // read query parameter
111 | const { ticket, 'no-user': noUser } = ctx.query
112 |
113 | if (noUser != null) {
114 | return {
115 | props: {
116 | noUser: true
117 | }
118 | }
119 | }
120 |
121 | // create supabase client
122 | const supabase = createPagesServerClient(ctx)
123 | // if no ticket, return empty props
124 | if (!ticket) {
125 | return {
126 | props: {}
127 | }
128 | }
129 |
130 | // search ticket for user
131 | const { data, error } = await supabase.from('ticket').select('*').eq('user_name', ticket)
132 | // check if we have results
133 |
134 | if (data.length > 0 && !error) {
135 | return {
136 | props: {
137 | burst: crypto.randomUUID(),
138 | ticketNumber: data[0].ticket_number,
139 | username: data[0].user_name,
140 | flavor: data[0].flavour,
141 | material: data[0].material,
142 | stickers: data[0].stickers,
143 | twitchTier: data[0].twitch_tier
144 | }
145 | }
146 | }
147 |
148 | return {
149 | props: {}
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/sections/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Header } from '@/components/Header'
2 | import Head from 'next/head'
3 |
4 | interface Props {
5 | children: React.ReactNode
6 | meta: {
7 | title: string
8 | description: string
9 | ogImage: string
10 | url: string
11 | }
12 | }
13 |
14 | export function Layout({ children, meta: { title, description, ogImage, url } }: Props) {
15 | return (
16 | <>
17 |
18 | {title}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {children}
35 | >
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/src/sections/ticket-home.tsx:
--------------------------------------------------------------------------------
1 | import Ticket from '@/components/Ticket'
2 | import TicketSpecial from '@/components/TicketGradient'
3 | import TicketPremium from '@/components/TicketPlatinum'
4 | import { useSupabaseClient } from '@supabase/auth-helpers-react'
5 | import { useEffect, useState } from 'react'
6 | import { FLAVORS } from '@/flavors/data'
7 | import { Button } from '@/components/Button'
8 | import { TicketIcon } from '@/components/icons'
9 | import { Container3D } from '@/components/Container3D'
10 | import { STICKERS_LIST } from '@/pages/ticket'
11 |
12 | export const TicketHome = ({
13 | ticketNumber,
14 | username,
15 | initialFlavor,
16 | material = 'standard',
17 | stickers,
18 | twitchTier
19 | }) => {
20 | const supabase = useSupabaseClient()
21 | const [flavor, setFlavor] = useState(FLAVORS[initialFlavor] ?? FLAVORS.javascript)
22 | const [number, setNumber] = useState(ticketNumber ?? 0)
23 |
24 | const [selectedStickers, _] = useState(() => {
25 | const currentStickers = stickers?.map((sticker) => (sticker === 'null' ? null : sticker))
26 |
27 | const currentList = stickers?.map((sticker) => {
28 | if (sticker === 'null') return null
29 | const stickerComponent = STICKERS_LIST.find(({ name }) => name === sticker)
30 | return stickerComponent?.StickerImage
31 | })
32 |
33 | return {
34 | limit: twitchTier == null ? 0 : Number(twitchTier),
35 | list: currentList,
36 | namesList: currentStickers
37 | }
38 | })
39 |
40 | useEffect(() => {
41 | if (initialFlavor) return
42 |
43 | const keys = Object.keys(FLAVORS)
44 | const length = keys.length
45 |
46 | const intervalId = setInterval(() => {
47 | // get a random key from FLAVORS object
48 | const randomKey = keys[Math.floor(Math.random() * length)]
49 | setFlavor(FLAVORS[randomKey])
50 | }, 2500)
51 |
52 | return () => {
53 | clearInterval(intervalId)
54 | }
55 | }, [])
56 |
57 | useEffect(() => {
58 | if (ticketNumber) return
59 |
60 | fetch('/api/number')
61 | .then((res) => res.json())
62 | .then((response) => {
63 | setNumber(+response.number + 100)
64 | })
65 | }, [])
66 |
67 | const handleLogin = async () => {
68 | const { data, error } = await supabase.auth.signInWithOAuth({
69 | provider: 'github',
70 | options: {
71 | redirectTo:
72 | process.env.NODE_ENV !== 'production'
73 | ? 'http://localhost:3000/api/auth/callback'
74 | : 'https://miduconf.com/api/auth/callback'
75 | }
76 | })
77 | }
78 |
79 | const handleGoToDiscord = () => {
80 | window.open('https://discord.gg/qNqRXh3f?event=1146458434682748939', '_blank')
81 | }
82 |
83 | return (
84 |
85 |
86 |
87 |
88 | {material === 'standard' && (
89 |
99 | )}
100 | {material === 'special' && (
101 |
111 | )}
112 | {material === 'premium' && (
113 |
123 | )}
124 |
125 |
126 |
127 |
134 |
135 |
136 |
137 | )
138 | }
139 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand'
2 |
3 | export const useStore = create((set) => ({
4 | team: null,
5 | selectTeam: (team) => set({ team })
6 | }))
7 |
--------------------------------------------------------------------------------
/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | html {
6 | scroll-behavior: smooth;
7 | }
8 |
9 | body {
10 | background: #000214;
11 | overflow-x: hidden;
12 | }
13 |
14 | @layer components {
15 | .header-animate {
16 | position: fixed;
17 | top: 0;
18 | left: 0;
19 | right: 0;
20 | animation: reduce-header linear both;
21 | animation-timeline: scroll();
22 | animation-range: 0 150px;
23 | }
24 | }
25 |
26 | @layer components {
27 | .ticket-dash-border {
28 | background-image: linear-gradient(hsla(0, 0%, 100%, 0.2) 0%, hsla(0, 0%, 100%, 0.2) 50%, transparent 50%);
29 | background-size: 0.0625rem 1.125rem;
30 | background-position: 100% 0;
31 | background-repeat: repeat-y;
32 | }
33 |
34 | .ticket-dash-border-top {
35 | background-image: linear-gradient(to right, hsla(0, 0%, 100%, 0.2) 0%, hsla(0, 0%, 100%, 0.2) 50%, transparent 50%);
36 | background-size: 1.125rem 0.0625rem;
37 | background-position: 0 0;
38 | background-repeat: repeat-x;
39 | }
40 | }
41 |
42 | @layer components {
43 | .flavors-gradient-list {
44 | mask: linear-gradient(to top, transparent, black 4rem);
45 | -webkit-mask: linear-gradient(to top, transparent, black 4rem);
46 | }
47 | }
48 |
49 | @layer components {
50 | .ticket-gradient-bg {
51 | background: radial-gradient(120% 100% at 90% 10%,
52 | #A3D8FF 0%,
53 | #3640e2 23%,
54 | #6639d9 50%,
55 | #657fd8 74%,
56 | #95bdf4 100%),
57 | radial-gradient(120% 100% at 10% 90%,
58 | #a3d9ff50 0%,
59 | #3640e250 23%,
60 | #6639d950 50%,
61 | #657fd850 74%,
62 | #95bdf450 100%);
63 | background-size: 200% 200%;
64 | background-blend-mode: multiply;
65 | animation: animateGradient 10s infinite alternate linear;
66 | z-index: 1;
67 | }
68 |
69 | .ticket-gradient-bg::after {
70 | content: '';
71 | position: absolute;
72 | width: 100%;
73 | height: 100%;
74 | z-index: 1;
75 | background: linear-gradient(-72deg,
76 | #ffffff 0%,
77 | rgb(0, 0, 0, .0) 16%,
78 | #ffffff 24%,
79 | rgb(0, 0, 0, .0) 33%,
80 | rgb(0, 0, 0, .0) 40%,
81 | #fff8f8 50%,
82 | rgb(0, 0, 0, .0) 61%,
83 | rgb(0, 0, 0, .0) 74%,
84 | #ffffff 83%,
85 | rgb(0, 0, 0, .0) 92%,
86 | #ffffff 100%);
87 | background-size: 200% 100%;
88 | opacity: .4;
89 | animation: animateLightGradient 120s infinite alternate linear;
90 | }
91 |
92 | .ticket-gradient-bg::before {
93 | content: '';
94 | position: absolute;
95 | width: 100%;
96 | height: 100%;
97 | z-index: -1;
98 | background-image: url(/img/tickets-effect/gradient.png);
99 | background-size: 50px 50px;
100 | opacity: 0.7;
101 | }
102 |
103 | @keyframes animateGradient {
104 | 0% {
105 | background-position: 0% 0%;
106 | }
107 |
108 | 25% {
109 | background-position: 50% 50%;
110 | }
111 |
112 | 50% {
113 | background-position: 100% 100%;
114 | }
115 |
116 | 75% {
117 | background-position: 50% 50%;
118 | }
119 |
120 | 100% {
121 | background-position: 0% 0%;
122 | }
123 | }
124 |
125 | @keyframes animateLightGradient {
126 | 0% {
127 | background-position: 0% 0%;
128 | }
129 |
130 | 25% {
131 | background-position: 50% 0%;
132 | }
133 |
134 | 50% {
135 | background-position: 100% 0%;
136 | }
137 |
138 | 75% {
139 | background-position: 50% 0%;
140 | }
141 |
142 | 100% {
143 | background-position: 0% 0%;
144 | }
145 | }
146 | }
147 |
148 | @layer components {
149 | .ticket-premium-bg {
150 | position: relative;
151 | background-image: url(/img/tickets-effect/bg.png);
152 | background-size: cover;
153 | background-position: center;
154 | background-repeat: no-repeat;
155 | z-index: 1;
156 | overflow: hidden;
157 | }
158 |
159 | .ticket-premium-bg::before {
160 | content: '';
161 | position: absolute;
162 | width: 100%;
163 | height: 100%;
164 | inset: 0;
165 | background: linear-gradient(to left bottom, #a172f750 0%, #a172f700 100%),
166 | linear-gradient(to right top, #5bc4f450 0%, #a172f700 0%);
167 | opacity: 0.5;
168 | animation: animateGradientPremium 10s infinite alternate linear;
169 | }
170 |
171 | .ticket-premium-bg::after {
172 | content: '';
173 | position: absolute;
174 | width: 100%;
175 | height: 100%;
176 | inset: 0;
177 | background: url(/img/tickets-effect/noise.png);
178 | background-size: 50px 50px;
179 | opacity: 0.4;
180 | }
181 |
182 | @keyframes animateGradientPremium {
183 | 0% {
184 | opacity: 0.5;
185 | }
186 |
187 | 25% {
188 | opacity: 0.7;
189 | }
190 |
191 | 50% {
192 | opacity: 0.9;
193 | }
194 |
195 | 75% {
196 | opacity: 0.7;
197 | }
198 |
199 | 100% {
200 | opacity: 0.5;
201 | }
202 | }
203 | }
204 |
205 | @layer utilities {
206 | .hidden-scroll::-webkit-scrollbar {
207 | width: 0;
208 | }
209 |
210 | ::-webkit-scrollbar-track {
211 | /* Customize the scrollbar track */
212 | }
213 |
214 | ::-webkit-scrollbar-thumb {
215 | /* Customize the scrollbar thumb */
216 | }
217 | }
218 |
219 | @keyframes reduce-header {
220 | to {
221 | box-shadow: 0 5px 50px -5px hsla(0, 0%, 100%, .1), 0 0 0 1px hsla(0, 0%, 100%, .10);
222 | background: rgba(0, 0, 0, .3);
223 | padding-block: 1rem;
224 | backdrop-filter: blur(10px);
225 | }
226 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './src/pages/**/*.{js,ts,jsx,tsx}',
5 | './src/components/**/*.{js,ts,jsx,tsx}',
6 | './src/sections/**/*.{js,ts,jsx,tsx}',
7 | './src/app/**/*.{js,ts,jsx,tsx}',
8 | './src/flavors/*.{js,ts,jsx,tsx}',
9 | './node_modules/flowbite/**/*.js'
10 | ],
11 | theme: {
12 | extend: {
13 | dropShadow: {
14 | gift: '3px 4px 8px rgba(0, 0, 0, 0.4)'
15 | },
16 | boxShadow: {
17 | button:
18 | 'inset 0 6px 12px #4C64D2, 0 0 17px rgba(110, 137, 255, 0.77), inset 0 1px 10px rgba(255, 255, 255, 0.55)',
19 | ['button-hover']:
20 | ' inset 0 6px 12px #4C64D2, 0 0 34px rgba(110, 137, 255, 0.77), inset 0 1px 10px rgba(255, 255, 255, 0.55)'
21 | },
22 | animation: {
23 | marquee: 'marquee var(--duration) linear infinite',
24 | meteor: 'meteor 5s linear infinite',
25 | 'text-gradient': 'text-gradient 1.5s linear infinite',
26 | spin: 'spin calc(var(--speed) * 2) infinite linear',
27 | slide: 'slide var(--speed) ease-in-out infinite alternate'
28 | },
29 | keyframes: {
30 | marquee: {
31 | from: { transform: 'translateX(0)' },
32 | to: { transform: 'translateX(calc(-50% - var(--gap)/2))' }
33 | },
34 | 'text-gradient': {
35 | to: {
36 | backgroundPosition: '200% center'
37 | }
38 | },
39 | spin: {
40 | '0%': {
41 | rotate: '0deg'
42 | },
43 | '15%, 35%': {
44 | rotate: '90deg'
45 | },
46 | '65%, 85%': {
47 | rotate: '270deg'
48 | },
49 | '100%': {
50 | rotate: '360deg'
51 | }
52 | },
53 | slide: {
54 | to: {
55 | transform: 'translate(calc(100cqw - 100%), 0)'
56 | }
57 | },
58 | meteor: {
59 | '0%': { transform: 'rotate(-40deg) translateX(0)', opacity: 0 },
60 | '30%': { opacity: 1 },
61 | '100%': {
62 | transform: 'rotate(-40deg) translateX(-500px)',
63 | opacity: 0
64 | }
65 | }
66 | },
67 | screens: {
68 | base: '1000px'
69 | },
70 | colors: {
71 | midu: {
72 | primary: '#0099FF',
73 | secondary: '#DEF2FF'
74 | }
75 | },
76 | backgroundImage: {
77 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
78 | 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
79 | button: 'linear-gradient(to bottom, #3152DF95, #1E254595)'
80 | }
81 | }
82 | },
83 | plugins: [
84 | require('flowbite/plugin'),
85 | require('tailwindcss-textshadow'),
86 | require('@midudev/tailwind-animations')
87 | ]
88 | }
89 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "downlevelIteration": true,
4 | "paths": {
5 | "@/*": ["./src/*"]
6 | },
7 | "lib": ["dom", "dom.iterable", "esnext"],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": false,
11 | "forceConsistentCasingInFileNames": true,
12 | "noEmit": true,
13 | "incremental": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "jsx": "preserve"
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------