Compare commits

..

28 Commits

Author SHA1 Message Date
semantic-release-bot d1816c1b6a chore(release): 3.21.0 [skip ci]
# [3.21.0](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.2...3.21.0) (2026-05-22)

### Bug Fixes

* **deps:** pin dependency @preline/collapse to 4.2.0 ([84e6b14](84e6b146c8))
* **deps:** update astro monorepo ([c92b1f2](c92b1f2801))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.82 ([518777c](518777c5d4))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.83 ([2bf8bee](2bf8bee7a1))
* **deps:** update dependency astro to v6.3.3 ([4ef9e92](4ef9e92d5d))
* **deps:** update dependency astro to v6.3.5 ([81cb4b2](81cb4b21af))
* **deps:** update dependency astro to v6.3.6 ([4ab3bd0](4ab3bd076f))
* **deps:** update dependency astro to v6.3.7 ([9b5317b](9b5317bec7))
* **deps:** update dependency marked to v18.0.4 ([df8a605](df8a60573a))
* **deps:** update dependency shiki to v4.1.0 ([b26605c](b26605cc3b))

### Features

* add compression features ([f279c58](f279c58b28))
* add custom font ([c7493ad](c7493ad09c))
* change collapse to preline ([b7787cb](b7787cb723))
* change font ([b42a697](b42a6974f6))
* change large card hover ([29017b1](29017b1d75))
* change timeline to preline ([3e5aa65](3e5aa65840))
* remove apps page ([34e39ac](34e39aca23))
* replace slider with preline marquee ([901a641](901a641b59))
* update background colors ([f71b28a](f71b28adf0))
* update preline ([d408309](d408309775))
2026-05-22 00:08:52 +00:00
alexlebens 89118578f5 Merge pull request 'chore(deps): update dependency typescript-eslint to v8.59.3' (#472) from main into release
release-image / build (push) Successful in 1m29s
release-image / guarddog (push) Successful in 1m47s
release-image / semantic-release (push) Successful in 47s
release-image / release-harbor (push) Successful in 10m34s
release-image / release-gitea (push) Successful in 6m52s
Reviewed-on: #472
2026-05-22 00:06:28 +00:00
alexlebens f279c58b28 feat: add compression features
test-build / guarddog (push) Successful in 2m16s
test-build / build (push) Successful in 3m5s
2026-05-21 19:02:12 -05:00
alexlebens ec59cad1a5 Merge pull request 'fix(deps): pin dependency @preline/collapse to 4.2.0' (#470) from renovate/pin-dependencies into main
test-build / guarddog (push) Successful in 1m6s
test-build / build (push) Successful in 1m30s
Reviewed-on: #470
2026-05-21 23:47:36 +00:00
renovate-bot 3af4a77674 Merge pull request 'fix(deps): update dependency astro to v6.3.7' (#471) from renovate/astro-monorepo into main
test-build / guarddog (push) Successful in 2m0s
test-build / build (push) Successful in 2m33s
2026-05-21 23:21:33 +00:00
renovate-bot 9b5317bec7 fix(deps): update dependency astro to v6.3.7
renovate/stability-days Updates have not met minimum release age requirement
test-build / guarddog (pull_request) Successful in 2m25s
test-build / build (pull_request) Successful in 2m36s
2026-05-21 23:21:08 +00:00
renovate-bot 84e6b146c8 fix(deps): pin dependency @preline/collapse to 4.2.0
renovate/stability-days Updates have not met minimum release age requirement
test-build / build (pull_request) Successful in 2m37s
test-build / guarddog (pull_request) Successful in 2m44s
2026-05-21 23:20:59 +00:00
alexlebens b42a6974f6 feat: change font
test-build / guarddog (push) Successful in 1m10s
test-build / build (push) Successful in 1m33s
2026-05-21 18:17:00 -05:00
alexlebens 29017b1d75 feat: change large card hover
test-build / build (push) Successful in 1m36s
test-build / guarddog (push) Failing after 12m8s
2026-05-21 18:08:42 -05:00
alexlebens 3e5aa65840 feat: change timeline to preline 2026-05-21 17:53:28 -05:00
alexlebens b7787cb723 feat: change collapse to preline
test-build / build (push) Successful in 2m38s
test-build / guarddog (push) Successful in 1m21s
2026-05-21 16:50:53 -05:00
alexlebens 28ed0f2fa0 Merge pull request 'chore(deps): update docker/build-push-action action to v7.2.0' (#469) from renovate/docker-build-push-action-7.x into main
Reviewed-on: #469
2026-05-21 21:28:26 +00:00
alexlebens c7493ad09c feat: add custom font
test-build / guarddog (push) Successful in 1m14s
test-build / build (push) Successful in 1m56s
2026-05-21 16:22:19 -05:00
alexlebens 34e39aca23 feat: remove apps page 2026-05-21 16:01:33 -05:00
alexlebens f71b28adf0 feat: update background colors
test-build / guarddog (push) Successful in 1m12s
test-build / build (push) Successful in 1m30s
2026-05-21 15:57:34 -05:00
alexlebens 901a641b59 feat: replace slider with preline marquee
test-build / guarddog (push) Successful in 1m12s
test-build / build (push) Successful in 1m28s
2026-05-21 14:57:43 -05:00
renovate-bot 3e25b27c46 chore(deps): update docker/build-push-action action to v7.2.0
test-build / guarddog (pull_request) Successful in 1m32s
test-build / build (pull_request) Successful in 1m41s
2026-05-21 18:01:02 +00:00
alexlebens d408309775 feat: update preline 2026-05-20 20:19:53 -05:00
alexlebens 05c6ec41d4 Merge pull request 'fix(deps): update dependency shiki to v4.1.0' (#467) from renovate/shiki-monorepo into main
test-build / guarddog (push) Successful in 1m7s
test-build / build (push) Successful in 1m15s
Reviewed-on: #467
2026-05-21 01:17:28 +00:00
renovate-bot b26605cc3b fix(deps): update dependency shiki to v4.1.0
renovate/stability-days Updates have met minimum release age requirement
test-build / guarddog (pull_request) Successful in 1m13s
test-build / build (pull_request) Failing after 12m49s
2026-05-21 00:03:03 +00:00
renovate-bot 7f91b3c8e8 Merge pull request 'fix(deps): update dependency astro to v6.3.6' (#468) from renovate/astro-monorepo into main
test-build / guarddog (push) Successful in 2m12s
test-build / build (push) Successful in 3m25s
2026-05-20 18:01:03 +00:00
renovate-bot 4ab3bd076f fix(deps): update dependency astro to v6.3.6
renovate/stability-days Updates have not met minimum release age requirement
test-build / build (pull_request) Successful in 1m16s
test-build / guarddog (pull_request) Successful in 2m10s
2026-05-20 18:00:48 +00:00
semantic-release-bot 217e0447a8 chore(release): 3.20.2 [skip ci]
## [3.20.2](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.1...3.20.2) (2026-05-10)

### Bug Fixes

* **content:** directus published update [skip ci] ([93708da](93708dac75))
2026-05-10 19:46:21 +00:00
gitea-bot 93708dac75 fix(content): directus published update [skip ci] 2026-05-10 19:45:55 +00:00
semantic-release-bot d9d935818c chore(release): 3.20.1 [skip ci]
## [3.20.1](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.0...3.20.1) (2026-05-10)

### Bug Fixes

* **content:** directus published update [skip ci] ([2ad4697](2ad4697825))
2026-05-10 00:44:44 +00:00
gitea-bot 2ad4697825 fix(content): directus published update [skip ci] 2026-05-10 00:44:22 +00:00
semantic-release-bot 5d37b99c80 chore(release): 3.20.0 [skip ci]
# [3.20.0](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.19.4...3.20.0) (2026-05-08)

### Bug Fixes

* **deps:** update astro monorepo ([e1339a5](e1339a53a2))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.81 ([e0b72bf](e0b72bfcbd))
* **deps:** update dependency astro to v6.2.2 ([28724b4](28724b4024))

### Features

* allow processing svg ([20ef569](20ef5697f1))
* merge ([d56ea50](d56ea50663))
* reduce top transparency effect ([6815d5a](6815d5a68b))
2026-05-08 23:30:20 +00:00
alexlebens ec9518a236 Merge pull request 'main' (#454) from main into release
release-image / build (push) Successful in 1m48s
release-image / guarddog (push) Successful in 1m50s
release-image / semantic-release (push) Successful in 43s
release-image / release-harbor (push) Successful in 4m35s
release-image / release-gitea (push) Successful in 7m56s
Reviewed-on: #454
2026-05-08 23:27:56 +00:00
16 changed files with 350 additions and 311 deletions
+2 -2
View File
@@ -213,7 +213,7 @@ jobs:
type=semver,pattern={{major}},value=${{ needs.semantic-release.outputs.new-release-version }}
- name: Build and Push Image
uses: docker/build-push-action@v7.1.0
uses: docker/build-push-action@v7.2.0
with:
context: .
push: true
@@ -317,7 +317,7 @@ jobs:
type=semver,pattern={{major}},value=${{ needs.semantic-release.outputs.new-release-version }}
- name: Build and Push Image
uses: docker/build-push-action@v7.1.0
uses: docker/build-push-action@v7.2.0
with:
context: .
push: true
+60
View File
@@ -1,3 +1,63 @@
# [3.21.0](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.2...3.21.0) (2026-05-22)
### Bug Fixes
* **deps:** pin dependency @preline/collapse to 4.2.0 ([84e6b14](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/84e6b146c89f7b7a94f64ef5e14d431f850eb2e9))
* **deps:** update astro monorepo ([c92b1f2](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/c92b1f2801e85c5782db29e9a75eb78df1a70a41))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.82 ([518777c](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/518777c5d4dcdde7690acea136ca23856db8ff1f))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.83 ([2bf8bee](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/2bf8bee7a1d20e857cd95bcb1a61c5742cbe13b3))
* **deps:** update dependency astro to v6.3.3 ([4ef9e92](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/4ef9e92d5d84c9d69bf9e979435b85727fc622f1))
* **deps:** update dependency astro to v6.3.5 ([81cb4b2](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/81cb4b21aff6c9cc73dfba0a4f62ad75faa0d68e))
* **deps:** update dependency astro to v6.3.6 ([4ab3bd0](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/4ab3bd076fb06493a1a6b949dd745e6ef59e1fcd))
* **deps:** update dependency astro to v6.3.7 ([9b5317b](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/9b5317bec7dbd7f1092d18b8d70aed631942086b))
* **deps:** update dependency marked to v18.0.4 ([df8a605](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/df8a60573a70b73e60115cdf10c6c36518ae7bbe))
* **deps:** update dependency shiki to v4.1.0 ([b26605c](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/b26605cc3be80d50881d9041dfb20be7ca1f3c8a))
### Features
* add compression features ([f279c58](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/f279c58b282fc1d24f6411548fbba1831e939a96))
* add custom font ([c7493ad](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/c7493ad09c5544090bd92c5fc219101a1f5f0b83))
* change collapse to preline ([b7787cb](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/b7787cb723b6a4dce0ef45e40d84be5869f1e6af))
* change font ([b42a697](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/b42a6974f62cb3aeb3e340d2daef2d621323a158))
* change large card hover ([29017b1](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/29017b1d75801f2142fee281b0ff7e164c4d134a))
* change timeline to preline ([3e5aa65](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/3e5aa658407290a65688e708509be9a724949646))
* remove apps page ([34e39ac](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/34e39aca23070f12cdd00a6774234e590f293156))
* replace slider with preline marquee ([901a641](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/901a641b59689e1a7a4278672b9a23386e8bdace))
* update background colors ([f71b28a](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/f71b28adf06779532b6303568a2b6e3b5020257a))
* update preline ([d408309](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/d408309775015ff30d1a0ddc7a5e095104e6c8bd))
## [3.20.2](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.1...3.20.2) (2026-05-10)
### Bug Fixes
* **content:** directus published update [skip ci] ([93708da](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/93708dac752e7fc001fc35d86145896fcfe474d1))
## [3.20.1](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.20.0...3.20.1) (2026-05-10)
### Bug Fixes
* **content:** directus published update [skip ci] ([2ad4697](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/2ad4697825060ecfabf515c45dc8d1acdc07c824))
# [3.20.0](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.19.4...3.20.0) (2026-05-08)
### Bug Fixes
* **deps:** update astro monorepo ([e1339a5](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/e1339a53a2b4c7392991db2179aaf63be1e0e38b))
* **deps:** update dependency @iconify-json/simple-icons to v1.2.81 ([e0b72bf](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/e0b72bfcbd89d195669666e01876b2ed50eafb5b))
* **deps:** update dependency astro to v6.2.2 ([28724b4](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/28724b40242d852f42298d0656a5da6e73a1884d))
### Features
* allow processing svg ([20ef569](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/20ef5697f15ff3d045dcd615eddc9887620ed9ea))
* merge ([d56ea50](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/d56ea50663f7fa3a4160ccbc34ac61ecc9838f03))
* reduce top transparency effect ([6815d5a](https://gitea.alexlebens.dev/alexlebens/site-profile/commit/6815d5a68b4f44b1cfc920c32cf14b4e53b5c44f))
## [3.19.4](https://gitea.alexlebens.dev/alexlebens/site-profile/compare/3.19.3...3.19.4) (2026-05-08)
+13 -5
View File
@@ -1,4 +1,4 @@
import { defineConfig } from 'astro/config';
import { defineConfig, fontProviders } from 'astro/config';
import node from '@astrojs/node';
import sitemap from '@astrojs/sitemap';
@@ -13,7 +13,7 @@ export default defineConfig({
site: getSiteURL(),
image: {
dangerouslyProcessSVG: true,
dangerouslyProcessSVG: true,
remotePatterns: [
{ protocol: 'https', hostname: '*.alexlebens.net' },
{ protocol: 'https', hostname: '*.jsdelivr.net' },
@@ -24,6 +24,8 @@ export default defineConfig({
}
},
prefetch: true,
integrations: [
sitemap(),
icon({
@@ -42,12 +44,12 @@ export default defineConfig({
}),
(await import('@playform/compress')).default({
CSS: true,
JavaScript: false,
JavaScript: true,
HTML: {
'html-minifier-terser': {
collapseWhitespace: true,
minifyCSS: false,
minifyJS: false,
minifyCSS: true,
minifyJS: true,
},
},
Image: false,
@@ -55,6 +57,12 @@ export default defineConfig({
}),
],
fonts: [{
provider: fontProviders.fontsource(),
name: "Fredoka",
cssVariable: "--font-base",
}],
markdown: {
syntaxHighlight: false,
},
+7 -20
View File
@@ -14,11 +14,12 @@
"@iconify-json/pajamas": "1.2.15",
"@iconify-json/simple-icons": "1.2.83",
"@playform/compress": "0.2.3",
"@preline/collapse": "4.2.0",
"@swup/astro": "1.8.0",
"@tailwindcss/postcss": "4.3.0",
"@tailwindcss/vite": "4.3.0",
"@types/unist": "3.0.3",
"astro": "6.3.5",
"astro": "6.3.7",
"astro-compress": "2.4.1",
"astro-icon": "1.1.5",
"dayjs": "1.11.20",
@@ -27,7 +28,7 @@
"marked-shiki": "1.2.1",
"mdast-util-to-string": "4.0.0",
"photoswipe": "5.4.4",
"preline": "4.1.3",
"preline": "4.2.0",
"reading-time": "1.5.0",
"sharp": "0.34.5",
"sharp-ico": "0.1.5",
@@ -574,6 +575,8 @@
"@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA=="],
"@preline/collapse": ["@preline/collapse@4.2.0", "", {}, "sha512-ge7sUQiHRGb7DOyl8q6KnybJDVL7R/kv9ah8svgmDslpmGYK7LIGR/H68mZyWbhh75mRTeoxhlnXGZEii/3Y0A=="],
"@rollup/plugin-alias": ["@rollup/plugin-alias@3.1.9", "", { "dependencies": { "slash": "^3.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw=="],
"@rollup/plugin-babel": ["@rollup/plugin-babel@5.3.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0" }, "optionalPeers": ["@types/babel__core"] }, "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q=="],
@@ -906,7 +909,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=="],
"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": ["astro@6.3.7", "", { "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-zIeDRrI0qNgN1lcCjNqt6/IVCVej7VwSa326cO8uP9BOk1cg4QuffhLnOn2gCgWQr32/wxpSRFfXiLKHglu1Tw=="],
"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=="],
@@ -2074,7 +2077,7 @@
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
"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=="],
"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=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
@@ -2750,8 +2753,6 @@
"astro/@astrojs/compiler": ["@astrojs/compiler@4.0.0", "", {}, "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA=="],
"astro/shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
"astro-compress/astro": ["astro@6.3.1", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@astrojs/internal-helpers": "0.9.0", "@astrojs/markdown-remark": "7.1.1", "@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-atz6dmkE3Gu24bDgb7g2RE/BYnKqPYIHd6hTUM1UXvu/i7qNZOKLAqEHvgYpv9PQVcgWsXpk4/OOXZ0E/FzvSQ=="],
"astro-eslint-parser/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
@@ -3346,18 +3347,6 @@
"astro-compress/astro/shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
"astro/shiki/@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="],
"astro/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="],
"astro/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="],
"astro/shiki/@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
"astro/shiki/@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
"astro/shiki/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
"babel-plugin-macros/cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
"babel-plugin-macros/cosmiconfig/yaml": ["yaml@1.10.3", "", {}, "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA=="],
@@ -3548,8 +3537,6 @@
"astro-compress/astro/shiki/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
"astro/shiki/@shikijs/core/@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="],
"cli-highlight/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"cli-highlight/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+4 -3
View File
@@ -1,7 +1,7 @@
{
"name": "site-profile",
"type": "module",
"version": "3.19.4",
"version": "3.21.0",
"homepage": "https://www.alexlebens.dev",
"bugs": {
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
@@ -38,11 +38,12 @@
"@iconify-json/pajamas": "1.2.15",
"@iconify-json/simple-icons": "1.2.83",
"@playform/compress": "0.2.3",
"@preline/collapse": "4.2.0",
"@swup/astro": "1.8.0",
"@tailwindcss/postcss": "4.3.0",
"@tailwindcss/vite": "4.3.0",
"@types/unist": "3.0.3",
"astro": "6.3.5",
"astro": "6.3.7",
"astro-compress": "2.4.1",
"astro-icon": "1.1.5",
"dayjs": "1.11.20",
@@ -51,7 +52,7 @@
"marked-shiki": "1.2.1",
"mdast-util-to-string": "4.0.0",
"photoswipe": "5.4.4",
"preline": "4.1.3",
"preline": "4.2.0",
"reading-time": "1.5.0",
"sharp": "0.34.5",
"sharp-ico": "0.1.5",
+1 -1
View File
@@ -30,7 +30,7 @@ const { post } = Astro.props;
inferSize={true}
/>
</div>
<div class="flex flex-col justify-center bg-background-card md:bg-transparent group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-neutral-800/90 md:dark:group-hover:bg-transparent rounded-b-2xl transition-all duration-300 p-6 gap-4">
<div class="card-base-hidden-md flex flex-col justify-center p-6 gap-4">
<h2 class="card-text-header">
{post.title}
</h2>
@@ -20,7 +20,7 @@ const { post } = Astro.props;
href={`/blog/${post.slug}`}
data-astro-prefetch
>
<div class="flex flex-col bg-background-card md:bg-transparent group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-neutral-800/90 md:dark:group-hover:bg-transparent rounded-b-2xl transition-all duration-300 p-6 gap-4">
<div class="card-base-hidden-md flex flex-col p-6 gap-4">
<h2 class="card-text-header">
{post.title}
</h2>
+111 -98
View File
@@ -18,15 +18,15 @@ const experiences = ((await directus.request(
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-10">
Experience
</h3>
<ul class="flex flex-col w-full ml-8 pr-8">
{experiences.map((experience: Experience) => {
<ul class="flex flex-col w-full gap-8">
{experiences.map((experience: Experience, index: number) => {
const startYear = new Date(experience.startDate).getFullYear();
const endYear = experience.endDate != null ? new Date(experience.endDate).getFullYear() : 'Present';
return (
<li class="relative">
<div class="smooth-reveal group relative grid sm:grid-cols-18 sm:gap-8 md:gap-6 pb-16">
<header class="relative sm:col-span-3 text-header font-semibold text-lg mt-1">
<li class="smooth-reveal card-base-hidden flex gap-x-4 -mx-4 md:-mx-8 px-4 md:px-8 py-4 md:py-6">
<div class="w-28 md:w-32 text-end pt-1 shrink-0">
<header class="text-sm md:text-base font-semibold text-header">
<time datetime={experience.startDate} data-title={experience.startDate}>
{startYear}
</time>
@@ -35,115 +35,130 @@ const experiences = ((await directus.request(
{endYear}
</time>
</header>
<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"/>
<h3>
<div
class="inline-flex items-center text-2xl leading-tight font-semibold"
aria-label="{position} - {company}"
>
<span class="text-header">
{experience.position} <span>@</span>
{experience.url ? (
<a
class="hover:text-main"
href={experience.url}
title={`Ver ${experience.name}`}
target="_blank"
>
{experience.name}
</a>
) : (
<span>{experience.name}</span>
)}
</span>
</div>
</h3>
{(experience.location || experience.location_type) && (
<div class="text-secondary text-sm">
{experience.location} {experience.location && experience.location_type && '-'} {experience.location_type}
</div>
<div class="relative last:after:hidden after:absolute after:top-6 after:-bottom-2 md:after:-bottom-4 after:inset-s-3.5 after:w-px after:translate-x-[-0.5px] after:bg-divider">
<div class="relative z-10 size-7 flex justify-center items-center">
<div class="size-2 rounded-full bg-accent"></div>
</div>
</div>
<div class="grow pt-0.5">
<h3>
<div
class="inline-flex items-center text-2xl leading-tight font-semibold"
aria-label="{position} - {company}"
>
<span class="text-header">
{experience.position} <span>@</span>
{experience.url ? (
<a
class="hover:text-main"
href={experience.url}
title={`Ver ${experience.name}`}
target="_blank"
>
{experience.name}
</a>
) : (
<span>{experience.name}</span>
)}
</span>
</div>
)}
<div class="text-md mt-4 flex flex-col gap-4" x-data="{ expanded: false }">
{experience.summary && (
</h3>
{(experience.location || experience.location_type) && (
<div class="text-secondary text-sm">
{experience.location} {experience.location && experience.location_type && '-'} {experience.location_type}
</div>
)}
<div class="text-md mt-4 flex flex-col">
{experience.summary && (
<div class="flex flex-col gap-1 mb-4">
<h4 class="text-header font-semibold">
Summary:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
<li class="marker:text-main">
{experience.summary}
</li>
</ul>
</div>
)}
{(experience.responsibilities || experience.achievements) && (
<>
<div id={`hs-show-hide-collapse-heading-${index}`} class="hs-collapse hidden w-full overflow-hidden transition-[height] duration-500">
<div class="relative flex flex-col gap-4 pb-4">
{experience.responsibilities && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Summary:
Responsibilities:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.responsibilities.map(responsibility => (
<li class="marker:text-main">
{experience.summary}
{responsibility}
</li>
))}
</ul>
</div>
)}
{(experience.responsibilities || experience.achievements) && (
<div class="relative flex flex-col gap-4" :class="expanded ? '' : 'mask-[linear-gradient(to_bottom,black_50%,transparent)]'" x-show="expanded" x-collapse.min.50px>
{experience.responsibilities && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Responsibilities:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.responsibilities.map(responsibility => (
<li class="marker:text-main">
{responsibility}
</li>
))}
</ul>
</div>
)}
{experience.achievements && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Achievements:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.achievements.map(achievement => (
<li class="marker:text-main">
{achievement}
</li>
))}
</ul>
</div>
)}
{experience.achievements && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Achievements:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.achievements.map(achievement => (
<li class="marker:text-main">
{achievement}
</li>
))}
</ul>
</div>
<button @click="expanded = ! expanded" class="group/more flex items-center justify-center text-primary hover:text-primary-hover text-xs underline transition-all gap-1.5 w-fit cursor-pointer">
<span x-text="expanded ? 'Show less' : 'Show more'">
Show more
</span>
)}
</div>
</div>
<p class="mb-4">
<button
type="button"
class="hs-collapse-toggle inline-flex items-center gap-x-1 text-sm rounded-lg text-primary hover:text-primary-hover disabled:opacity-50 disabled:pointer-events-none"
id={`hs-show-hide-collapse-${index}`}
aria-expanded="false"
aria-controls={`hs-show-hide-collapse-heading-${index}`}
data-hs-collapse={`#hs-show-hide-collapse-heading-${index}`}
>
<span class="hs-collapse-open:hidden">Read more</span>
<span class="hs-collapse-open:block hidden">Read less</span>
<svg
class="group-hover/more:translate-y-0.5 ease-out duration-300 h-4 w-4"
:class="{ 'rotate-180': expanded }"
viewBox="0 0 24 24"
class="hs-collapse-open:rotate-180 shrink-0 size-4"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9" />
<path d="m6 9 6 6 6-6"/>
</svg>
</button>
<ul
class="flex print:hidden flex-wrap gap-2 mt-2"
aria-label="Technologies used"
>
{experience.skills && experience.skills.map(skill => {
const iconName = skill.toLowerCase();
const skillName = skill.split(':')[1].replace(/^language-/, '').replace(/-/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
return (
<li class="flex items-center bg-steel/20 dark:bg-bermuda/20 text-neutral-800 dark:text-neutral-200 text-xs rounded-md border border-solid border-steel/20 dark:border-bermuda/20 gap-1 px-2 py-0.5">
<Icon name={`${iconName}`} class="h-4 w-4" /> <span>{skillName}</span>
</li>
)
})}
</ul>
)}
</div>
</p>
</>
)}
<ul
class="flex print:hidden flex-wrap gap-2"
aria-label="Technologies used"
>
{experience.skills && experience.skills.map(skill => {
const iconName = skill.toLowerCase();
const skillName = skill.split(':')[1].replace(/^language-/, '').replace(/-/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
return (
<li class="flex items-center bg-steel/20 dark:bg-bermuda/20 text-neutral-800 dark:text-neutral-200 text-xs rounded-md border border-solid border-steel/20 dark:border-bermuda/20 gap-1 px-2 py-0.5">
<Icon name={`${iconName}`} class="h-4 w-4" /> <span>{skillName}</span>
</li>
)
})}
</ul>
</div>
</div>
</li>
@@ -152,8 +167,6 @@ const experiences = ((await directus.request(
</ul>
</section>
<!-- Alpine Plugins -->
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
import "@preline/collapse/index.js";
</script>
+84 -117
View File
@@ -18,150 +18,117 @@ const skills = ((await directus.request(
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
Skills
</h3>
<div>
<div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8 mask-[linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]">
<!-- Main slider container -->
<div class="slider-track animate-slide flex">
{[...skills, ...skills, ...skills].map((skill: Skill) => {
return (
<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="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 justify-center rounded-lg text-primary">
<Icon name={skill.icon} class="h-8 w-8 sm:h-12 sm:w-12" />
<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 class="flex">
<div class="marquee-track-x animate-[marquee-x_120s_linear_infinite] hover:[animation-play-state:paused] flex w-max gap-4 py-10">
<div class="flex gap-4">
{[...skills, ...skills, ...skills].map((skill: Skill) => {
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="p-4 sm:p-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 justify-center rounded-lg text-primary">
<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>
<h3 class="text-neutral-900 dark:text-neutral-100 text-base font-semibold sm:text-xl">
{skill.title}
</h3>
<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 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>
<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 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>
</figure>
);
})}
</div>
);
})}
</div>
</div>
</div>
</section>
<script>
document.addEventListener('astro:page-load', () => {
function setupInfiniteScroll() {
const cards = document.querySelectorAll('.skill-card');
if (!cards.length) return;
}
function initSkillCards() {
const cards = document.querySelectorAll<HTMLElement>('.skill-card');
if (!cards.length) return;
setupInfiniteScroll();
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
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 = '';
});
cards.forEach((card) => {
// Desktop/Mouse events
card.addEventListener('mouseenter', () => {
card.style.setProperty('transition', 'transform 0.1s ease, box-shadow 0.1s ease', 'important');
});
} else {
// Simpler effects for touch devices
cards.forEach((card) => {
card.addEventListener('touchstart', () => {
card.classList.add('is-touched');
});
card.addEventListener('touchend', () => {
setTimeout(() => {
card.classList.remove('is-touched');
}, 300);
});
card.addEventListener('mousemove', (e: MouseEvent) => {
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.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>
<style>
/* 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 effects */
.skill-card {
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
overflow: hidden;
transform-style: preserve-3d;
will-change: transform;
}
.skill-card:hover {
z-index: 10;
}
/* Reduce animation complexity on mobile */
@media (max-width: 640px) {
.skill-card {
transition:
-1
View File
@@ -13,7 +13,6 @@ export const NavigationLinks: NavigationLink[] = [
{ name: 'Home', url: '/' },
{ name: 'Blog', url: '/blog/' },
{ name: 'Categories', url: '/categories/' },
{ name: 'Apps', url: '/apps/' },
{ name: 'About Me', url: '/about/' },
];
+5 -10
View File
@@ -1,4 +1,6 @@
---
import { Font } from "astro:assets";
import { readSingleton } from '@directus/sdk';
import BaseHead from '@components/BaseHead.astro';
@@ -38,6 +40,8 @@ const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
structuredData={structuredData}
/>
<Font cssVariable="--font-base" />
<!-- Set Theme -->
<script is:inline>
const theme = (() => {
@@ -171,7 +175,7 @@ const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
.bg {
animation: slide 25s ease-in-out infinite alternate;
will-change: transform;
background-image: linear-gradient(-55deg, var(--bg-primary) 33.3%, var(--bg-secondary) 33.3%, var(--bg-secondary) 66.6%, var(--bg-tertiary) 66.6%);
background-image: linear-gradient(-55deg, var(--color-background-1) 33.3%, var(--color-background-2) 33.3%, var(--color-background-2) 66.6%, var(--color-background-3) 66.6%);
filter: blur(40px);
top: 0;
bottom: 0;
@@ -180,15 +184,6 @@ const normalizeTitle = !title ? global.name : `${title} | ${global.name}`;
opacity: .5;
position: fixed;
z-index: -1;
--bg-primary: #e5e5e5;
--bg-secondary: #dce3eb;
--bg-tertiary: #f4f6f8;
}
:global(.dark) .bg {
--bg-primary: #3b3836;
--bg-secondary: #332f2e;
--bg-tertiary: #44403c;
}
.bg2 {
-39
View File
@@ -1,39 +0,0 @@
---
import { readSingleton } from '@directus/sdk';
import HeroSection from '@components/sections/HeroSection.astro';
import ApplicationSection from '@components/sections/ApplicationSection.astro';
import BaseLayout from '@layouts/BaseLayout.astro';
import directus from '@lib/directus';
const global = await directus.request(readSingleton('site_global'));
---
<BaseLayout
title="Applications"
description={global.about_applications}
structuredData={{
'@context': 'https://schema.org',
'@type': 'WebPage',
inLanguage: 'en-US',
'@id': Astro.url.href,
url: Astro.url.href,
name: `Applications | ${global.name}`,
description: global.about_applications,
isPartOf: {
'@type': 'WebSite',
url: global.site_url,
name: global.name,
description: global.about,
},
}}
>
<HeroSection
title="Applications"
subTitle={global.about_applications}
/>
<ApplicationSection className="smooth-reveal-2" />
</BaseLayout>
+47 -6
View File
@@ -1,4 +1,5 @@
@import 'tailwindcss';
@import './utilities-buttons.css';
@import './utilities-cards.css';
@import './utilities-misc.css';
@@ -6,6 +7,11 @@
@plugin '@tailwindcss/typography';
@plugin '@tailwindcss/forms';
/* Preline */
@source "../../node_modules/@preline/collapse/*.js";
@import "../../node_modules/@preline/collapse/variants.css";
@import "../../node_modules/@preline/collapse/theme.css";
/* Dark mode support for Tailwind CSS v4 */
/* https://tailwindcss.com/docs/dark-mode */
@custom-variant dark (&:where(.dark, .dark *));
@@ -39,23 +45,31 @@
--color-secondary: light-dark(var(--color-neutral-500), var(--color-neutral-400));
--color-secondary-hover: light-dark(var(--color-neutral-800), var(--color-neutral-200));
/* Object colors */
--color-background: light-dark(var(--color-neutral-200), var(--color-stone-700));
--color-background-accent: light-dark(color-mix(in srgb, var(--color-slate-300) 40%, transparent), color-mix(in srgb, var(--color-stone-800) 20%, transparent));
--color-background-card: light-dark(color-mix(in srgb, var(--color-neutral-100) 80%, transparent), color-mix(in srgb, var(--color-neutral-800) 60%, transparent));
/* Background colors */
--color-background: light-dark(var(--color-neutral-200), var(--color-mist-800));
--color-background-accent: light-dark(color-mix(in srgb, var(--color-slate-300) 40%, transparent), color-mix(in srgb, var(--color-mist-900) 20%, transparent));
--color-background-card: light-dark(color-mix(in srgb, var(--color-mist-100) 80%, transparent), color-mix(in srgb, var(--color-mist-900) 40%, transparent));
--color-background-1: light-dark(color-mix(in srgb, var(--color-mist-200) 75%, var(--color-slate-100)), color-mix(in srgb, var(--color-mist-700) 95%, var(--color-mist-950)));
--color-background-2: light-dark(color-mix(in srgb, var(--color-mist-400) 10%, var(--color-slate-100)), color-mix(in srgb, var(--color-mist-700) 80%, var(--color-mist-950)));
--color-background-3: light-dark(color-mix(in srgb, var(--color-mist-200) 85%, var(--color-slate-100)), color-mix(in srgb, var(--color-mist-700) 85%, var(--color-mist-950)));
/* Object colors */
--color-divider: light-dark(color-mix(in srgb, var(--color-slate-400) 40%, transparent), color-mix(in srgb, var(--color-neutral-500) 50%, transparent));
/* Typography */
--color-prose-blog-body: var(--color-neutral-700);
--color-prose-blog-headings: var(--color-neutral-900);
--color-prose-blog-links: var(--color-orange-300);
--color-prose-blog-invert-body: var(--color-neutral-400);
--color-prose-blog-invert-headings: var(--color-neutral-200);
--radius-markdown-img: 0.5rem;
/* Font */
--font-sans: var(--font-base);
/* Reveal Animations */
--animate-reveal: reveal 0.8s ease forwards;
--animate-reveal-fade: reveal-fade 1.8s ease forwards;
@@ -74,7 +88,7 @@
:root {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
--theme-transition: 0.3s ease;
}
@@ -114,6 +128,33 @@
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 */
.prose blockquote {
font-style: normal;
+2 -2
View File
@@ -8,7 +8,7 @@
@utility button-base-hidden {
@apply transition-all duration-300
border border-transparent
hover:bg-neutral-200 dark:hover:bg-neutral-700
hover:bg-mist-200 dark:hover:bg-mist-700
p-2
}
@@ -41,7 +41,7 @@
@utility button-bg-neutral {
@apply transition-all duration-300
border border-neutral-100 dark:border-stone-500/20
border border-neutral-100 dark:border-mist-700/20
bg-background-card hover:bg-neutral-100 dark:hover:bg-neutral-800/90
}
+11 -4
View File
@@ -1,8 +1,8 @@
@utility card-base {
@apply transition-all duration-300
rounded-xl
border border-neutral-100 dark:border-stone-500/20
bg-background-card hover:bg-neutral-100 dark:hover:bg-neutral-800/90
border border-mist-100/20 dark:border-mist-700/20
bg-background-card hover:bg-neutral-100 dark:hover:bg-mist-900/70
shadow-xs hover:shadow-md dark:shadow-md dark:hover:shadow-lg
}
@@ -10,7 +10,14 @@
@apply transition-all duration-300
rounded-2xl
border border-transparent
hover:bg-neutral-400/20 dark:hover:bg-neutral-800/40
hover:bg-mist-400/20 dark:hover:bg-mist-800/40
}
@utility card-base-hidden-md {
@apply transition-all duration-300
rounded-b-2xl
bg-background-card md:bg-transparent
group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-mist-900/70 md:dark:group-hover:bg-transparent
}
@utility card-hover-icon-color {
@@ -21,7 +28,7 @@
@utility card-hover-icon-scale {
@apply transition-transform duration-300 will-change-transform
drop-shadow-md dark:drop-shadow-xl dark:drop-shadow-neutral-500/60
drop-shadow-md dark:drop-shadow-xl dark:drop-shadow-mist-500/60
group-hover:scale-3d group-hover:scale-105
}
+2 -2
View File
@@ -1,7 +1,7 @@
/* Nav */
@utility nav-base {
@apply border border-neutral-100 dark:border-stone-500/20
bg-neutral-100 dark:bg-neutral-800
@apply border border-mist-100/20 dark:border-mist-700/20
bg-mist-100/80 dark:bg-mist-900/40
shadow-xs dark:shadow-md
}