feat(langs): Add internacionalization functionality

This commit is contained in:
Alexander Navarro 2024-03-16 18:37:12 -03:00
parent eef9ec9457
commit 45fcc13497
27 changed files with 1330 additions and 390 deletions

5
astro-i18next.config.mjs Normal file
View file

@ -0,0 +1,5 @@
/** @type {import('astro-i18next').AstroI18nextConfig} */
export default {
defaultLocale: 'en',
locales: ['en', 'es'],
};

View file

@ -1,10 +1,11 @@
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import react from '@astrojs/react'; import react from '@astrojs/react';
import astroI18next from 'astro-i18next';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
prefetch: true, prefetch: true,
integrations: [react()], integrations: [react(), astroI18next()],
experimental: {}, experimental: {},
}); });

View file

@ -15,6 +15,9 @@
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"astro": "^4.0.6", "astro": "^4.0.6",
"astro-i18next": "1.0.0-beta.21",
"i18next": "^22.5.1",
"i18next-fs-backend": "^2.3.1",
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"sass": "^1.71.1", "sass": "^1.71.1",

369
pnpm-lock.yaml generated
View file

@ -20,6 +20,15 @@ dependencies:
astro: astro:
specifier: ^4.0.6 specifier: ^4.0.6
version: 4.0.6(sass@1.71.1)(typescript@5.2.2) version: 4.0.6(sass@1.71.1)(typescript@5.2.2)
astro-i18next:
specifier: 1.0.0-beta.21
version: 1.0.0-beta.21(astro@4.0.6)
i18next:
specifier: ^22.5.1
version: 22.5.1
i18next-fs-backend:
specifier: ^2.3.1
version: 2.3.1
react: react:
specifier: ^18.0.0 specifier: ^18.0.0
version: 18.2.0 version: 18.2.0
@ -393,6 +402,13 @@ packages:
'@babel/types': 7.23.4 '@babel/types': 7.23.4
dev: false dev: false
/@babel/runtime@7.24.0:
resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.1
dev: false
/@babel/template@7.22.15: /@babel/template@7.22.15:
resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -478,6 +494,15 @@ packages:
dev: false dev: false
optional: true optional: true
/@esbuild/android-arm@0.15.18:
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: false
optional: true
/@esbuild/android-arm@0.19.8: /@esbuild/android-arm@0.19.8:
resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==} resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -559,6 +584,15 @@ packages:
dev: false dev: false
optional: true optional: true
/@esbuild/linux-loong64@0.15.18:
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@esbuild/linux-loong64@0.19.8: /@esbuild/linux-loong64@0.19.8:
resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==} resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -772,6 +806,22 @@ packages:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0 fastq: 1.15.0
/@proload/core@0.3.3:
resolution: {integrity: sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==}
dependencies:
deepmerge: 4.3.1
escalade: 3.1.1
dev: false
/@proload/plugin-tsm@0.2.1(@proload/core@0.3.3):
resolution: {integrity: sha512-Ex1sL2BxU+g8MHdAdq9SZKz+pU34o8Zcl9PHWo2WaG9hrnlZme607PU6gnpoAYsDBpHX327+eu60wWUk+d/b+A==}
peerDependencies:
'@proload/core': ^0.3.2
dependencies:
'@proload/core': 0.3.3
tsm: 2.3.0
dev: false
/@rollup/rollup-android-arm-eabi@4.7.0: /@rollup/rollup-android-arm-eabi@4.7.0:
resolution: {integrity: sha512-rGku10pL1StFlFvXX5pEv88KdGW6DHUghsxyP/aRYb9eH+74jTGJ3U0S/rtlsQ4yYq1Hcc7AMkoJOb1xu29Fxw==} resolution: {integrity: sha512-rGku10pL1StFlFvXX5pEv88KdGW6DHUghsxyP/aRYb9eH+74jTGJ3U0S/rtlsQ4yYq1Hcc7AMkoJOb1xu29Fxw==}
cpu: [arm] cpu: [arm]
@ -1375,6 +1425,26 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/astro-i18next@1.0.0-beta.21(astro@4.0.6):
resolution: {integrity: sha512-1YPqwexumHpK/d9afEoi52CBFTu6k4MYv/oHjsaAasZDvFClU6U5VPttC/OgZcXRYggCM6ee2LOnyHqlmXOeLA==}
hasBin: true
peerDependencies:
astro: '>=1.0.0'
dependencies:
'@proload/core': 0.3.3
'@proload/plugin-tsm': 0.2.1(@proload/core@0.3.3)
astro: 4.0.6(sass@1.71.1)(typescript@5.2.2)
i18next: 22.5.1
i18next-browser-languagedetector: 7.2.0
i18next-fs-backend: 2.3.1
i18next-http-backend: 2.5.0
iso-639-1: 2.1.15
locale-emoji: 0.3.0
pathe: 1.1.2
transitivePeerDependencies:
- encoding
dev: false
/astro@4.0.6(sass@1.71.1)(typescript@5.2.2): /astro@4.0.6(sass@1.71.1)(typescript@5.2.2):
resolution: {integrity: sha512-P7CfFqWKzkJozzF6IoOC6qoI2ONndV8P3ULhGDgMiXPL7xVkWI5haTBSpyrcjBx643tVXspIRsSV/v+Cx+CjGw==} resolution: {integrity: sha512-P7CfFqWKzkJozzF6IoOC6qoI2ONndV8P3ULhGDgMiXPL7xVkWI5haTBSpyrcjBx643tVXspIRsSV/v+Cx+CjGw==}
engines: {node: '>=18.14.1', npm: '>=6.14.0'} engines: {node: '>=18.14.1', npm: '>=6.14.0'}
@ -1843,6 +1913,14 @@ packages:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
dev: true dev: true
/cross-fetch@4.0.0:
resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
dependencies:
node-fetch: 2.7.0
transitivePeerDependencies:
- encoding
dev: false
/cross-spawn@7.0.3: /cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -1973,6 +2051,11 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true dev: true
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dev: false
/define-data-property@1.1.1: /define-data-property@1.1.1:
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -2198,6 +2281,216 @@ packages:
is-symbol: 1.0.4 is-symbol: 1.0.4
dev: true dev: true
/esbuild-android-64@0.15.18:
resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: false
optional: true
/esbuild-android-arm64@0.15.18:
resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: false
optional: true
/esbuild-darwin-64@0.15.18:
resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/esbuild-darwin-arm64@0.15.18:
resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/esbuild-freebsd-64@0.15.18:
resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: false
optional: true
/esbuild-freebsd-arm64@0.15.18:
resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-32@0.15.18:
resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-64@0.15.18:
resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-arm64@0.15.18:
resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-arm@0.15.18:
resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-mips64le@0.15.18:
resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-ppc64le@0.15.18:
resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-riscv64@0.15.18:
resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-s390x@0.15.18:
resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-netbsd-64@0.15.18:
resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: false
optional: true
/esbuild-openbsd-64@0.15.18:
resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: false
optional: true
/esbuild-sunos-64@0.15.18:
resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-32@0.15.18:
resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-64@0.15.18:
resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-arm64@0.15.18:
resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild@0.15.18:
resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.15.18
'@esbuild/linux-loong64': 0.15.18
esbuild-android-64: 0.15.18
esbuild-android-arm64: 0.15.18
esbuild-darwin-64: 0.15.18
esbuild-darwin-arm64: 0.15.18
esbuild-freebsd-64: 0.15.18
esbuild-freebsd-arm64: 0.15.18
esbuild-linux-32: 0.15.18
esbuild-linux-64: 0.15.18
esbuild-linux-arm: 0.15.18
esbuild-linux-arm64: 0.15.18
esbuild-linux-mips64le: 0.15.18
esbuild-linux-ppc64le: 0.15.18
esbuild-linux-riscv64: 0.15.18
esbuild-linux-s390x: 0.15.18
esbuild-netbsd-64: 0.15.18
esbuild-openbsd-64: 0.15.18
esbuild-sunos-64: 0.15.18
esbuild-windows-32: 0.15.18
esbuild-windows-64: 0.15.18
esbuild-windows-arm64: 0.15.18
dev: false
/esbuild@0.19.8: /esbuild@0.19.8:
resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==} resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -3186,6 +3479,30 @@ packages:
engines: {node: '>=16.17.0'} engines: {node: '>=16.17.0'}
dev: false dev: false
/i18next-browser-languagedetector@7.2.0:
resolution: {integrity: sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA==}
dependencies:
'@babel/runtime': 7.24.0
dev: false
/i18next-fs-backend@2.3.1:
resolution: {integrity: sha512-tvfXskmG/9o+TJ5Fxu54sSO5OkY6d+uMn+K6JiUGLJrwxAVfer+8V3nU8jq3ts9Pe5lXJv4b1N7foIjJ8Iy2Gg==}
dev: false
/i18next-http-backend@2.5.0:
resolution: {integrity: sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==}
dependencies:
cross-fetch: 4.0.0
transitivePeerDependencies:
- encoding
dev: false
/i18next@22.5.1:
resolution: {integrity: sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==}
dependencies:
'@babel/runtime': 7.24.0
dev: false
/iconv-lite@0.4.24: /iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -3507,6 +3824,11 @@ packages:
/isexe@2.0.0: /isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/iso-639-1@2.1.15:
resolution: {integrity: sha512-7c7mBznZu2ktfvyT582E2msM+Udc1EjOyhVRE/0ZsjD9LBtWSm23h3PtiRh2a35XoUsTQQjJXaJzuLjXsOdFDg==}
engines: {node: '>=6.0'}
dev: false
/isstream@0.1.2: /isstream@0.1.2:
resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
dev: true dev: true
@ -3679,6 +4001,10 @@ packages:
strip-bom: 3.0.0 strip-bom: 3.0.0
dev: false dev: false
/locale-emoji@0.3.0:
resolution: {integrity: sha512-JGm8+naU49CBDnH1jksS3LecPdfWQLxFgkLN6ZhYONKa850pJ0Xt8DPGJnYK0ZuJI8jTuiDDPCDtSL3nyacXwg==}
dev: false
/locate-path@5.0.0: /locate-path@5.0.0:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -4279,6 +4605,18 @@ packages:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
dev: false dev: false
/node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
dependencies:
whatwg-url: 5.0.0
dev: false
/node-releases@2.0.13: /node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: false dev: false
@ -4528,6 +4866,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
dev: false
/pend@1.2.0: /pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
dev: true dev: true
@ -4776,6 +5118,10 @@ packages:
which-builtin-type: 1.1.3 which-builtin-type: 1.1.3
dev: true dev: true
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: false
/regexp.prototype.flags@1.5.1: /regexp.prototype.flags@1.5.1:
resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -5485,6 +5831,10 @@ packages:
url-parse: 1.5.10 url-parse: 1.5.10
dev: true dev: true
/tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
dev: false
/trim-lines@3.0.1: /trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
dev: false dev: false
@ -5530,6 +5880,14 @@ packages:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true dev: true
/tsm@2.3.0:
resolution: {integrity: sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==}
engines: {node: '>=12'}
hasBin: true
dependencies:
esbuild: 0.15.18
dev: false
/tsutils@3.21.0(typescript@5.2.2): /tsutils@3.21.0(typescript@5.2.2):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -5887,6 +6245,17 @@ packages:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
dev: false dev: false
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
dev: false
/whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
dev: false
/which-boxed-primitive@1.0.2: /which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies: dependencies:

