Compare commits
1 Commits
main
..
ccc496f7ed
| Author | SHA1 | Date | |
|---|---|---|---|
|
ccc496f7ed
|
@@ -18,7 +18,7 @@
|
|||||||
"@tailwindcss/postcss": "4.3.0",
|
"@tailwindcss/postcss": "4.3.0",
|
||||||
"@tailwindcss/vite": "4.3.0",
|
"@tailwindcss/vite": "4.3.0",
|
||||||
"@types/unist": "3.0.3",
|
"@types/unist": "3.0.3",
|
||||||
"astro": "6.3.6",
|
"astro": "6.3.5",
|
||||||
"astro-compress": "2.4.1",
|
"astro-compress": "2.4.1",
|
||||||
"astro-icon": "1.1.5",
|
"astro-icon": "1.1.5",
|
||||||
"dayjs": "1.11.20",
|
"dayjs": "1.11.20",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"marked-shiki": "1.2.1",
|
"marked-shiki": "1.2.1",
|
||||||
"mdast-util-to-string": "4.0.0",
|
"mdast-util-to-string": "4.0.0",
|
||||||
"photoswipe": "5.4.4",
|
"photoswipe": "5.4.4",
|
||||||
"preline": "4.2.0",
|
"preline": "4.1.3",
|
||||||
"reading-time": "1.5.0",
|
"reading-time": "1.5.0",
|
||||||
"sharp": "0.34.5",
|
"sharp": "0.34.5",
|
||||||
"sharp-ico": "0.1.5",
|
"sharp-ico": "0.1.5",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"@tailwindcss/forms": "0.5.11",
|
"@tailwindcss/forms": "0.5.11",
|
||||||
"@tailwindcss/typography": "0.5.19",
|
"@tailwindcss/typography": "0.5.19",
|
||||||
"@types/markdown-it": "14.1.2",
|
"@types/markdown-it": "14.1.2",
|
||||||
"eslint": "10.4.0",
|
"eslint": "10.3.0",
|
||||||
"eslint-config-prettier": "10.1.8",
|
"eslint-config-prettier": "10.1.8",
|
||||||
"eslint-plugin-astro": "1.7.0",
|
"eslint-plugin-astro": "1.7.0",
|
||||||
"eslint-plugin-format": "2.0.1",
|
"eslint-plugin-format": "2.0.1",
|
||||||
@@ -392,7 +392,7 @@
|
|||||||
|
|
||||||
"@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="],
|
"@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="],
|
||||||
|
|
||||||
"@eslint/config-helpers": ["@eslint/config-helpers@0.6.0", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA=="],
|
"@eslint/config-helpers": ["@eslint/config-helpers@0.5.5", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w=="],
|
||||||
|
|
||||||
"@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="],
|
"@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="],
|
||||||
|
|
||||||
@@ -906,7 +906,7 @@
|
|||||||
|
|
||||||
"arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],
|
"arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],
|
||||||
|
|
||||||
"astro": ["astro@6.3.6", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@astrojs/internal-helpers": "0.9.1", "@astrojs/markdown-remark": "7.1.2", "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", "devalue": "^5.6.3", "diff": "^8.0.3", "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", "rehype": "^13.0.2", "semver": "^7.7.4", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "svgo": "^4.0.1", "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", "unstorage": "^1.17.5", "vfile": "^6.0.3", "vite": "^7.3.2", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", "zod": "^4.3.6" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "./bin/astro.mjs" } }, "sha512-lM30gGI/iASK9Z1WQVnBBYzxVwDv8slkXbJOF7FNJdZQeBrFETpsQvYoLRupM/adt2ObP5hkYAWEeCjofoqlRw=="],
|
"astro": ["astro@6.3.5", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@astrojs/internal-helpers": "0.9.1", "@astrojs/markdown-remark": "7.1.2", "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", "devalue": "^5.6.3", "diff": "^8.0.3", "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", "rehype": "^13.0.2", "semver": "^7.7.4", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "svgo": "^4.0.1", "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", "unstorage": "^1.17.5", "vfile": "^6.0.3", "vite": "^7.3.2", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", "zod": "^4.3.6" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "./bin/astro.mjs" } }, "sha512-gU+4KedkbTuVgz7YoVAN+9Ftnq0GaYwejxK2NbqDzB0M9dWd0f3kXZBuaM9hzbchRFoRAJfJjFtdX9LK6Ir7ZA=="],
|
||||||
|
|
||||||
"astro-compress": ["astro-compress@2.4.1", "", { "dependencies": { "@playform/pipe": "0.1.5", "@types/csso": "5.0.4", "@types/html-minifier-terser": "7.0.2", "astro": "*", "commander": "14.0.3", "csso": "5.0.5", "deepmerge-ts": "7.1.5", "fast-glob": "3.3.3", "html-minifier-terser": "7.2.0", "kleur": "4.1.5", "lightningcss": "1.32.0", "sharp": "0.34.5", "svgo": "4.0.1", "terser": "5.46.1" } }, "sha512-bKPNuajD05ecjiZy/8nqTEOWErFttH/j+adWrvXTARcMieCdI5UdBvvhr+8lrpCXFImiYTwUongj2cDywlSW2Q=="],
|
"astro-compress": ["astro-compress@2.4.1", "", { "dependencies": { "@playform/pipe": "0.1.5", "@types/csso": "5.0.4", "@types/html-minifier-terser": "7.0.2", "astro": "*", "commander": "14.0.3", "csso": "5.0.5", "deepmerge-ts": "7.1.5", "fast-glob": "3.3.3", "html-minifier-terser": "7.2.0", "kleur": "4.1.5", "lightningcss": "1.32.0", "sharp": "0.34.5", "svgo": "4.0.1", "terser": "5.46.1" } }, "sha512-bKPNuajD05ecjiZy/8nqTEOWErFttH/j+adWrvXTARcMieCdI5UdBvvhr+8lrpCXFImiYTwUongj2cDywlSW2Q=="],
|
||||||
|
|
||||||
@@ -1234,7 +1234,7 @@
|
|||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||||
|
|
||||||
"eslint": ["eslint@10.4.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.6.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ=="],
|
"eslint": ["eslint@10.3.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.5.5", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw=="],
|
||||||
|
|
||||||
"eslint-compat-utils": ["eslint-compat-utils@0.6.5", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ=="],
|
"eslint-compat-utils": ["eslint-compat-utils@0.6.5", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ=="],
|
||||||
|
|
||||||
@@ -2074,7 +2074,7 @@
|
|||||||
|
|
||||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||||
|
|
||||||
"preline": ["preline@4.2.0", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@types/culori": "^4.0.1", "apexcharts": "^4.5.0", "culori": "^4.0.2", "datatables.net-dt": "^2.2.2", "dropzone": "^6.0.0-beta.2", "nouislider": "^15.8.1", "vanilla-calendar-pro": "^3.0.4" }, "bin": { "preline-theme-generator": "skills/theme-generator/scripts/generate-theme.js" } }, "sha512-lDdP5VzJDwVdWFDOUHKtkvWGxnsKt1o7Q9Sla19MMX03Lzzp4Pxwxs+TndcFZaNiSchYSDgSnjCsm7olV5JV3g=="],
|
"preline": ["preline@4.1.3", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@types/culori": "^4.0.1", "apexcharts": "^4.5.0", "culori": "^4.0.2", "datatables.net-dt": "^2.2.2", "dropzone": "^6.0.0-beta.2", "nouislider": "^15.8.1", "vanilla-calendar-pro": "^3.0.4" }, "bin": { "preline-theme-generator": "skills/theme-generator/scripts/generate-theme.js" } }, "sha512-M2Rg4J7mZqINfVX0RlWAG1zT+hhUE66PmLoRrq6xIumhID3vONBvbAIYixdTYVsNdv4UWeyr2jatWlJl23q05Q=="],
|
||||||
|
|
||||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -42,7 +42,7 @@
|
|||||||
"@tailwindcss/postcss": "4.3.0",
|
"@tailwindcss/postcss": "4.3.0",
|
||||||
"@tailwindcss/vite": "4.3.0",
|
"@tailwindcss/vite": "4.3.0",
|
||||||
"@types/unist": "3.0.3",
|
"@types/unist": "3.0.3",
|
||||||
"astro": "6.3.6",
|
"astro": "6.3.5",
|
||||||
"astro-compress": "2.4.1",
|
"astro-compress": "2.4.1",
|
||||||
"astro-icon": "1.1.5",
|
"astro-icon": "1.1.5",
|
||||||
"dayjs": "1.11.20",
|
"dayjs": "1.11.20",
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"marked-shiki": "1.2.1",
|
"marked-shiki": "1.2.1",
|
||||||
"mdast-util-to-string": "4.0.0",
|
"mdast-util-to-string": "4.0.0",
|
||||||
"photoswipe": "5.4.4",
|
"photoswipe": "5.4.4",
|
||||||
"preline": "4.2.0",
|
"preline": "4.1.3",
|
||||||
"reading-time": "1.5.0",
|
"reading-time": "1.5.0",
|
||||||
"sharp": "0.34.5",
|
"sharp": "0.34.5",
|
||||||
"sharp-ico": "0.1.5",
|
"sharp-ico": "0.1.5",
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
"@tailwindcss/forms": "0.5.11",
|
"@tailwindcss/forms": "0.5.11",
|
||||||
"@tailwindcss/typography": "0.5.19",
|
"@tailwindcss/typography": "0.5.19",
|
||||||
"@types/markdown-it": "14.1.2",
|
"@types/markdown-it": "14.1.2",
|
||||||
"eslint": "10.4.0",
|
"eslint": "10.3.0",
|
||||||
"eslint-config-prettier": "10.1.8",
|
"eslint-config-prettier": "10.1.8",
|
||||||
"eslint-plugin-astro": "1.7.0",
|
"eslint-plugin-astro": "1.7.0",
|
||||||
"eslint-plugin-format": "2.0.1",
|
"eslint-plugin-format": "2.0.1",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const experiences = ((await directus.request(
|
|||||||
</time>
|
</time>
|
||||||
</header>
|
</header>
|
||||||
<div class="relative flex flex-col sm:col-span-12 pb-6">
|
<div class="relative flex flex-col sm:col-span-12 pb-6">
|
||||||
<div class="absolute bg-accent translate-x-[-1.71rem] rounded-full h-2 w-2 mt-3"/>
|
<div class="absolute bg-accent -translate-x-[1.71rem] rounded-full h-2 w-2 mt-3"/>
|
||||||
<h3>
|
<h3>
|
||||||
<div
|
<div
|
||||||
class="inline-flex items-center text-2xl leading-tight font-semibold"
|
class="inline-flex items-center text-2xl leading-tight font-semibold"
|
||||||
|
|||||||
@@ -18,117 +18,150 @@ const skills = ((await directus.request(
|
|||||||
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
|
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
|
||||||
Skills
|
Skills
|
||||||
</h3>
|
</h3>
|
||||||
<div class="smooth-reveal relative flex flex-col gap-2 mask-[linear-gradient(to_right,transparent,black_10%,black_90%,transparent)] before:pointer-events-none before:absolute before:inset-y-0 before:inset-s-0 before:z-2 before:w-20 after:pointer-events-none after:absolute after:inset-y-0 after:inset-e-0 after:z-2 after:w-20">
|
<div>
|
||||||
<div class="flex">
|
<div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8 mask-[linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]">
|
||||||
<div class="marquee-track-x animate-[marquee-x_120s_linear_infinite] hover:[animation-play-state:paused] flex w-max gap-4 py-10">
|
<!-- Main slider container -->
|
||||||
<div class="flex gap-4">
|
<div class="slider-track animate-slide flex">
|
||||||
{[...skills, ...skills, ...skills].map((skill: Skill) => {
|
{[...skills, ...skills, ...skills].map((skill: Skill) => {
|
||||||
return (
|
return (
|
||||||
<figure class="skill-card card-base transform hover:-translate-y-2 hover:scale-105 transition-all duration-300 mx-2 min-w-55 sm:mx-4 sm:min-w-70">
|
<div class="skill-card card-base transform hover:-translate-y-2 hover:scale-105 transition-all duration-300 mx-2 min-w-55 sm:mx-4 sm:min-w-70">
|
||||||
<div class="p-4 sm:p-6">
|
<div class="p-4 sm:p-6">
|
||||||
<div class="flex items-center justify-between mb-4 sm:mb-6">
|
<div class="flex items-center justify-between mb-4 sm:mb-6">
|
||||||
<div class="flex items-center gap-2 sm:gap-4">
|
<div class="flex items-center gap-2 sm:gap-4">
|
||||||
<div class="flex items-center justify-center rounded-lg text-primary">
|
<div class="flex items-center justify-center rounded-lg text-primary">
|
||||||
<Icon name={skill.icon} class="h-8 w-8 sm:h-12 sm:w-12" />
|
<Icon name={skill.icon} class="h-8 w-8 sm:h-12 sm:w-12" />
|
||||||
</div>
|
|
||||||
<h3 class="text-neutral-900 dark:text-neutral-100 text-base font-semibold sm:text-xl">
|
|
||||||
{skill.title}
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<span class=" bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 font-mono text-xs sm:text-sm rounded-full px-2 sm:px-2.5 py-0.5 sm:py-1">
|
<h3 class="text-neutral-900 dark:text-neutral-100 text-base font-semibold sm:text-xl">
|
||||||
{skill.level}%
|
{skill.title}
|
||||||
</span>
|
</h3>
|
||||||
</div>
|
|
||||||
<div class="relative bg-stone-500/20 dark:bg-stone-500/20 rounded-full h-1.5 sm:h-2 w-full">
|
|
||||||
<div
|
|
||||||
class="progress-bar-animate bg-linear-to-r from-steel via-bermuda to-steel absolute top-0 left-0 h-full rounded-full transition-all duration-1000"
|
|
||||||
style={`width: ${skill.level}%`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-between text-secondary font-mono text-[10px] mt-1 sm:mt-2 sm:text-xs">
|
|
||||||
<span>Beginner</span>
|
|
||||||
<span>Advanced</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span class=" bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 font-mono text-xs sm:text-sm rounded-full px-2 sm:px-2.5 py-0.5 sm:py-1">
|
||||||
|
{skill.level}%
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</figure>
|
<div class="relative bg-stone-500/20 dark:bg-stone-500/20 rounded-full h-1.5 sm:h-2 w-full overflow-hidden">
|
||||||
);
|
<div
|
||||||
})}
|
class="progress-bar-animate bg-linear-to-r from-steel via-bermuda to-steel absolute top-0 left-0 h-full rounded-full transition-all duration-1000"
|
||||||
|
style={`width: ${skill.level}%`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between text-secondary font-mono text-[10px] mt-1 sm:mt-2 sm:text-xs">
|
||||||
|
<span>Beginner</span>
|
||||||
|
<span>Advanced</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function initSkillCards() {
|
document.addEventListener('astro:page-load', () => {
|
||||||
const cards = document.querySelectorAll<HTMLElement>('.skill-card');
|
function setupInfiniteScroll() {
|
||||||
if (!cards.length) return;
|
const cards = document.querySelectorAll('.skill-card');
|
||||||
|
if (!cards.length) return;
|
||||||
|
}
|
||||||
|
|
||||||
cards.forEach((card) => {
|
setupInfiniteScroll();
|
||||||
// Desktop/Mouse events
|
|
||||||
card.addEventListener('mouseenter', () => {
|
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
||||||
card.style.setProperty('transition', 'transform 0.1s ease, box-shadow 0.1s ease', 'important');
|
const cards = document.querySelectorAll('.skill-card');
|
||||||
|
|
||||||
|
if (!isTouchDevice) {
|
||||||
|
cards.forEach((card) => {
|
||||||
|
card.addEventListener('mousemove', (e) => {
|
||||||
|
const rect = card.getBoundingClientRect();
|
||||||
|
const x = e.clientX - rect.left;
|
||||||
|
const y = e.clientY - rect.top;
|
||||||
|
|
||||||
|
const centerX = rect.width / 2;
|
||||||
|
const centerY = rect.height / 2;
|
||||||
|
|
||||||
|
const angleX = (y - centerY) / 15;
|
||||||
|
const angleY = (centerX - x) / 15;
|
||||||
|
|
||||||
|
card.style.transform = `perspective(1000px) rotateX(${angleX}deg) rotateY(${angleY}deg) scale(1.08) translateZ(20px)`;
|
||||||
|
|
||||||
|
// Dynamic shadow based on tilt
|
||||||
|
const shadowX = (x - centerX) / 25;
|
||||||
|
const shadowY = (y - centerY) / 25;
|
||||||
|
card.style.boxShadow = `
|
||||||
|
${shadowX}px ${shadowY}px 20px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 20px rgba(0, 0, 0, 0.05)
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
card.addEventListener('mouseleave', () => {
|
||||||
|
card.style.transform = '';
|
||||||
|
card.style.boxShadow = '';
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Simpler effects for touch devices
|
||||||
|
cards.forEach((card) => {
|
||||||
|
card.addEventListener('touchstart', () => {
|
||||||
|
card.classList.add('is-touched');
|
||||||
|
});
|
||||||
|
|
||||||
card.addEventListener('mousemove', (e: MouseEvent) => {
|
card.addEventListener('touchend', () => {
|
||||||
const rect = card.getBoundingClientRect();
|
setTimeout(() => {
|
||||||
const x = e.clientX - rect.left;
|
card.classList.remove('is-touched');
|
||||||
const y = e.clientY - rect.top;
|
}, 300);
|
||||||
|
});
|
||||||
const centerX = rect.width / 2;
|
|
||||||
const centerY = rect.height / 2;
|
|
||||||
|
|
||||||
const angleX = (y - centerY) / 15;
|
|
||||||
const angleY = (centerX - x) / 15;
|
|
||||||
|
|
||||||
card.style.setProperty('transform', `perspective(1000px) rotateX(${angleX}deg) rotateY(${angleY}deg) scale(1.08) translateZ(20px)`, 'important');
|
|
||||||
|
|
||||||
const shadowX = (x - centerX) / 25;
|
|
||||||
const shadowY = (y - centerY) / 25;
|
|
||||||
card.style.setProperty('box-shadow', `
|
|
||||||
${shadowX}px ${shadowY}px 20px rgba(0, 0, 0, 0.1),
|
|
||||||
0 10px 20px rgba(0, 0, 0, 0.05)
|
|
||||||
`, 'important');
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
card.addEventListener('mouseleave', () => {
|
});
|
||||||
card.style.removeProperty('transform');
|
|
||||||
card.style.removeProperty('box-shadow');
|
|
||||||
card.style.removeProperty('transition');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mobile/Touch events
|
|
||||||
card.addEventListener('touchstart', () => {
|
|
||||||
card.classList.add('is-touched');
|
|
||||||
}, { passive: true });
|
|
||||||
|
|
||||||
card.addEventListener('touchend', () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
card.classList.remove('is-touched');
|
|
||||||
}, 300);
|
|
||||||
}, { passive: true });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run exactly once on initial load, and again if navigating via Astro View Transitions
|
|
||||||
initSkillCards();
|
|
||||||
document.addEventListener('astro:after-swap', initSkillCards);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Skill card effects */
|
/* Specific css to enable sliding effect */
|
||||||
|
.slider-track {
|
||||||
|
width: fit-content;
|
||||||
|
animation: scroll 40s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scroll {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(calc(-220px * 6 - 16px * 6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.slider-track {
|
||||||
|
animation: scroll 80s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scroll {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(calc(-280px * 6 - 32px * 6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-stack-slider:hover .slider-track {
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
|
||||||
.skill-card {
|
.skill-card {
|
||||||
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transform-style: preserve-3d;
|
|
||||||
will-change: transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.skill-card:hover {
|
.skill-card:hover {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reduce animation complexity on mobile */
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.skill-card {
|
.skill-card {
|
||||||
transition:
|
transition:
|
||||||
|
|||||||
@@ -114,33 +114,6 @@
|
|||||||
border-color var(--theme-transition);
|
border-color var(--theme-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preline marquee */
|
|
||||||
@keyframes marquee-x {
|
|
||||||
from {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: translateX(calc(-50% - 0.5rem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes marquee-y {
|
|
||||||
from {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: translateY(calc(-50% - 0.5rem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.marquee-track-x,
|
|
||||||
.marquee-track-y {
|
|
||||||
animation-duration: 1ms;
|
|
||||||
animation-iteration-count: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Typography */
|
/* Typography */
|
||||||
.prose blockquote {
|
.prose blockquote {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
Reference in New Issue
Block a user