feat: v0 of portfolio

This commit is contained in:
Alejandro Laguna
2025-04-06 15:28:54 +02:00
parent 1b5f536457
commit c3b832c9db
22 changed files with 917 additions and 221 deletions

View File

@@ -2,10 +2,10 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon-32x32.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Vite + Preact</title>
<title>Alejandro Laguna</title>
</head>
<body>
<div id="app"></div>

557
package-lock.json generated
View File

@@ -5,8 +5,10 @@
"packages": {
"": {
"dependencies": {
"@tailwindcss/vite": "^4.1.3",
"preact": "^10.25.3",
"preact-iso": "^2.9.1"
"preact-iso": "^2.9.1",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
"@preact/preset-vite": "^2.9.3",
@@ -341,7 +343,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -358,7 +359,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -375,7 +375,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -392,7 +391,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -409,7 +407,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -426,7 +423,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -443,7 +439,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -460,7 +455,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -477,7 +471,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -494,7 +487,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -511,7 +503,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -528,7 +519,6 @@
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -545,7 +535,6 @@
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -562,7 +551,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -579,7 +567,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -596,7 +583,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -613,7 +599,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -630,7 +615,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -647,7 +631,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -664,7 +647,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -681,7 +663,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -698,7 +679,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -715,7 +695,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -732,7 +711,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -749,7 +727,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -934,7 +911,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -948,7 +924,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -962,7 +937,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -976,7 +950,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -990,7 +963,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1004,7 +976,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1018,7 +989,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1032,7 +1002,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1046,7 +1015,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1060,7 +1028,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1074,7 +1041,6 @@
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1088,7 +1054,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1102,7 +1067,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1116,7 +1080,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1130,7 +1093,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1144,7 +1106,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1158,7 +1119,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1172,7 +1132,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1186,7 +1145,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1200,18 +1158,240 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@tailwindcss/node": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.3.tgz",
"integrity": "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA==",
"license": "MIT",
"dependencies": {
"enhanced-resolve": "^5.18.1",
"jiti": "^2.4.2",
"lightningcss": "1.29.2",
"tailwindcss": "4.1.3"
}
},
"node_modules/@tailwindcss/oxide": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.3.tgz",
"integrity": "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ==",
"license": "MIT",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.1.3",
"@tailwindcss/oxide-darwin-arm64": "4.1.3",
"@tailwindcss/oxide-darwin-x64": "4.1.3",
"@tailwindcss/oxide-freebsd-x64": "4.1.3",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3",
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.3",
"@tailwindcss/oxide-linux-arm64-musl": "4.1.3",
"@tailwindcss/oxide-linux-x64-gnu": "4.1.3",
"@tailwindcss/oxide-linux-x64-musl": "4.1.3",
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.3",
"@tailwindcss/oxide-win32-x64-msvc": "4.1.3"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.3.tgz",
"integrity": "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.3.tgz",
"integrity": "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.3.tgz",
"integrity": "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.3.tgz",
"integrity": "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.3.tgz",
"integrity": "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.3.tgz",
"integrity": "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.3.tgz",
"integrity": "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz",
"integrity": "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz",
"integrity": "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.3.tgz",
"integrity": "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.3.tgz",
"integrity": "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/vite": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.3.tgz",
"integrity": "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ==",
"license": "MIT",
"dependencies": {
"@tailwindcss/node": "4.1.3",
"@tailwindcss/oxide": "4.1.3",
"tailwindcss": "4.1.3"
},
"peerDependencies": {
"vite": "^5.2.0 || ^6"
}
},
"node_modules/@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true,
"license": "MIT"
},
"node_modules/array-union": {
@@ -1387,6 +1567,15 @@
}
}
},
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -1473,6 +1662,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/enhanced-resolve": {
"version": "5.18.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -1490,7 +1692,6 @@
"version": "0.25.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz",
"integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -1673,7 +1874,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -1765,7 +1965,6 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC"
},
"node_modules/he": {
@@ -1821,6 +2020,15 @@
"node": ">=0.12.0"
}
},
"node_modules/jiti": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -1874,6 +2082,234 @@
"dev": true,
"license": "MIT"
},
"node_modules/lightningcss": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz",
"integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==",
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-darwin-arm64": "1.29.2",
"lightningcss-darwin-x64": "1.29.2",
"lightningcss-freebsd-x64": "1.29.2",
"lightningcss-linux-arm-gnueabihf": "1.29.2",
"lightningcss-linux-arm64-gnu": "1.29.2",
"lightningcss-linux-arm64-musl": "1.29.2",
"lightningcss-linux-x64-gnu": "1.29.2",
"lightningcss-linux-x64-musl": "1.29.2",
"lightningcss-win32-arm64-msvc": "1.29.2",
"lightningcss-win32-x64-msvc": "1.29.2"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz",
"integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz",
"integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz",
"integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz",
"integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==",
"cpu": [
"arm"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz",
"integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz",
"integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz",
"integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz",
"integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz",
"integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz",
"integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -1958,7 +2394,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
@@ -2067,7 +2502,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -2100,7 +2534,6 @@
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -2191,7 +2624,6 @@
"version": "4.38.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz",
"integrity": "sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.7"
@@ -2295,7 +2727,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -2324,6 +2755,21 @@
"node": ">=0.10.0"
}
},
"node_modules/tailwindcss": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.3.tgz",
"integrity": "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g==",
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2409,7 +2855,6 @@
"version": "6.2.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.4.tgz",
"integrity": "sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",