View file

@ -0,0 +1,5 @@
{
"titles": {
"featuredWork": "Featured Work"
}
}

View file

@ -0,0 +1,5 @@
{
"titles": {
"featuredWork": "Trabajo Destacado"
}
}

View file

@ -0,0 +1,16 @@
---
import { LanguageSelector } from 'astro-i18next/components';
---
<LanguageSelector showFlag={false} class="selector" />
<style lang="scss">
.selector {
padding: var(--prj-spacing-1);
border: 1px solid var(--prj-input);
color: var(--prj-input-text);
background-color: var(--prj-input);
font-size: 0.9rem;
border-radius: 4px;
}
</style>

View file

@ -1,13 +1,15 @@
--- ---
import { localizePath } from 'astro-i18next';
import OffCanvas from '@components/OffCanvas/OffCanvas.astro'; import OffCanvas from '@components/OffCanvas/OffCanvas.astro';
import OffCanvasBtn from '@components/OffCanvas/OffCanvasBtn.astro'; import OffCanvasBtn from '@components/OffCanvas/OffCanvasBtn.astro';
import LangSelector from '@components/LangSelector.astro';
const links = [ const links = [
{ href: '/', text: 'Home' }, { href: localizePath('/'), text: 'Home' },
{ href: '/blog', text: 'Blog' }, { href: localizePath('/blog'), text: 'Blog' },
{ href: '/portafolio', text: 'Portafolio' }, { href: localizePath('/portafolio'), text: 'Portafolio' },
{ href: '/curriculum', text: 'Curriculum' }, { href: localizePath('/curriculum'), text: 'Curriculum' },
{ href: '/contact', text: 'Contact' }, { href: localizePath('/contact'), text: 'Contact' },
]; ];
--- ---
@ -23,6 +25,9 @@ const links = [
</li> </li>
)) ))
} }
<li class="nav-item">
<LangSelector />
</li>
</ul> </ul>
</nav> </nav>
@ -70,6 +75,10 @@ const links = [
.navbar-desktop ul { .navbar-desktop ul {
width: fit-content; width: fit-content;
margin-left: auto; margin-left: auto;
.nav-item {
margin-bottom: 0;
}
} }
ul { ul {
@ -82,7 +91,7 @@ const links = [
a { a {
--boder-color: transparent; --boder-color: transparent;
border: 1px solid var(--boder-color); border: 1px solid transparent;
border-radius: 4px; border-radius: 4px;
text-decoration: none; text-decoration: none;

View file

@ -1,5 +1,7 @@
--- ---
import { ViewTransitions } from 'astro:transitions'; import { ViewTransitions } from 'astro:transitions';
import i18next, { t } from 'i18next';
import { HeadHrefLangs } from 'astro-i18next/components';
export interface Props { export interface Props {
title: string; title: string;
} }
@ -12,13 +14,14 @@ const { title } = Astro.props;
--- ---
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang={i18next.language}>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="description" content="Astro description" /> <meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<HeadHrefLangs />
<title>{title}</title> <title>{title}</title>
<ViewTransitions /> <ViewTransitions />

View file

@ -1,5 +1,8 @@
--- ---
import Layout from '../layouts/Layout.astro'; import { changeLanguage } from "i18next";
import Layout from "../layouts/Layout.astro";
changeLanguage("en");
--- ---
<Layout title="Welcome to Astro."> <Layout title="Welcome to Astro.">

View file

@ -1,5 +1,8 @@
--- ---
import Layout from '../layouts/Layout.astro'; import { changeLanguage } from "i18next";
import Layout from "../layouts/Layout.astro";
changeLanguage("en");
--- ---
<Layout title="Blog"> <Layout title="Blog">

View file

@ -1,20 +1,20 @@
--- ---
import type { InferGetStaticPropsType, GetStaticPaths } from 'astro'; import { changeLanguage } from "i18next";
import { getCollection } from 'astro:content'; import type { InferGetStaticPropsType, GetStaticPaths } from "astro";
import Layout from '@layouts/Layout.astro'; import { getCollection } from "astro:content";
import Toc from '@components/Toc/Toc'; import Layout from "@layouts/Layout.astro";
import Toc from "@components/Toc/Toc";
changeLanguage("en");
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const entries = await getCollection('blog'); const entries = await getCollection("blog");
return entries.map((entry) => ({ return entries.map((entry) => ({
params: { slug: entry.slug }, params: { slug: entry.slug },
props: entry, props: entry,
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>; type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props; const entry = Astro.props;
const { Content, headings } = await entry.render(); const { Content, headings } = await entry.render();
--- ---

View file

@ -1,34 +1,35 @@
--- ---
import { getCollection } from 'astro:content'; import { changeLanguage } from "i18next";
import Layout from '@layouts/Layout.astro'; import { getCollection } from "astro:content";
import Table from '@components/Table'; import Layout from "@layouts/Layout.astro";
import { HeaderType, type Header } from '@components/Table/types'; import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
const rawEntries = await getCollection('blog', ({ data }) => { changeLanguage("en");
const rawEntries = await getCollection("blog", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true; return import.meta.env.PROD ? data.draft !== true : true;
}); });
const entries = rawEntries.map((item, idx) => ({ const entries = rawEntries.map((item, idx) => ({
...item.data, ...item.data,
id: idx + 1, id: idx + 1,
slug: item.slug, slug: item.slug,
})); }));
const headers: Header[] = [ const headers: Header[] = [
{ {
key: 'id', key: "id",
header: 'index', header: "index",
type: HeaderType.Index, type: HeaderType.Index,
}, },
{ {
key: 'title', key: "title",
header: 'Title', header: "Title",
formatter: (data) => `<a href="blog/${data.slug}">${data.title}</a>`, formatter: (data) => `<a href="blog/${data.slug}">${data.title}</a>`,
type: HeaderType.String, type: HeaderType.String,
}, },
{ {
key: 'tags', key: "tags",
header: 'Tags', header: "Tags",
type: HeaderType.Multiple, type: HeaderType.Multiple,
}, },
]; ];

10
src/pages/es/404.astro Normal file
View file

@ -0,0 +1,10 @@
---
import { changeLanguage } from "i18next";
import Layout from "../../layouts/Layout.astro";
changeLanguage("es");
---
<Layout title="Welcome to Astro.">
<h1>not found</h1>
</Layout>

10
src/pages/es/blog.astro Normal file
View file

@ -0,0 +1,10 @@
---
import { changeLanguage } from "i18next";
import Layout from "../../layouts/Layout.astro";
changeLanguage("es");
---
<Layout title="Blog">
<h1>Blog</h1>
</Layout>

View file

@ -0,0 +1,26 @@
---
import { changeLanguage } from "i18next";
import type { InferGetStaticPropsType, GetStaticPaths } from "astro";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Toc from "@components/Toc/Toc";
changeLanguage("es");
export const getStaticPaths = (async () => {
const entries = await getCollection("blog");
return entries.map((entry) => ({
params: { slug: entry.slug },
props: entry,
}));
}) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props;
const { Content, headings } = await entry.render();
---
<Layout title={entry.data.title}>
<Toc headings={headings} />
<Content />
</Layout>

View file

@ -0,0 +1,44 @@
---
import { changeLanguage } from "i18next";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
changeLanguage("es");
const rawEntries = await getCollection("blog", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
const entries = rawEntries.map((item, idx) => ({
...item.data,
id: idx + 1,
slug: item.slug,
}));
const headers: Header[] = [
{
key: "id",
header: "index",
type: HeaderType.Index,
},
{
key: "title",
header: "Title",
formatter: (data) => `<a href="blog/${data.slug}">${data.title}</a>`,
type: HeaderType.String,
},
{
key: "tags",
header: "Tags",
type: HeaderType.Multiple,
},
];
---
<Layout title="List of blog entries">
<h1>Blog's entries</h1>
<section>
<Table client:load data={entries} headers={headers} />
</section>
</Layout>

View file

@ -0,0 +1,26 @@
---
import { changeLanguage } from "i18next";
import { InferGetStaticParamsType, InferGetStaticPropsType, GetStaticPaths, } from "astro";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Toc from "@components/Toc/Toc";
changeLanguage("es");
export const getStaticPaths = (async () => {
const games = await getCollection("games");
return games.map((entry) => ({
params: { slug: entry.slug },
props: entry,
}));
}) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props;
const { Content, headings } = await entry.render();
---
<Layout title={entry.data.title}>
<Toc headings={headings} />
<Content />
</Layout>

View file

@ -0,0 +1,61 @@
---
import { changeLanguage } from "i18next";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
changeLanguage("es");
const rawGames = await getCollection("games");
let games = rawGames.map((item, idx) => ({
...item.data,
id: idx + 1,
slug: item.slug,
customCell: item.data.has_content
? `<a href="games/${item.slug}">${item.data.title}</a>`
: `<div>${item.data.title}</div>`,
}));
games = games.sort((a, b) => b.date_added.getTime() - a.date_added.getTime());
const headers: Header[] = [
{
key: "id",
header: "index",
type: HeaderType.Index,
},
{
key: "title",
header: "Title",
type: HeaderType.String,
hasCustomCell: true,
},
{
key: "status",
header: "Status",
type: HeaderType.Select,
},
{
key: "genres",
header: "Genres",
type: HeaderType.Multiple,
},
{
key: "times_played",
header: "Times Played",
type: HeaderType.Number,
},
{
key: "registered_hours",
header: "Registered Hours",
type: HeaderType.Number,
},
];
---
<Layout title="List of games">
<h1>Games</h1>
<section>
<Table client:load data={games} headers={headers} />
</section>
</Layout>

276
src/pages/es/index.astro Normal file
View file

@ -0,0 +1,276 @@
---
import { getCollection } from "astro:content";
import Layout from "../../layouts/Layout.astro";
import Card from "../../components/Card.astro";
import Button from "../../components/Button/Button.astro";
import { Image } from "astro:assets";
import { t, changeLanguage } from "i18next";
import portrait from "../../assets/images/portrait.jpg";
changeLanguage("es");
const blog = await getCollection("blog", ({ data }) => import.meta.env.PROD ? data.draft !== true : true);
// TODO: show the pinned ones, not the recents
const portafolio = await getCollection("portafolio", ({ data }) => import.meta.env.PROD ? data.draft !== true : true);
---
<Layout title="aleidk">
<section
id="hero"
class="bg-image flex-center"
style="--bg-image: url(https://placehold.co/600x400)"
>
<div class="hstack gap-5">
<!-- <Image -->
<!-- id="portrait" -->
<!-- src={portrait} -->
<!-- alt="portrait of Alexander Navarro" -->
<!-- loading="eager" -->
<!-- width={200} -->
<!-- /> -->
<div>
<h1 class="my-0">Alexander Navarro</h1>
<p>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Amet,
repudiandae veritatis totam animi ut facere omnis. Quasi, tempore
porro, neque officia nisi error quia deleniti nesciunt provident vitae
consequuntur quod?
</p>
</div>
</div>
</section>
<section>
<h2 class="text-center">{t('titles.featuredWork')}</h2>Featured Work
</section>
<div class="grid grid-cols-1 grid-lg-cols-3 gap-4">
<Card className="anim-hover-zoom">
<img
src="https://placehold.co/600x400"
alt="project img"
class="border-radius"
/>
<h3 class="fs-4 text-center my-1">Project N°1</h3>
<p class="text-justify">
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint
cillum sint consectetur cupidatat.
</p>
<div class="text-end">
<a href="">See more...</a>
</div>
</Card>
<Card className="anim-hover-zoom">
<img
src="https://placehold.co/600x400"
alt="project img"
class="border-radius"
/>
<h3 class="fs-4 text-center my-1">Project N°1</h3>
<p class="text-justify">
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint
cillum sint consectetur cupidatat.
</p>
<div class="text-end">
<a href="">See more...</a>
</div>
</Card>
<Card className="anim-hover-zoom">
<img
src="https://placehold.co/600x400"
alt="project img"
class="border-radius"
/>
<h3 class="fs-4 text-center my-1">Project N°1</h3>
<p class="text-justify">
Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint
cillum sint consectetur cupidatat.
</p>
<div class="text-end">
<a href="">See more...</a>
</div>
</Card>
</div>
<div class="mt-4 text-center">
<Button className="px-4 py-2 fs-5 ">View Work</Button>
</div>
</Layout>
<section class:list={[{ 'd-none': import.meta.env.PROD }]}>
<h2 class="mb-4">What I've been up to...</h2>
<div class="hstack flex-eq flex-wrap flex-md-nowrap">
<div class="vstack justify-content-center">
<h4 class="text-center">Blog</h4>
<ol class="list-unstyle mt-0 fs-5">
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
</ol>
</div>
<div>
<div class="text-center mb-2">
<img class="" src="https://placehold.co/400x200" alt="project img" />
</div>
<p class="text-justify">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Esse
consequatur iste molestiae blanditiis eligendi consectetur ullam.
Excepturi quasi sed est animi laudantium necessitatibus, tempore
delectus nulla aspernatur quod nesciunt fugiat.
</p>
</div>
</div>
<div class="hstack-reverse flex-eq flex-wrap flex-md-nowrap">
<div class="vstack justify-content-center">
<h4 class="text-center">Games</h4>
<ol class="list-unstyle mt-0 fs-5">
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
<li class="mb-3">
<a href="#"
>Qui minim labore adipisicing minim sint cillum sint consectetur
cupidatat.</a
>
</li>
</ol>
</div>
<div>
<div class="text-center mb-2">
<img class="" src="https://placehold.co/400x200" alt="project img" />
</div>
<p class="text-justify">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Esse
consequatur iste molestiae blanditiis eligendi consectetur ullam.
Excepturi quasi sed est animi laudantium necessitatibus, tempore
delectus nulla aspernatur quod nesciunt fugiat.
</p>
</div>
</div>
</section>
<section class="bg-image" style="--bg-image: url(https://placehold.co/600x400)">
<h2 class="text-center">Who am I?</h2>
<p class="w-95 w-lg-70 mx-auto text-justify">
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet.
Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum
Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident.
Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex
occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat
officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in
Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non
excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut
ea consectetur et est culpa et culpa duis.
</p>
<div class="text-center fs-4 mb-0">
<a href="">
<Button>View full curriculum</Button>
</a>
</div>
</section>
<section>
<h2>Contact</h2>
<div class="grid grid-cols-1 grid-lg-cols-2">
<div>
<div class="text-center">
<img
class="respect-width border-radius"
src="https://placehold.co/500x300"
alt="project img"
/>
</div>
<p class="text-justify">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis
reprehenderit, porro dolorem cumque suscipit accusantium officiis eius
exercitationem harum itaque perferendis praesentium asperiores vitae
pariatur ad culpa mollitia necessitatibus hic!
</p>
</div>
<div class="vstack justify-content-center">
<ul
class="list-unstyle fs-5 ml-lg-5 mt-3 d-flex d-lg-block justify-content-around anim-idle-hover-group anim-group-lg-none"
>
{
[
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Github',
},
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Linkedin',
},
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Email',
},
].map((item) => (
<li class="mb-3">
<a href={item.link} class="hstack flex-column flex-lg-row gap-2">
<>
<img src={item.img} alt={item.alt} />
<span>{item.text}</span>
</>
</a>
</li>
))
}
</ul>
</div>
</div>
</section>
<style>
#portrait {
border-radius: 50%;
border: 5px solid var(--prj-text);
}
#hero {
min-height: 50vh;
}
</style>

View file

@ -0,0 +1,31 @@
---
import { changeLanguage } from "i18next";
import type { InferGetStaticPropsType, GetStaticPaths } from "astro";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Toc from "@components/Toc/Toc";
import Gallery from "@components/MediaGallery/Gallery";
changeLanguage("es");
export const getStaticPaths = (async () => {
const entries = await getCollection("portafolio");
return entries.map((entry) => ({
params: { slug: entry.slug },
props: entry,
}));
}) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props;
const { Content, headings } = await entry.render();
---
<Layout title={entry.data.title}>
<h1>{entry.data.title}</h1>
<Gallery client:load items={entry.data.media} />
<Toc headings={headings} />
<Content />
</Layout>

View file

@ -0,0 +1,44 @@
---
import { changeLanguage } from "i18next";
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
changeLanguage("es");
const rawEntries = await getCollection("portafolio", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
const entries = rawEntries.map((item, idx) => ({
...item.data,
id: idx + 1,
slug: item.slug,
}));
const headers: Header[] = [
{
key: "id",
header: "index",
type: HeaderType.Index,
},
{
key: "title",
header: "Title",
formatter: (data) => `<a href="portafolio/${data.slug}">${data.title}</a>`,
type: HeaderType.String,
},
{
key: "technologies",
header: "Technologies",
type: HeaderType.Multiple,
},
];
---
<Layout title="List of blog entries">
<h1>Blog's entries</h1>
<section>
<Table client:load data={entries} headers={headers} />
</section>
</Layout>

View file

@ -1,24 +1,20 @@
--- ---
import { import { changeLanguage } from "i18next";
InferGetStaticParamsType, import { InferGetStaticParamsType, InferGetStaticPropsType, GetStaticPaths, } from "astro";
InferGetStaticPropsType, import { getCollection } from "astro:content";
GetStaticPaths, import Layout from "@layouts/Layout.astro";
} from 'astro'; import Toc from "@components/Toc/Toc";
import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro'; changeLanguage("en");
import Toc from '@components/Toc/Toc';
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const games = await getCollection('games'); const games = await getCollection("games");
return games.map((entry) => ({ return games.map((entry) => ({
params: { slug: entry.slug }, params: { slug: entry.slug },
props: entry, props: entry,
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>; type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props; const entry = Astro.props;
const { Content, headings } = await entry.render(); const { Content, headings } = await entry.render();
--- ---

View file

@ -1,11 +1,13 @@
--- ---
import { getCollection } from 'astro:content'; import { changeLanguage } from "i18next";
import Layout from '@layouts/Layout.astro'; import { getCollection } from "astro:content";
import Table from '@components/Table'; import Layout from "@layouts/Layout.astro";
import { HeaderType, type Header } from '@components/Table/types'; import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
const rawGames = await getCollection('games'); changeLanguage("en");
const rawGames = await getCollection("games");
let games = rawGames.map((item, idx) => ({ let games = rawGames.map((item, idx) => ({
...item.data, ...item.data,
id: idx + 1, id: idx + 1,
@ -14,39 +16,37 @@ let games = rawGames.map((item, idx) => ({
? `<a href="games/${item.slug}">${item.data.title}</a>` ? `<a href="games/${item.slug}">${item.data.title}</a>`
: `<div>${item.data.title}</div>`, : `<div>${item.data.title}</div>`,
})); }));
games = games.sort((a, b) => b.date_added.getTime() - a.date_added.getTime()); games = games.sort((a, b) => b.date_added.getTime() - a.date_added.getTime());
const headers: Header[] = [ const headers: Header[] = [
{ {
key: 'id', key: "id",
header: 'index', header: "index",
type: HeaderType.Index, type: HeaderType.Index,
}, },
{ {
key: 'title', key: "title",
header: 'Title', header: "Title",
type: HeaderType.String, type: HeaderType.String,
hasCustomCell: true, hasCustomCell: true,
}, },
{ {
key: 'status', key: "status",
header: 'Status', header: "Status",
type: HeaderType.Select, type: HeaderType.Select,
}, },
{ {
key: 'genres', key: "genres",
header: 'Genres', header: "Genres",
type: HeaderType.Multiple, type: HeaderType.Multiple,
}, },
{ {
key: 'times_played', key: "times_played",
header: 'Times Played', header: "Times Played",
type: HeaderType.Number, type: HeaderType.Number,
}, },
{ {
key: 'registered_hours', key: "registered_hours",
header: 'Registered Hours', header: "Registered Hours",
type: HeaderType.Number, type: HeaderType.Number,
}, },
]; ];

View file

@ -1,19 +1,17 @@
--- ---
import { getCollection } from 'astro:content'; import { getCollection } from "astro:content";
import Layout from '../layouts/Layout.astro'; import Layout from "../layouts/Layout.astro";
import Card from '../components/Card.astro'; import Card from "../components/Card.astro";
import Button from '../components/Button/Button.astro'; import Button from "../components/Button/Button.astro";
import { Image } from 'astro:assets'; import { Image } from "astro:assets";
import { t, changeLanguage } from "i18next";
import portrait from "../assets/images/portrait.jpg";
import portrait from '../assets/images/portrait.jpg'; changeLanguage("en");
const blog = await getCollection('blog', ({ data }) => const blog = await getCollection("blog", ({ data }) => import.meta.env.PROD ? data.draft !== true : true);
import.meta.env.PROD ? data.draft !== true : true,
);
// TODO: show the pinned ones, not the recents // TODO: show the pinned ones, not the recents
const portafolio = await getCollection('portafolio', ({ data }) => const portafolio = await getCollection("portafolio", ({ data }) => import.meta.env.PROD ? data.draft !== true : true);
import.meta.env.PROD ? data.draft !== true : true,
);
--- ---
<Layout title="aleidk"> <Layout title="aleidk">
@ -43,7 +41,8 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
</section> </section>
<section> <section>
<h2 class="text-center">Featured Work</h2> <h2 class="text-center">{t('titles.featuredWork')}</h2>Featured Work
</section>
<div class="grid grid-cols-1 grid-lg-cols-3 gap-4"> <div class="grid grid-cols-1 grid-lg-cols-3 gap-4">
<Card className="anim-hover-zoom"> <Card className="anim-hover-zoom">
@ -101,7 +100,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
<div class="mt-4 text-center"> <div class="mt-4 text-center">
<Button className="px-4 py-2 fs-5 ">View Work</Button> <Button className="px-4 py-2 fs-5 ">View Work</Button>
</div> </div>
</section> </Layout>
<section class:list={[{ 'd-none': import.meta.env.PROD }]}> <section class:list={[{ 'd-none': import.meta.env.PROD }]}>
<h2 class="mb-4">What I've been up to...</h2> <h2 class="mb-4">What I've been up to...</h2>
@ -183,10 +182,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
</div> </div>
</section> </section>
<section <section class="bg-image" style="--bg-image: url(https://placehold.co/600x400)">
class="bg-image"
style="--bg-image: url(https://placehold.co/600x400)"
>
<h2 class="text-center">Who am I?</h2> <h2 class="text-center">Who am I?</h2>
<p class="w-95 w-lg-70 mx-auto text-justify"> <p class="w-95 w-lg-70 mx-auto text-justify">
@ -198,8 +194,8 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat
officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in
Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non
excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut
ut ea consectetur et est culpa et culpa duis. ea consectetur et est culpa et culpa duis.
</p> </p>
<div class="text-center fs-4 mb-0"> <div class="text-center fs-4 mb-0">
@ -255,10 +251,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
}, },
].map((item) => ( ].map((item) => (
<li class="mb-3"> <li class="mb-3">
<a <a href={item.link} class="hstack flex-column flex-lg-row gap-2">
href={item.link}
class="hstack flex-column flex-lg-row gap-2"
>
<> <>
<img src={item.img} alt={item.alt} /> <img src={item.img} alt={item.alt} />
<span>{item.text}</span> <span>{item.text}</span>
@ -281,4 +274,3 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
min-height: 50vh; min-height: 50vh;
} }
</style> </style>
</Layout>

View file

@ -1,21 +1,21 @@
--- ---
import type { InferGetStaticPropsType, GetStaticPaths } from 'astro'; import { changeLanguage } from "i18next";
import { getCollection } from 'astro:content'; import type { InferGetStaticPropsType, GetStaticPaths } from "astro";
import Layout from '@layouts/Layout.astro'; import { getCollection } from "astro:content";
import Toc from '@components/Toc/Toc'; import Layout from "@layouts/Layout.astro";
import Gallery from '@components/MediaGallery/Gallery'; import Toc from "@components/Toc/Toc";
import Gallery from "@components/MediaGallery/Gallery";
changeLanguage("en");
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const entries = await getCollection('portafolio'); const entries = await getCollection("portafolio");
return entries.map((entry) => ({ return entries.map((entry) => ({
params: { slug: entry.slug }, params: { slug: entry.slug },
props: entry, props: entry,
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>; type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const entry = Astro.props; const entry = Astro.props;
const { Content, headings } = await entry.render(); const { Content, headings } = await entry.render();
--- ---

View file

@ -1,34 +1,35 @@
--- ---
import { getCollection } from 'astro:content'; import { changeLanguage } from "i18next";
import Layout from '@layouts/Layout.astro'; import { getCollection } from "astro:content";
import Table from '@components/Table'; import Layout from "@layouts/Layout.astro";
import { HeaderType, type Header } from '@components/Table/types'; import Table from "@components/Table";
import { HeaderType, type Header } from "@components/Table/types";
const rawEntries = await getCollection('portafolio', ({ data }) => { changeLanguage("en");
const rawEntries = await getCollection("portafolio", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true; return import.meta.env.PROD ? data.draft !== true : true;
}); });
const entries = rawEntries.map((item, idx) => ({ const entries = rawEntries.map((item, idx) => ({
...item.data, ...item.data,
id: idx + 1, id: idx + 1,
slug: item.slug, slug: item.slug,
})); }));
const headers: Header[] = [ const headers: Header[] = [
{ {
key: 'id', key: "id",
header: 'index', header: "index",
type: HeaderType.Index, type: HeaderType.Index,
}, },
{ {
key: 'title', key: "title",
header: 'Title', header: "Title",
formatter: (data) => `<a href="portafolio/${data.slug}">${data.title}</a>`, formatter: (data) => `<a href="portafolio/${data.slug}">${data.title}</a>`,
type: HeaderType.String, type: HeaderType.String,
}, },
{ {
key: 'technologies', key: "technologies",
header: 'Technologies', header: "Technologies",
type: HeaderType.Multiple, type: HeaderType.Multiple,
}, },
]; ];