View File

@@ -10,8 +10,10 @@
"deploy": "gh-pages -d dist"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.3",
"preact": "^10.25.3",
"preact-iso": "^2.9.1"
"preact-iso": "^2.9.1",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
"@preact/preset-vite": "^2.9.3",

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

BIN
public/resume_eng.pdf Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 166 KiB

BIN
src/assets/sketch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

48
src/components/About.tsx Normal file
View File

@@ -0,0 +1,48 @@
import { useEffect, useState } from 'react';
import image from '../assets/sketch.png';
const taglines = [
"Amateur Writer",
"Bookworm",
"Star Gazer",
"Physics Enthusiast",
"Lifelong Learner",
"Tea Enthusiast",
"Cosmic Explorer",
"Knowledge Seeker",
];
export default function About({ theme }) {
const [tagline, setTagline] = useState('');
useEffect(() => {
const randomTagline = taglines[Math.floor(Math.random() * taglines.length)];
setTagline(randomTagline);
}, []);
return (
<section id="about" class="pt-8">
<div class="flex flex-col md:flex-row gap-8 items-center">
<div class="flex-1">
<h1 class={`text-4xl md:text-5xl mb-4 ${theme.accent} font-serif font-semibold`}>Alejandro Laguna</h1>
<h2 class="text-xl md:text-2xl mb-6 text-[#b8c4b5]/80 font-medium font-serif">Software Engineer & {tagline}</h2>
<p class="text-lg mb-6 text-[#b8c4b5]/90">
Crafting digital projects that inspire me, while exploring everything from books and tea to space and science. First-year computer science student.
</p>
<div class="flex gap-4">
<a href="#projects" class={`px-6 py-2 rounded-full border ${theme.border} ${theme.hover} transition-all hover:-translate-y-0.5`}>
View Work
</a>
<a href="mailto:alejandro.laguna@epitech.eu" class={`px-6 py-2 rounded-full ${theme.button} transition-all hover:-translate-y-0.5`}>
Contact
</a>
</div>
</div>
<div class="flex-1 flex justify-center">
<img src={image} alt="Alex Clark's Sketch" class="w-64 h-64 rounded-full object-cover" />
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,36 @@
import EducationCard from './EducationCard';
const education = [
{
institution: "European Institute of Technology (EPITECH)",
degree: "Degree + Master in Computer Science",
duration: "2024 - 2029",
highlights: [
"ONGOING",
"Multiple courses passed with Honors",
"Completed over 30 projects from different fields"
]
},
{
institution: "INS Cendrassos",
degree: "Microcomputer systems & networks",
duration: "2022 - 2024",
highlights: [
"First of the class",
"ERASMUS+ Scholarship",
]
}
];
export default function Education({ theme }) {
return (
<section id="education">
<h2 class={`text-3xl mb-8 font-serif font-semibold ${theme.accent}`}>Education</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
{education.map((edu, i) => (
<EducationCard key={i} education={edu} theme={theme} />
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,18 @@
export default function EducationCard({ education, theme }) {
return (
<div class={`p-4 rounded-xl border ${theme.border} ${theme.card} transition-all hover:-translate-y-1 group`}>
<div class="flex justify-between items-start mb-4">
<div>
<h3 class="text-lg">{education.degree}</h3>
<p class="text-[#b8c4b5]/80">{education.institution}</p>
</div>
<span class="text-sm text-[#b8c4b5]/50">{education.duration}</span>
</div>
<ul class="list-disc pl-6 space-y-2 mb-4">
{education.highlights.map((highlight, j) => (
<li key={j} class="text-[#b8c4b5]/90">{highlight}</li>
))}
</ul>
</div>
);
}

View File

@@ -0,0 +1,39 @@
import ExperienceCard from './ExperienceCard';
const experience = [
{
company: "Avantiam Inc - Figueres, Spain",
role: "Full-Stack Developer",
duration: "Sep 2023 - Sep 2024",
technologies: ["Laravel", "Livewire", "AlpineJS", "TailwindCSS", "MariaDB/MySQL"],
highlights: [
"Developed and maintained a comprehensive business management service used by over 100 companies",
"Managed all aspects of the project lifecycle, including server administration, performance tuning, and user experience improvements.",
"Recommendation letter available upon request."
]
},
{
company: "Niblu Group - Maribor, Slovenia",
role: "Backend Developer Intern",
duration: "Summer 2023",
technologies: ["NextJS", "TailwindCSS", "TypeScript", "FastAPI", "AWS S3 Bucket"],
highlights: [
"Developed a secure authentication system and features for managing courses across different user roles.",
"Integrated AWS S3 for seamless storage and retrieval of course materials.",
"Gained valuable personal and professional growth through the ERASMUS experience, adapting to new challenges abroad alone."
]
}
];
export default function Experience({ theme }) {
return (
<section id="experience">
<h2 class={`text-3xl mb-8 ${theme.accent} font-semibold font-serif`}>Work Experience</h2>
<div class="space-y-8">
{experience.map((exp, i) => (
<ExperienceCard key={i} experience={exp} theme={theme} />
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,36 @@
export default function ExperienceCard({ experience, theme }) {
return (
<div class={`p-6 rounded-xl border ${theme.border} ${theme.card} transition-all hover:-translate-y-1 group`}>
<div class="flex justify-between items-start mb-4">
<div>
<h3 class="text-xl">{experience.company}</h3>
<p class="text-[#b8c4b5]/80">{experience.role}</p>
</div>
<span class="text-sm text-[#b8c4b5]/50">{experience.duration}</span>
</div>
<ul class="list-disc pl-6 space-y-2 mb-4">
{experience.highlights.map((highlight, j) => (
<li key={j} class="text-[#b8c4b5]/90">{highlight}</li>
))}
</ul>
{experience.technologies && (
<div class="flex flex-wrap gap-2 mb-4">
<h4 class="text-lg font-semibold text-[#b8c4b5]/90">Technologies Used:</h4>
{experience.technologies.map((tech, i) => (
<span key={i} class={`px-3 rounded-full ${theme.bg} text-[#b8c4b5]/80`}>{tech}</span>
))}
</div>
)}
{experience.link && (
<a
href={experience.link}
class={`inline-flex items-center text-sm ${theme.accent} ${theme.hover}`}
>
View More
<span class="ml-2 transition-transform group-hover:translate-x-1"></span>
</a>
)}
</div>
);
}

26
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,26 @@
export default function Footer({ theme }) {
const handleDownload = () => {
const link = document.createElement('a');
link.href = '/public/resume_eng.pdf';
link.download = 'alejandrolaguna_resume_eng.pdf';
link.click();
};
return (
<footer class={`pt-8 border-t border-opacity-20 ${theme.border}`}>
<div class="flex flex-col md:flex-row justify-between items-center">
<p class="text-sm text-[#b8c4b5]/50 mb-4 md:mb-0">© 2025 Alejandro Laguna</p>
<div class="flex gap-6">
<a href="https://github.com/alejandrolaguna20" class={`text-sm ${theme.text} ${theme.hover}`}>GitHub</a>
<a href="https://www.linkedin.com/in/alejandro-laguna-939687278/" class={`text-sm ${theme.text} ${theme.hover}`}>LinkedIn</a>
<button
onClick={handleDownload}
class={`text-sm ${theme.text} ${theme.hover} cursor-pointer`}
>
CV
</button>
</div>
</div>
</footer>
);
}

View File

@@ -1,18 +1,22 @@
import { useLocation } from 'preact-iso';
export function Header() {
const { url } = useLocation();
export function Header({ theme }) {
return (
<header>
<nav>
<a href="/" class={url == '/' && 'active'}>
Home
</a>
<a href="/404" class={url == '/404' && 'active'}>
404
<header class="fixed w-full top-0 z-50 backdrop-blur-sm">
<div class="max-w-5xl mx-auto px-4 py-3 flex justify-between items-center">
<h1 class={`text-xl font-bold opacity-50 ${theme.accent} tracking-wider font-serif`}>alejandrolaguna.dev</h1>
<nav class="hidden md:flex gap-6">
{['About', 'Projects', 'Experience'].map((item) => (
<a
href={`#${item.toLowerCase()}`}
class={`text-sm ${theme.text} ${theme.hover} transition-colors`}
>
{item}
</a>
))}
</nav>
</div>
</header>
);
}

10
src/components/Layout.tsx Normal file
View File

@@ -0,0 +1,10 @@
export default function Layout({ children, theme }) {
return (
<div class={`min-h-screen transition-colors duration-300 ${theme.bg} ${theme.text}`}>
<main class="max-w-5xl mx-auto px-4 pt-24 pb-16 space-y-16">
{children}
</main>
</div>
);
}

View File

@@ -0,0 +1,26 @@
export default function ProjectCard({ project, theme }) {
return (
<div class={`p-6 rounded-xl border ${theme.border} ${theme.card} transition-all hover:-translate-y-1 group`}>
<div class="flex justify-between items-start mb-4">
<h3 class="text-xl">{project.title}</h3>
<span class="text-sm text-[#b8c4b5]/50">{project.year}</span>
</div>
<p class="mb-4 text-[#b8c4b5]/80">{project.description}</p>
<div class="flex flex-wrap gap-2 mb-4">
{project.tech.map((tech, j) => (
<span key={j} class={`px-3 py-1 rounded-full ${theme.bg} text-[#b8c4b5]/80`}>{tech}</span>
))}
</div>
{project.link && (
<a
href={project.link}
class={`inline-flex items-center text-sm ${theme.accent} ${theme.hover}`}
>
View Details
<span class="ml-2 transition-transform group-hover:translate-x-1"></span>
</a>
)}
</div>
);
}

View File

@@ -0,0 +1,46 @@
import ProjectCard from './ProjectCard';
const projects = [
{
title: "Codertype",
description: "A monkeytype-like application designed specifically for developers",
tech: ["Laravel", "Livewire", "AlpineJS", "TailwindCSS", "PostgreSQL"],
year: "2025",
link: "https://github.com/alejandrolaguna20/codertype"
},
{
title: "Nook.nvim",
description: "A tiny Neovim plugin created to manage tasks in a way that perfectly fits my personal workflow ",
tech: ["Lua"],
year: "2025",
link: "https://github.com/alejandrolaguna20/nook.nvim"
},
{
title: "Portfolio",
description: "The website you are currently browsing, my little corner on the web.",
tech: ["Typescript", "PreactJS", "TailwindCSS", "Vite"],
year: "2025",
link: "https://github.com/alejandrolaguna20/portfolio"
},
{
title: "Epitech Projects",
description: "A variety of projects I am building in my first year @ Epitech that range from algorithm implementation, graphical and mathematical simulations, and developing from scratch different Linux commands and programs, including a shell.",
tech: ["C", "Bash", "Python"],
year: "2025",
link: "https://www.epitech.eu/programme-grande-ecole-informatique/"
}
];
export default function Projects({ theme }) {
return (
<section id="projects">
<h2 class={`text-3xl font-semibold font-serif mb-8 ${theme.accent}`}>Projects</h2>
<div class="grid gap-6">
{projects.map((project, i) => (
<ProjectCard key={i} project={project} theme={theme} />
))}
</div>
</section>
);
}

View File

@@ -1,19 +1,40 @@
import { render } from 'preact';
import { LocationProvider, Router, Route } from 'preact-iso';
import { Header } from './components/Header.jsx';
import { Home } from './pages/Home/index.jsx';
import { NotFound } from './pages/_404.jsx';
import './style.css';
import { Header } from './components/Header.js';
export function App() {
const theme = {
bg: 'bg-[#1c2529]',
text: 'text-[#f0e4c8]',
accent: 'text-[#c7dd9a]',
accent2: 'text-[#f0b090]',
border: 'border-[#344146]',
card: 'bg-[#263136]',
hover: 'hover:text-[#fff4d8]',
button: 'bg-[#344146] hover:bg-[#49555a] text-[#f0e4c8]',
bg_hl: 'bg-[#344146]',
gradient: 'from-[#1c2529] via-[#263136] to-[#1c2529]'
}
return (
<LocationProvider>
<Header />
<Header
theme={theme}
/>
<main>
<Router>
<Route path="/" component={Home} />
<Route default component={NotFound} />
<Route
path="/"
component={() => (
<Home
theme={theme}
/>
)}
/>
<Route default component={() => (<Home theme={theme} />)} />
</Router>
</main>
</LocationProvider>

View File

@@ -1,39 +1,28 @@
import preactLogo from '../../assets/preact.svg';
import './style.css';
import { useState, useEffect } from 'preact/hooks';
import Layout from '../../components/Layout';
import About from '../../components/About';
import Projects from '../../components/Projects';
import Experience from '../../components/Experience';
import Footer from '../../components/Footer';
import Education from '../../components/Education';
export function Home({ theme }) {
const [scrollPosition, setScrollPosition] = useState(0);
useEffect(() => {
const handleScroll = () => setScrollPosition(window.scrollY);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
export function Home() {
return (
<div class="home">
<a href="https://preactjs.com" target="_blank">
<img src={preactLogo} alt="Preact logo" height="160" width="160" />
</a>
<h1>Get Started building Vite-powered Preact Apps </h1>
<section>
<Resource
title="Learn Preact"
description="If you're new to Preact, try the interactive tutorial to learn important concepts"
href="https://preactjs.com/tutorial"
/>
<Resource
title="Differences to React"
description="If you're coming from React, you may want to check out our docs to see where Preact differs"
href="https://preactjs.com/guide/v10/differences-to-react"
/>
<Resource
title="Learn Vite"
description="To learn more about Vite and how you can customize it to fit your needs, take a look at their excellent documentation"
href="https://vitejs.dev"
/>
</section>
</div>
<Layout theme={theme}>
<About theme={theme} />
<Education theme={theme} />
<Experience theme={theme} />
<Projects theme={theme} />
<Footer theme={theme} />
</Layout>
);
}
function Resource(props) {
return (
<a href={props.href} target="_blank" class="resource">
<h2>{props.title}</h2>
<p>{props.description}</p>
</a>
);
}

View File

@@ -1,47 +0,0 @@
img {
margin-bottom: 1.5rem;
}
img:hover {
filter: drop-shadow(0 0 2em #673ab8aa);
}
.home section {
margin-top: 5rem;
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 1.5rem;
}
.resource {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
text-align: left;
text-decoration: none;
color: #222;
background-color: #f1f1f1;
border: 1px solid transparent;
}
.resource:hover {
border: 1px solid #000;
box-shadow: 0 25px 50px -12px #673ab888;
}
@media (max-width: 639px) {
.home section {
margin-top: 5rem;
grid-template-columns: 1fr;
row-gap: 1rem;
}
}
@media (prefers-color-scheme: dark) {
.resource {
color: #ccc;
background-color: #161616;
}
.resource:hover {
border: 1px solid #bbb;
}
}

View File

@@ -1,70 +1,63 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
@import url('https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&family=Sarala:wght@400;700&display=swap');
@import "tailwindcss";
color: #222;
background-color: #ffffff;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
@theme {
--font-serif: "Aleo", "monospace";
}
body {
margin: 0;
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
#app {
display: flex;
flex-direction: column;
min-height: 100vh;
}
header {
display: flex;
justify-content: flex-end;
background-color: #673ab8;
}
header nav {
display: flex;
}
header a {
color: #fff;
padding: 0.75rem;
text-decoration: none;
}
header a.active {
background-color: #0005;
}
header a:hover {
background-color: #0008;
}
main {
flex: auto;
display: flex;
align-items: center;
max-width: 1280px;
margin: 0 auto;
text-align: center;
}
@media (max-width: 639px) {
main {
margin: 2rem;
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-color-scheme: dark) {
:root {
color: #ccc;
background-color: #1a1a1a;
.transition-all {
transition: all 0.3s ease;
}
.hover\:-translate-y-2:hover {
transform: translateY(-8px);
}
.hover\:-translate-y-1:hover {
transform: translateY(-4px);
}
.backdrop-blur-sm {
backdrop-filter: blur(8px);
}
/* Add to style.css */
.group:hover .group-hover\:translate-x-1 {
transform: translateX(0.25rem);
}
.transition-transform {
transition: transform 0.3s ease;
}
.list-disc li::marker {
color: #b8c4b550;
}
.group:hover .group-hover\:translate-x-1 {
transform: translateX(0.25rem);
}
.transition-transform {
transition: transform 0.3s ease;
}
.list-disc li::marker {
color: #b8c4b550;
}
html {
scroll-behavior: smooth;
}

View File

@@ -1,7 +1,11 @@
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
import tailwindcss from '@tailwindcss/vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [preact()],
plugins: [
tailwindcss(),
preact(),
],
});