Compare commits
17 Commits
33bbdecabd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a8473b964 | |||
| 18211ad485 | |||
| 429cf94023 | |||
| 0497731c45 | |||
| 6c2c6da91d | |||
| 19e17ea947 | |||
| 3d9120c570 | |||
| 875b8a7f47 | |||
| 1ddc76ae69 | |||
| 6423ffba63 | |||
| 505670dbf8 | |||
| b3d7e7af2b | |||
| 440c95224d | |||
| b9ee82e9d8 | |||
|
3af9f08b7c
|
|||
| 0bd56b172f | |||
|
ebf70bd747
|
@@ -27,7 +27,7 @@ ENV SITE_URL=https://www.alexlebens.dev
|
||||
ENV DIRECTUS_URL=https://directus.alexlebens.net
|
||||
ENV PORT=4321
|
||||
|
||||
LABEL version="2.10.1"
|
||||
LABEL version="2.12.0"
|
||||
LABEL description="Astro based personal website"
|
||||
|
||||
EXPOSE $PORT
|
||||
|
||||
11
package.json
11
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "site-profile",
|
||||
"type": "module",
|
||||
"version": "2.10.1",
|
||||
"version": "2.12.0",
|
||||
"homepage": "https://www.alexlebens.dev",
|
||||
"bugs": {
|
||||
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
|
||||
@@ -39,18 +39,16 @@
|
||||
"@iconify-json/pajamas": "^1.2.15",
|
||||
"@iconify-json/simple-icons": "^1.2.70",
|
||||
"@playform/compress": "^0.2.1",
|
||||
"@swup/astro": "^1.7.0",
|
||||
"@swup/astro": "^1.8.0",
|
||||
"@tailwindcss/postcss": "^4.1.18",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/unist": "^3.0.3",
|
||||
"astro": "^5.17.2",
|
||||
"astro-compressor": "^1.2.0",
|
||||
"astro-icon": "^1.1.5",
|
||||
"marked": "^17.0.2",
|
||||
"marked-shiki": "^1.2.1",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"motion": "^12.34.0",
|
||||
"preline": "^4.0.1",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
@@ -62,13 +60,12 @@
|
||||
"ultrahtml": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint-react/eslint-plugin": "^2.12.4",
|
||||
"@eslint-react/eslint-plugin": "^2.13.0",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"astro-icon": "^1.1.5",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-astro": "^1.5.0",
|
||||
"eslint-plugin-astro": "^1.6.0",
|
||||
"eslint-plugin-format": "^1.4.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
|
||||
204
pnpm-lock.yaml
generated
204
pnpm-lock.yaml
generated
@@ -45,8 +45,8 @@ importers:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1(@types/node@25.2.3)(jiti@2.6.1)(rollup@2.79.2)(typescript@5.9.3)(yaml@2.8.2)
|
||||
'@swup/astro':
|
||||
specifier: ^1.7.0
|
||||
version: 1.7.0(@types/babel__core@7.20.5)
|
||||
specifier: ^1.8.0
|
||||
version: 1.8.0(@types/babel__core@7.20.5)
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.1.18
|
||||
version: 4.1.18
|
||||
@@ -62,9 +62,6 @@ importers:
|
||||
astro:
|
||||
specifier: ^5.17.2
|
||||
version: 5.17.2(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@2.79.2)(terser@5.44.1)(typescript@5.9.3)(yaml@2.8.2)
|
||||
astro-compressor:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
astro-icon:
|
||||
specifier: ^1.1.5
|
||||
version: 1.1.5
|
||||
@@ -77,9 +74,6 @@ importers:
|
||||
mdast-util-to-string:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
motion:
|
||||
specifier: ^12.34.0
|
||||
version: 12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
preline:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
@@ -109,7 +103,7 @@ importers:
|
||||
version: 1.6.0
|
||||
devDependencies:
|
||||
'@eslint-react/eslint-plugin':
|
||||
specifier: ^2.12.4
|
||||
specifier: ^2.13.0
|
||||
version: 2.13.0(eslint@10.0.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@tailwindcss/forms':
|
||||
specifier: ^0.5.11
|
||||
@@ -124,7 +118,7 @@ importers:
|
||||
specifier: ^10.1.8
|
||||
version: 10.1.8(eslint@10.0.0(jiti@2.6.1))
|
||||
eslint-plugin-astro:
|
||||
specifier: ^1.5.0
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0(eslint@10.0.0(jiti@2.6.1))
|
||||
eslint-plugin-format:
|
||||
specifier: ^1.4.0
|
||||
@@ -1429,13 +1423,9 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@isaacs/balanced-match@4.0.1':
|
||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.1':
|
||||
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
'@isaacs/cliui@9.0.0':
|
||||
resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
||||
@@ -1747,8 +1737,8 @@ packages:
|
||||
peerDependencies:
|
||||
swup: ^4.0.0
|
||||
|
||||
'@swup/astro@1.7.0':
|
||||
resolution: {integrity: sha512-OxZskzeYkEZ4+McbwJKyD018sHNlrKQLdtHzlmNjivrzQY/dB7ncnWqDs3d4IkA7Y+ydNjpwBqpR/asjDhTiag==}
|
||||
'@swup/astro@1.8.0':
|
||||
resolution: {integrity: sha512-FI8/jNXgyUoWpnOgdB3MOUobRtRzedKBE8+qbBH5c8CE4q9Ni/GHPGrXK/0xG+g1ZiIQuTF3OXRvTLNVouiBig==}
|
||||
|
||||
'@swup/body-class-plugin@3.3.0':
|
||||
resolution: {integrity: sha512-4h/6mAgDd0+ml8Gc2kX8tikIR0HZZLF+WTnfm0JTVrGDw74bgEBenbsaWFfIS+gn4RWKZdWBUOfaZ+Im5J7Gvw==}
|
||||
@@ -2153,8 +2143,8 @@ packages:
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
ajv@8.18.0:
|
||||
resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==}
|
||||
|
||||
ansi-align@3.0.1:
|
||||
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
|
||||
@@ -2231,10 +2221,6 @@ packages:
|
||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
astro-compressor@1.2.0:
|
||||
resolution: {integrity: sha512-Y0UWW/AjyLcHlRhCK9yUqy0kg4qZHd54kDIMY4C/1huS6pSVZNsMY7a3Jk7o5RjytIkVaLDDkcUzR8SgipBH8g==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
astro-eslint-parser@1.3.0:
|
||||
resolution: {integrity: sha512-aOLc/aDR7lTWAHlytEefwn4Y6qs6uMr69DZvUx2A1AOAZsWhGB/paiRWPtVchh9wzMvLeqr+DkbENhVreVr9AQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -2316,6 +2302,10 @@ packages:
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
balanced-match@4.0.2:
|
||||
resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
base-64@1.0.0:
|
||||
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
|
||||
|
||||
@@ -2339,6 +2329,10 @@ packages:
|
||||
brace-expansion@2.0.2:
|
||||
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
|
||||
|
||||
brace-expansion@5.0.2:
|
||||
resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2392,8 +2386,8 @@ packages:
|
||||
caniuse-api@3.0.0:
|
||||
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
||||
|
||||
caniuse-lite@1.0.30001769:
|
||||
resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==}
|
||||
caniuse-lite@1.0.30001770:
|
||||
resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
@@ -3071,8 +3065,8 @@ packages:
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fast-xml-parser@5.3.5:
|
||||
resolution: {integrity: sha512-JeaA2Vm9ffQKp9VjvfzObuMCjUYAp5WDYhRYL5LrBPY/jUDlUtOvDfot0vKSkB9tuX885BDHjtw4fZadD95wnA==}
|
||||
fast-xml-parser@5.3.6:
|
||||
resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.20.1:
|
||||
@@ -3149,20 +3143,6 @@ packages:
|
||||
fraction.js@5.3.4:
|
||||
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
||||
|
||||
framer-motion@12.34.0:
|
||||
resolution: {integrity: sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
fresh@2.0.0:
|
||||
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -3569,8 +3549,8 @@ packages:
|
||||
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-wsl@3.1.0:
|
||||
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
|
||||
is-wsl@3.1.1:
|
||||
resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
isarray@2.0.5:
|
||||
@@ -3583,6 +3563,10 @@ packages:
|
||||
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
jackspeak@4.2.3:
|
||||
resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
jake@10.9.4:
|
||||
resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -4003,8 +3987,8 @@ packages:
|
||||
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
|
||||
hasBin: true
|
||||
|
||||
minimatch@10.1.2:
|
||||
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
|
||||
minimatch@10.2.0:
|
||||
resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@3.1.2:
|
||||
@@ -4032,26 +4016,6 @@ packages:
|
||||
morphdom@2.7.8:
|
||||
resolution: {integrity: sha512-D/fR4xgGUyVRbdMGU6Nejea1RFzYxYtyurG4Fbv2Fi/daKlWKuXGLOdXtl+3eIwL110cI2hz1ZojGICjjFLgTg==}
|
||||
|
||||
motion-dom@12.34.0:
|
||||
resolution: {integrity: sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==}
|
||||
|
||||
motion-utils@12.29.2:
|
||||
resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==}
|
||||
|
||||
motion@12.34.0:
|
||||
resolution: {integrity: sha512-01Sfa/zgsD/di8zA/uFW5Eb7/SPXoGyUfy+uMRMW5Spa8j0z/UbfQewAYvPMYFCXRlyD6e5aLHh76TxeeJD+RA==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
mri@1.2.0:
|
||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -5137,10 +5101,9 @@ packages:
|
||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar@7.5.7:
|
||||
resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==}
|
||||
tar@7.5.9:
|
||||
resolution: {integrity: sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==}
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
terser@5.44.1:
|
||||
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
|
||||
@@ -5279,8 +5242,8 @@ packages:
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
undici@7.21.0:
|
||||
resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
|
||||
undici@7.22.0:
|
||||
resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==}
|
||||
engines: {node: '>=20.18.1'}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1:
|
||||
@@ -5302,8 +5265,8 @@ packages:
|
||||
unified@11.0.5:
|
||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||
|
||||
unifont@0.7.3:
|
||||
resolution: {integrity: sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA==}
|
||||
unifont@0.7.4:
|
||||
resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==}
|
||||
|
||||
unist-util-find-after@5.0.0:
|
||||
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
|
||||
@@ -5824,7 +5787,7 @@ snapshots:
|
||||
|
||||
'@astrojs/rss@4.0.15':
|
||||
dependencies:
|
||||
fast-xml-parser: 5.3.5
|
||||
fast-xml-parser: 5.3.6
|
||||
piccolore: 0.1.3
|
||||
|
||||
'@astrojs/sitemap@3.7.0':
|
||||
@@ -5840,7 +5803,7 @@ snapshots:
|
||||
dlv: 1.1.3
|
||||
dset: 3.1.4
|
||||
is-docker: 3.0.0
|
||||
is-wsl: 3.1.0
|
||||
is-wsl: 3.1.1
|
||||
which-pm-runs: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6873,7 +6836,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@eslint/object-schema': 3.0.1
|
||||
debug: 4.4.3
|
||||
minimatch: 10.1.2
|
||||
minimatch: 10.2.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -6942,7 +6905,7 @@ snapshots:
|
||||
local-pkg: 1.1.2
|
||||
pathe: 2.0.3
|
||||
svgo: 3.3.2
|
||||
tar: 7.5.7
|
||||
tar: 7.5.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7057,11 +7020,7 @@ snapshots:
|
||||
'@img/sharp-win32-x64@0.34.5':
|
||||
optional: true
|
||||
|
||||
'@isaacs/balanced-match@4.0.1': {}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.1':
|
||||
dependencies:
|
||||
'@isaacs/balanced-match': 4.0.1
|
||||
'@isaacs/cliui@9.0.0': {}
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
dependencies:
|
||||
@@ -7378,7 +7337,7 @@ snapshots:
|
||||
focus-options-polyfill: 1.6.0
|
||||
swup: 4.8.2
|
||||
|
||||
'@swup/astro@1.7.0(@types/babel__core@7.20.5)':
|
||||
'@swup/astro@1.8.0(@types/babel__core@7.20.5)':
|
||||
dependencies:
|
||||
'@swup/a11y-plugin': 5.0.0(swup@4.8.2)
|
||||
'@swup/body-class-plugin': 3.3.0(swup@4.8.2)
|
||||
@@ -7858,9 +7817,9 @@ snapshots:
|
||||
|
||||
acorn@8.15.0: {}
|
||||
|
||||
ajv-draft-04@1.0.0(ajv@8.17.1):
|
||||
ajv-draft-04@1.0.0(ajv@8.18.0):
|
||||
optionalDependencies:
|
||||
ajv: 8.17.1
|
||||
ajv: 8.18.0
|
||||
|
||||
ajv@6.12.6:
|
||||
dependencies:
|
||||
@@ -7869,7 +7828,7 @@ snapshots:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ajv@8.17.1:
|
||||
ajv@8.18.0:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-uri: 3.1.0
|
||||
@@ -7973,8 +7932,6 @@ snapshots:
|
||||
get-intrinsic: 1.3.0
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
astro-compressor@1.2.0: {}
|
||||
|
||||
astro-eslint-parser@1.3.0:
|
||||
dependencies:
|
||||
'@astrojs/compiler': 2.13.1
|
||||
@@ -8053,7 +8010,7 @@ snapshots:
|
||||
tinyglobby: 0.2.15
|
||||
tsconfck: 3.1.6(typescript@5.9.3)
|
||||
ultrahtml: 1.6.0
|
||||
unifont: 0.7.3
|
||||
unifont: 0.7.4
|
||||
unist-util-visit: 5.1.0
|
||||
unstorage: 1.17.4
|
||||
vfile: 6.0.3
|
||||
@@ -8155,7 +8112,7 @@ snapshots:
|
||||
tinyglobby: 0.2.15
|
||||
tsconfck: 3.1.6(typescript@5.9.3)
|
||||
ultrahtml: 1.6.0
|
||||
unifont: 0.7.3
|
||||
unifont: 0.7.4
|
||||
unist-util-visit: 5.1.0
|
||||
unstorage: 1.17.4
|
||||
vfile: 6.0.3
|
||||
@@ -8218,7 +8175,7 @@ snapshots:
|
||||
autoprefixer@10.4.24(postcss@8.5.6):
|
||||
dependencies:
|
||||
browserslist: 4.28.1
|
||||
caniuse-lite: 1.0.30001769
|
||||
caniuse-lite: 1.0.30001770
|
||||
fraction.js: 5.3.4
|
||||
picocolors: 1.1.1
|
||||
postcss: 8.5.6
|
||||
@@ -8271,6 +8228,10 @@ snapshots:
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
balanced-match@4.0.2:
|
||||
dependencies:
|
||||
jackspeak: 4.2.3
|
||||
|
||||
base-64@1.0.0: {}
|
||||
|
||||
baseline-browser-mapping@2.9.19: {}
|
||||
@@ -8299,6 +8260,10 @@ snapshots:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
brace-expansion@5.0.2:
|
||||
dependencies:
|
||||
balanced-match: 4.0.2
|
||||
|
||||
braces@3.0.3:
|
||||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
@@ -8310,7 +8275,7 @@ snapshots:
|
||||
browserslist@4.28.1:
|
||||
dependencies:
|
||||
baseline-browser-mapping: 2.9.19
|
||||
caniuse-lite: 1.0.30001769
|
||||
caniuse-lite: 1.0.30001770
|
||||
electron-to-chromium: 1.5.286
|
||||
node-releases: 2.0.27
|
||||
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||
@@ -8352,11 +8317,11 @@ snapshots:
|
||||
caniuse-api@3.0.0:
|
||||
dependencies:
|
||||
browserslist: 4.28.1
|
||||
caniuse-lite: 1.0.30001769
|
||||
caniuse-lite: 1.0.30001770
|
||||
lodash.memoize: 4.1.2
|
||||
lodash.uniq: 4.5.0
|
||||
|
||||
caniuse-lite@1.0.30001769: {}
|
||||
caniuse-lite@1.0.30001770: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
@@ -8401,7 +8366,7 @@ snapshots:
|
||||
parse5: 7.3.0
|
||||
parse5-htmlparser2-tree-adapter: 7.1.0
|
||||
parse5-parser-stream: 7.1.2
|
||||
undici: 7.21.0
|
||||
undici: 7.22.0
|
||||
whatwg-mimetype: 4.0.0
|
||||
|
||||
chokidar@4.0.3:
|
||||
@@ -9197,7 +9162,7 @@ snapshots:
|
||||
imurmurhash: 0.1.4
|
||||
is-glob: 4.0.3
|
||||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
minimatch: 10.1.2
|
||||
minimatch: 10.2.0
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.4
|
||||
optionalDependencies:
|
||||
@@ -9277,7 +9242,7 @@ snapshots:
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fast-xml-parser@5.3.5:
|
||||
fast-xml-parser@5.3.6:
|
||||
dependencies:
|
||||
strnum: 2.1.2
|
||||
|
||||
@@ -9353,15 +9318,6 @@ snapshots:
|
||||
|
||||
fraction.js@5.3.4: {}
|
||||
|
||||
framer-motion@12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
motion-dom: 12.34.0
|
||||
motion-utils: 12.29.2
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
fresh@2.0.0: {}
|
||||
|
||||
fs-extra@10.1.0:
|
||||
@@ -9830,7 +9786,7 @@ snapshots:
|
||||
dependencies:
|
||||
is-docker: 2.2.1
|
||||
|
||||
is-wsl@3.1.0:
|
||||
is-wsl@3.1.1:
|
||||
dependencies:
|
||||
is-inside-container: 1.0.0
|
||||
|
||||
@@ -9847,6 +9803,10 @@ snapshots:
|
||||
has-symbols: 1.1.0
|
||||
set-function-name: 2.0.2
|
||||
|
||||
jackspeak@4.2.3:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 9.0.0
|
||||
|
||||
jake@10.9.4:
|
||||
dependencies:
|
||||
async: 3.2.6
|
||||
@@ -10452,9 +10412,9 @@ snapshots:
|
||||
|
||||
mini-svg-data-uri@1.4.4: {}
|
||||
|
||||
minimatch@10.1.2:
|
||||
minimatch@10.2.0:
|
||||
dependencies:
|
||||
'@isaacs/brace-expansion': 5.0.1
|
||||
brace-expansion: 5.0.2
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
@@ -10483,20 +10443,6 @@ snapshots:
|
||||
|
||||
morphdom@2.7.8: {}
|
||||
|
||||
motion-dom@12.34.0:
|
||||
dependencies:
|
||||
motion-utils: 12.29.2
|
||||
|
||||
motion-utils@12.29.2: {}
|
||||
|
||||
motion@12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
framer-motion: 12.34.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
mri@1.2.0: {}
|
||||
|
||||
mrmime@2.0.1: {}
|
||||
@@ -11695,7 +11641,7 @@ snapshots:
|
||||
|
||||
tapable@2.3.0: {}
|
||||
|
||||
tar@7.5.7:
|
||||
tar@7.5.9:
|
||||
dependencies:
|
||||
'@isaacs/fs-minipass': 4.0.1
|
||||
chownr: 3.0.0
|
||||
@@ -11839,7 +11785,7 @@ snapshots:
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
undici@7.21.0: {}
|
||||
undici@7.22.0: {}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1: {}
|
||||
|
||||
@@ -11862,7 +11808,7 @@ snapshots:
|
||||
trough: 2.2.0
|
||||
vfile: 6.0.3
|
||||
|
||||
unifont@0.7.3:
|
||||
unifont@0.7.4:
|
||||
dependencies:
|
||||
css-tree: 3.1.0
|
||||
ofetch: 1.5.1
|
||||
@@ -12155,8 +12101,8 @@ snapshots:
|
||||
yaml-language-server@1.19.2:
|
||||
dependencies:
|
||||
'@vscode/l10n': 0.0.18
|
||||
ajv: 8.17.1
|
||||
ajv-draft-04: 1.0.0(ajv@8.17.1)
|
||||
ajv: 8.18.0
|
||||
ajv-draft-04: 1.0.0(ajv@8.18.0)
|
||||
lodash: 4.17.21
|
||||
prettier: 3.8.1
|
||||
request-light: 0.5.8
|
||||
|
||||
@@ -3,10 +3,11 @@ import { getImage } from 'astro:assets';
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import { SEO } from '@/config';
|
||||
|
||||
import brandSrc from '@images/brand_logo.png';
|
||||
import faviconSvgSrc from '@images/favicon_icon.svg';
|
||||
import faviconSrc from '@images/favicon_icon.png';
|
||||
import { SEO } from '@/config';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
@@ -18,6 +19,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const canonicalURL = Astro.url.href;
|
||||
|
||||
let {
|
||||
title,
|
||||
description,
|
||||
@@ -27,14 +29,14 @@ let {
|
||||
structuredData = SEO.structuredData,
|
||||
} = Astro.props;
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
|
||||
let card = 'summary_large_image';
|
||||
if (!ogImage) {
|
||||
ogImage = brandSrc;
|
||||
card = 'summary';
|
||||
}
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
|
||||
const faviconSvg = await getImage({ src: faviconSvgSrc, format: 'svg' });
|
||||
const appleTouchIcon = await getImage({ src: faviconSrc, width: 180, height: 180, format: 'png' });
|
||||
const socialImageRes = await getImage({ src: ogImage, width: 1200, height: 600 });
|
||||
@@ -62,12 +64,12 @@ if (!socialImage.startsWith('http')) {
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="theme-color" content="#facc15" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content={Astro.url} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content={ogTitle} />
|
||||
<meta property="og:site_name" content={global.name} />
|
||||
<meta property="og:description" content={ogDescription} />
|
||||
@@ -76,17 +78,10 @@ if (!socialImage.startsWith('http')) {
|
||||
<meta content="600" property="og:image:height" />
|
||||
<meta content="image/png" property="og:image:type" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content={card} />
|
||||
<meta property="twitter:url" content={Astro.url} />
|
||||
<meta property="twitter:domain" content={Astro.url} />
|
||||
<meta property="twitter:title" content={ogTitle} />
|
||||
<meta property="twitter:description" content={ogDescription} />
|
||||
<meta property="twitter:image" content={socialImage} />
|
||||
|
||||
<!-- Links -->
|
||||
<link href={canonicalURL} rel="canonical" />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
<link rel="alternate" type="application/rss+xml" title={title} href="/rss.xml" />
|
||||
<!--<link href="/manifest.json" rel="manifest" />-->
|
||||
<link href="/favicon.ico" rel="icon" sizes="any" type="image/x-icon" />
|
||||
<link href={faviconSvg.src} rel="icon" type="image/svg+xml" sizes="any" />
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
---
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BrandLogo from '@components/ui/logos/BrandLogo.astro';
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import directus from '@lib/directus';
|
||||
import { NavigationLinks, FooterLinks } from '@/config';
|
||||
|
||||
import footerImg from '@images/flowers.png';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
---
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import { formatDate } from '@support/time';
|
||||
|
||||
interface Props {
|
||||
post: Post;
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
|
||||
const baseClasses = 'group group-hover smooth-reveal-cards rounded-xl flex flex-col';
|
||||
const borderClasses = 'border border-stone-200/50 dark:border-stone-700/50';
|
||||
const bgColorClasses =
|
||||
'bg-neutral-100/80 hover:bg-neutral-100 dark:bg-neutral-800/60 dark:hover:bg-neutral-800/90';
|
||||
const shadowClasses = 'shadow-xs hover:shadow-md dark:shadow-md dark:hover:shadow-lg';
|
||||
---
|
||||
|
||||
<div class={`${baseClasses}`}>
|
||||
<a
|
||||
class={`rounded-xl duration-300 transition-all ${borderClasses} ${shadowClasses} ${bgColorClasses}`}
|
||||
href={`/blog/${post.slug}/`}
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div
|
||||
class="relative w-full flex-shrink-0 overflow-hidden rounded-t-xl before:absolute before:inset-x-0 before:z-[1] before:size-full"
|
||||
>
|
||||
<Image
|
||||
class="h-auto w-full rounded-t-xl"
|
||||
src={getDirectusImageURL(post.image)}
|
||||
alt={post.image_alt}
|
||||
draggable="false"
|
||||
loading="eager"
|
||||
format="webp"
|
||||
width="800"
|
||||
height="460"
|
||||
/>
|
||||
</div>
|
||||
<div class="rounded-xl p-4 md:p-5">
|
||||
<h3 class="text-xl font-bold text-neutral-600 dark:text-neutral-200">
|
||||
{post.title}
|
||||
</h3>
|
||||
<div
|
||||
class="group-hover:text-steel dark:group-hover:text-bermuda transition-text relative z-10 mx-auto flex min-h-[44px] items-center font-medium text-neutral-600 decoration-2 duration-300 sm:mx-0 sm:mt-4 dark:text-neutral-400"
|
||||
>
|
||||
<span class="relative inline-block overflow-hidden"> Read more </span>
|
||||
<Icon
|
||||
name="mdi:keyboard-arrow-right"
|
||||
class="h-3 w-3 translate-y-0.25 transition duration-300 group-hover:translate-x-1 md:h-5 md:w-5"
|
||||
/>
|
||||
<p class="ml-auto text-sm text-neutral-600 dark:text-neutral-400">
|
||||
{formatDate(post.published_date)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
btnExists?: boolean;
|
||||
btnTitle?: string;
|
||||
btnURL?: string;
|
||||
img: any;
|
||||
imgAlt: any;
|
||||
}
|
||||
|
||||
const { title, subTitle, btnExists, btnTitle, btnURL, img, imgAlt } = Astro.props;
|
||||
---
|
||||
|
||||
<section
|
||||
class="mx-auto max-w-[85rem] items-center gap-8 px-4 py-10 sm:px-6 sm:py-16 md:grid md:grid-cols-2 lg:grid lg:grid-cols-2 lg:px-8 lg:py-14 xl:gap-16 2xl:max-w-full"
|
||||
>
|
||||
<Image
|
||||
class="h-full w-full rounded-xl object-cover sm:max-h-[320px] md:max-h-[360px]"
|
||||
src={img}
|
||||
alt={imgAlt}
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
width="850"
|
||||
height="420"
|
||||
/>
|
||||
|
||||
<div class="mt-4 md:mt-0">
|
||||
<h2
|
||||
class="mb-4 text-4xl font-extrabold tracking-tight text-balance text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<p
|
||||
class="mb-4 max-w-prose font-light text-pretty text-neutral-600 sm:text-lg dark:text-neutral-300"
|
||||
>
|
||||
{subTitle}
|
||||
</p>
|
||||
{btnExists ? <GoLinkPrimaryButton title={btnTitle} url={btnURL} /> : null}
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
import BlogCard from '@components/blog/BlogCard.astro';
|
||||
|
||||
interface Props {
|
||||
posts: Post[];
|
||||
}
|
||||
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="mx-auto mb-10 max-w-[85rem] px-4 py-8 sm:px-6 lg:px-8 2xl:max-w-full">
|
||||
<div class="text-left">
|
||||
<h2
|
||||
id="recent-articles"
|
||||
class="smooth-reveal-2 mb-10 text-5xl font-extrabold tracking-tight text-balance text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
Recent Posts
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:space-x-12 lg:space-x-16">
|
||||
<div class="w-full">
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{posts.map((b) => <BlogCard post={b} />)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
btnExists?: boolean;
|
||||
btnTitle?: string;
|
||||
btnURL?: string;
|
||||
single?: boolean;
|
||||
imgOne?: any;
|
||||
imgOneAlt?: any;
|
||||
imgTwo?: any;
|
||||
imgTwoAlt?: any;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subTitle,
|
||||
btnExists,
|
||||
btnTitle,
|
||||
btnURL,
|
||||
single,
|
||||
imgOne,
|
||||
imgOneAlt,
|
||||
imgTwo,
|
||||
imgTwoAlt,
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<section
|
||||
class="mx-auto max-w-[85rem] items-center gap-16 px-4 py-10 sm:px-6 lg:grid lg:grid-cols-2 lg:px-8 lg:py-14 2xl:max-w-full"
|
||||
>
|
||||
<div>
|
||||
<h2
|
||||
class="mb-4 text-4xl font-extrabold tracking-tight text-balance text-neutral-800 dark:text-neutral-200"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<p
|
||||
class="mb-4 max-w-prose font-light text-pretty text-neutral-600 sm:text-lg dark:text-neutral-400"
|
||||
>
|
||||
{subTitle}
|
||||
</p>
|
||||
{btnExists ? <GoLinkPrimaryButton title={btnTitle} url={btnURL} /> : null}
|
||||
</div>
|
||||
|
||||
{
|
||||
single ? (
|
||||
<div class="mt-8">
|
||||
<Image
|
||||
class="w-full rounded-lg"
|
||||
src={imgOne}
|
||||
alt={imgOneAlt}
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="850"
|
||||
height="420"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div class="mt-8 grid grid-cols-2 gap-4">
|
||||
<Image
|
||||
class="w-full rounded-xl"
|
||||
src={imgOne}
|
||||
alt={imgOneAlt}
|
||||
draggable="false"
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="400"
|
||||
height="230"
|
||||
/>
|
||||
<Image
|
||||
class="mt-4 w-full rounded-xl lg:mt-10"
|
||||
src={imgTwo}
|
||||
alt={imgTwoAlt}
|
||||
draggable="false"
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="400"
|
||||
height="230"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</section>
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
import BlogLeftSection from '@components/blog/BlogLeftSection.astro';
|
||||
import BlogRightSection from '@components/blog/BlogRightSection.astro';
|
||||
|
||||
interface Props {
|
||||
posts: Post[];
|
||||
}
|
||||
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="smooth-reveal">
|
||||
{
|
||||
posts.map((b, index) =>
|
||||
index % 2 === 0 ? (
|
||||
<BlogLeftSection
|
||||
title={b.title}
|
||||
subTitle={b.description}
|
||||
btnExists={true}
|
||||
btnTitle="Read More"
|
||||
btnURL={`/blog/${b.slug}`}
|
||||
img={getDirectusImageURL(b.image)}
|
||||
imgAlt={b.image_alt}
|
||||
/>
|
||||
) : (
|
||||
<BlogRightSection
|
||||
title={b.title}
|
||||
subTitle={b.description}
|
||||
btnExists={true}
|
||||
btnTitle="Read More"
|
||||
btnURL={`/blog/${b.slug}`}
|
||||
single={!b.image_second}
|
||||
imgOne={getDirectusImageURL(b.image)}
|
||||
imgOneAlt={b.image_alt}
|
||||
imgTwo={getDirectusImageURL(b?.image_second)}
|
||||
imgTwoAlt={b?.image_second_alt}
|
||||
/>
|
||||
)
|
||||
)
|
||||
}
|
||||
</section>
|
||||
@@ -2,11 +2,10 @@
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
const { title, url } = Astro.props;
|
||||
const { url } = Astro.props;
|
||||
---
|
||||
|
||||
<a
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
---
|
||||
import Icon from '@components/ui/icons/icon.astro';
|
||||
|
||||
interface Props {
|
||||
noArrow?: boolean;
|
||||
}
|
||||
|
||||
const { noArrow } = Astro.props;
|
||||
---
|
||||
|
||||
<button
|
||||
@@ -14,7 +8,7 @@ const { noArrow } = Astro.props;
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div class="button-text-title flex relative items-center text-center">
|
||||
{noArrow ? null : <Icon name="arrowLeft" />}
|
||||
<Icon name="arrowLeft" />
|
||||
<span class="ml-2">
|
||||
Go Back
|
||||
</span>
|
||||
|
||||
@@ -33,19 +33,20 @@ const socialPlatforms: SocialPlatform[] = [
|
||||
---
|
||||
|
||||
<div class="inline-flex items-center gap-x-2">
|
||||
{
|
||||
socialPlatforms.map((platform) => (
|
||||
<a
|
||||
class="button-base-hidden group inline-flex rounded-lg gap-x-2"
|
||||
href={platform.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={`Share on ${platform.name}`}
|
||||
>
|
||||
<div class="button-text-title-hidden flex relative items-center text-center">
|
||||
<Icon name={platform.svg} class="h-5 w-5" />
|
||||
</div>
|
||||
</a>
|
||||
))
|
||||
}
|
||||
{socialPlatforms.map((platform) => (
|
||||
<a
|
||||
class="button-base-hidden group inline-flex rounded-lg gap-x-2"
|
||||
href={platform.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={`Share on ${platform.name}`}
|
||||
>
|
||||
<div class="button-text-title-hidden flex relative items-center text-center">
|
||||
<Icon
|
||||
name={platform.svg}
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
58
src/components/cards/BlogCard.astro
Normal file
58
src/components/cards/BlogCard.astro
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
|
||||
interface Props {
|
||||
post: Post;
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="smooth-reveal-cards group flex flex-col">
|
||||
<a
|
||||
class="card-base border-none!"
|
||||
href={`/blog/${post.slug}/`}
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div class="relative shrink-0 rounded-t-xl w-full overflow-hidden before:absolute before:inset-x-0 before:z-1 before:size-full">
|
||||
<Image
|
||||
class="rounded-t-xl h-auto w-full"
|
||||
src={getDirectusImageURL(post.image)}
|
||||
alt={post.image_alt}
|
||||
draggable="false"
|
||||
loading="eager"
|
||||
format="webp"
|
||||
/>
|
||||
</div>
|
||||
<div class="rounded-xl p-4 md:p-5">
|
||||
<h3 class="card-text-title text-xl">
|
||||
{post.title}
|
||||
</h3>
|
||||
<div class="ml-6 flex">
|
||||
<div class="relative inline-block w-full">
|
||||
<div class="card-text-title card-hover-text-title flex relative items-center mx-auto min-h-11 sm:mx-0 sm:mt-4">
|
||||
<span class="relative inline-block overflow-hidden ml-2">
|
||||
Read more
|
||||
</span>
|
||||
<Icon
|
||||
name="mdi:keyboard-arrow-right"
|
||||
class="translate-y-0.5 transition duration-300 group-hover:translate-x-1"
|
||||
/>
|
||||
<p class="card-text-description text-sm ml-auto">
|
||||
{new Date(post.published_date).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -8,37 +8,30 @@ interface Props {
|
||||
}
|
||||
|
||||
const { slug, title, description, count, publishDate } = Astro.props;
|
||||
|
||||
const baseClasses =
|
||||
'group group-hover rounded-xl flex h-full min-h-[220px] cursor-pointer flex-col overflow-hidden';
|
||||
const bgColorClasses =
|
||||
'bg-neutral-100/60 dark:bg-neutral-800/60 hover:bg-neutral-100 dark:hover:bg-neutral-800/90 ';
|
||||
---
|
||||
|
||||
<a class={`rounded-xl`} href={`/categories/${slug}/`} data-astro-prefetch="false">
|
||||
<div class={`${baseClasses}`}>
|
||||
<div
|
||||
class={`relative min-h-0 flex-grow overflow-hidden transition-all duration-300 ${bgColorClasses}`}
|
||||
>
|
||||
<div class="smooth-reveal-cards group h-full">
|
||||
<a
|
||||
class="card-base flex flex-col h-full min-h-55"
|
||||
href={`/categories/${slug}/`}
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div class="relative grow overflow-hidden">
|
||||
<div class="absolute inset-1 flex flex-col p-3 md:p-4 lg:p-5">
|
||||
<div class="overflow-hidden">
|
||||
<h2
|
||||
class="group-hover:text-steel dark:group-hover:text-bermuda transition-text mb-4 text-4xl font-extrabold tracking-tight text-balance whitespace-nowrap text-neutral-800 duration-300 dark:text-neutral-200"
|
||||
>
|
||||
<h3 class="card-text-title-major card-hover-text-title whitespace-nowrap mb-4">
|
||||
{title}
|
||||
</h2>
|
||||
<p class="mb-4 font-light text-neutral-600 sm:text-lg dark:text-neutral-400">
|
||||
</h3>
|
||||
<p class="card-text-description mb-4">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="mt-auto flex items-center justify-between pt-1 text-xs text-neutral-600 md:pt-2 dark:text-neutral-300"
|
||||
>
|
||||
<div class="card-text-description flex items-center justify-between text-xs mt-auto pt-1 md:pt-2">
|
||||
<span class="inline-flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
@@ -51,8 +44,8 @@ const bgColorClasses =
|
||||
<span class="inline-flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
@@ -66,5 +59,5 @@ const bgColorClasses =
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
import Logo from '@components/ui/logos/Logo.astro';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
|
||||
interface Props {
|
||||
topic: string;
|
||||
@@ -12,7 +14,8 @@ interface Props {
|
||||
logoIcon?: string;
|
||||
}
|
||||
|
||||
const { topic, area, date, url, logoUrlLight, logoUrlDark, logoIcon } = Astro.props;
|
||||
const { topic, area, date, url, logoUrlLight, logoIcon } = Astro.props;
|
||||
const logoUrlDark = Astro.props.logoUrlDark || logoUrlLight;
|
||||
---
|
||||
|
||||
<div class="smooth-reveal group flex flex-col">
|
||||
@@ -25,8 +28,8 @@ const { topic, area, date, url, logoUrlLight, logoUrlDark, logoIcon } = Astro.pr
|
||||
{logoUrlLight ? (
|
||||
<div class="card-hover-icon-scale mr-5">
|
||||
<Logo
|
||||
srcLight={logoUrlLight}
|
||||
srcDark={logoUrlDark}
|
||||
srcLight={getDirectusImageURL(logoUrlLight)}
|
||||
srcDark={getDirectusImageURL(logoUrlDark!)}
|
||||
alt={`Logo of ${topic}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,13 +9,11 @@ interface Props {
|
||||
}
|
||||
|
||||
const { title, description, url, icon } = Astro.props;
|
||||
|
||||
const sizeClasses = 'h-30 w-100 md:w-[300px]';
|
||||
---
|
||||
|
||||
<div class="smooth-reveal-2 group flex flex-col">
|
||||
<a
|
||||
class={`card-base flex items-center ${sizeClasses}`}
|
||||
class="card-base flex items-center h-30 w-100 md:w-75"
|
||||
href={url}
|
||||
data-astro-prefetch
|
||||
>
|
||||
@@ -29,9 +27,9 @@ const sizeClasses = 'h-30 w-100 md:w-[300px]';
|
||||
<span class="card-text-title card-hover-text-title block text-lg">
|
||||
{title}
|
||||
</span>
|
||||
<span class="card-text-description block mt-1">
|
||||
<p class="card-text-description block mt-1">
|
||||
{description}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,9 +39,9 @@ const visitClass = visitSource ? 'card-hover-text-gitea' : 'card-hover-text-titl
|
||||
<span class="card-text-title block text-lg">
|
||||
{title}
|
||||
</span>
|
||||
<span class="card-text-description block mt-1">
|
||||
<p class="card-text-description block mt-1">
|
||||
{description}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{highlights && (
|
||||
@@ -55,7 +55,7 @@ const visitClass = visitSource ? 'card-hover-text-gitea' : 'card-hover-text-titl
|
||||
)}
|
||||
<div class="ml-6 flex">
|
||||
<div class="relative inline-block">
|
||||
<div class={`card-text-title ${visitClass} flex relative items-center mx-auto min-h-11 font-semibold text-md sm:mx-0 sm:mt-4`}>
|
||||
<div class={`card-text-title ${visitClass} flex relative items-center font-semibold text-md min-h-11 mx-auto sm:mx-0 sm:mt-4`}>
|
||||
{visitSource && <Icon name="pajamas:gitea" />}
|
||||
<span class="relative inline-block overflow-hidden ml-2">
|
||||
{visitText}
|
||||
|
||||
55
src/components/cards/LargeBlogLeftCard.astro
Normal file
55
src/components/cards/LargeBlogLeftCard.astro
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
url: string;
|
||||
img: string;
|
||||
imgAlt: string;
|
||||
}
|
||||
|
||||
const { title, subTitle, url, img, imgAlt } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="smooth-reveal group">
|
||||
<a
|
||||
class="card-base-hidden md:grid md:grid-cols-2 lg:grid lg:grid-cols-2 items-center gap-8 xl:gap-16 max-w-340 2xl:max-w-full px-4 sm:px-6 lg:px-8 py-10 sm:py-16 lg:py-14 mx-auto"
|
||||
href={url}
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div>
|
||||
<Image
|
||||
class="rounded-xl w-full h-full sm:max-h-80 md:max-h-90 object-cover"
|
||||
src={getDirectusImageURL(img)}
|
||||
alt={imgAlt}
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
width="850"
|
||||
height="420"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-text-header mb-4">
|
||||
{title}
|
||||
</h2>
|
||||
<p class="card-text-title font-light text-pretty sm:text-lg max-w-prose mb-4">
|
||||
{subTitle}
|
||||
</p>
|
||||
<div class="button-base button-bg-teal inline-flex rounded-lg gap-x-2">
|
||||
<div class="button-text-title flex relative items-center text-center">
|
||||
<span class="mr-2">
|
||||
Read More
|
||||
</span>
|
||||
<Icon
|
||||
name="mdi:keyboard-arrow-right"
|
||||
class="button-hover-arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
83
src/components/cards/LargeBlogRightCard.astro
Normal file
83
src/components/cards/LargeBlogRightCard.astro
Normal file
@@ -0,0 +1,83 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
url: string;
|
||||
single?: boolean;
|
||||
imgOne: any;
|
||||
imgOneAlt: any;
|
||||
imgTwo?: any;
|
||||
imgTwoAlt?: any;
|
||||
}
|
||||
|
||||
const { title, subTitle, url, single, imgOne, imgOneAlt, imgTwo, imgTwoAlt } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="smooth-reveal group">
|
||||
<a
|
||||
class="card-base-hidden items-center lg:grid lg:grid-cols-2 gap-16 max-w-340 2xl:max-w-full px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto"
|
||||
href={url}
|
||||
data-astro-prefetch
|
||||
>
|
||||
<div>
|
||||
<h2 class="card-text-header mb-4">
|
||||
{title}
|
||||
</h2>
|
||||
<p class="card-text-title font-light text-pretty sm:text-lg max-w-prose mb-4">
|
||||
{subTitle}
|
||||
</p>
|
||||
<div class="button-base button-bg-teal inline-flex rounded-lg gap-x-2">
|
||||
<div class="button-text-title flex relative items-center text-center">
|
||||
<span class="mr-2">
|
||||
Read More
|
||||
</span>
|
||||
<Icon
|
||||
name="mdi:keyboard-arrow-right"
|
||||
class="button-hover-arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{single ? (
|
||||
<div>
|
||||
<Image
|
||||
class="rounded-xl w-full"
|
||||
src={getDirectusImageURL(imgOne)}
|
||||
alt={imgOneAlt}
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="850"
|
||||
height="420"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<Image
|
||||
class="rounded-xl w-full"
|
||||
src={getDirectusImageURL(imgOne)}
|
||||
alt={imgOneAlt}
|
||||
draggable="false"
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="400"
|
||||
height="230"
|
||||
/>
|
||||
<Image
|
||||
class="rounded-xl w-full mt-4 lg:mt-10"
|
||||
src={getDirectusImageURL(imgTwo)}
|
||||
alt={imgTwoAlt}
|
||||
draggable="false"
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
width="400"
|
||||
height="230"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
@@ -7,12 +7,10 @@ interface Props {
|
||||
}
|
||||
|
||||
const { dayName, label, icon, temp } = Astro.props;
|
||||
|
||||
const sizeClasses = 'w-32 md:w-40';
|
||||
---
|
||||
|
||||
<div class="smooth-reveal-2 group flex flex-col">
|
||||
<div class={`card-base ${sizeClasses}`}>
|
||||
<div class="card-base w-32 md:w-40">
|
||||
<div class="p-5 text-center">
|
||||
<span class="card-text-description block font-bold text-xs uppercase tracking-widest">
|
||||
{dayName}
|
||||
|
||||
@@ -3,8 +3,8 @@ import { readItems } from '@directus/sdk';
|
||||
|
||||
import type { Application } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import HighlightsCard from '@components/cards/HighlightsCard.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
const applications = ((await directus.request(
|
||||
readItems('site_applications' as any, {
|
||||
|
||||
93
src/components/sections/CategorySection.astro
Normal file
93
src/components/sections/CategorySection.astro
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { readItems } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import CategoryCard from '@components/cards/CategoryCard.astro';
|
||||
import directus from '@lib/directus';
|
||||
import { timeago } from '@support/time';
|
||||
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
filter: { published: { _eq: true } },
|
||||
fields: ['*'],
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const layoutPattern = [
|
||||
{ col: 2, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
];
|
||||
|
||||
const postMap: Map<string, Post[]> = posts
|
||||
.sort((a: Post, b: Post) => b.published_date.valueOf() - a.published_date.valueOf())
|
||||
.reduce((acc, obj) => {
|
||||
let posts = acc.get(obj.category);
|
||||
if (!posts) {
|
||||
posts = [];
|
||||
}
|
||||
posts.push(obj);
|
||||
|
||||
acc.set(obj.category, posts);
|
||||
|
||||
return acc;
|
||||
}, new Map<string, Post[]>());
|
||||
|
||||
const categories = (await getCollection('categories'))
|
||||
.sort((a, b) => {
|
||||
const aCount = postMap.get(a.slug)?.length ?? 0;
|
||||
const bCount = postMap.get(b.slug)?.length ?? 0;
|
||||
return bCount - aCount;
|
||||
})
|
||||
.map((c, index) => {
|
||||
const posts = postMap.get(c.slug);
|
||||
const pattern = layoutPattern[index % layoutPattern.length];
|
||||
const smColSpan = Math.min(pattern.col, 2);
|
||||
const mdColSpan = Math.min(pattern.col, 4);
|
||||
const rowSpan = pattern.row;
|
||||
const rowSpanClass = rowSpan > 1 ? `row-span-${rowSpan}` : 'row-span-1';
|
||||
const gridItemClass = `col-span-${smColSpan} md:col-span-${mdColSpan} ${rowSpanClass}`;
|
||||
return {
|
||||
...c,
|
||||
posts,
|
||||
gridItemClass,
|
||||
layoutPattern: {
|
||||
smCol: smColSpan,
|
||||
mdCol: mdColSpan,
|
||||
row: rowSpan,
|
||||
index,
|
||||
},
|
||||
};
|
||||
});
|
||||
---
|
||||
|
||||
<section class="mx-auto px-4 py-10 sm:px-6 lg:px-8 lg:py-14 lg:pt-10 2xl:max-w-full">
|
||||
<div class="grid grid-flow-row-dense grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{categories.map((category) => {
|
||||
return (
|
||||
<div
|
||||
class={category.gridItemClass}
|
||||
style={category.layoutPattern.row > 1 ? 'grid-row: span 2 / span 2;' : ''}
|
||||
>
|
||||
<CategoryCard
|
||||
slug={category.slug}
|
||||
title={category.data.title}
|
||||
description={category.data.description}
|
||||
count={postMap.get(category.slug)?.length ?? 0}
|
||||
publishDate={timeago(postMap.get(category.slug)?.[0]?.published_date)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
@@ -3,9 +3,8 @@ import { readItems } from '@directus/sdk';
|
||||
|
||||
import type { Education, Certificate} from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
import EducationCard from '@components/cards/EducationCard.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
const educations = ((await directus.request(
|
||||
readItems('site_education' as any, {
|
||||
@@ -37,8 +36,8 @@ const certificates = ((await directus.request(
|
||||
area={education.area}
|
||||
date={education.graduationDate}
|
||||
url={education.url}
|
||||
logoUrlLight={getDirectusImageURL(education.logo)}
|
||||
logoUrlDark={getDirectusImageURL(education.logoDark)}
|
||||
logoUrlLight={education.logo}
|
||||
logoUrlDark={education.logoDark}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -78,7 +78,7 @@ const experiences = ((await directus.request(
|
||||
</div>
|
||||
)}
|
||||
{(experience.responsibilities || experience.achievements) && (
|
||||
<div class="relative flex flex-col gap-4 max-sm:h-auto! md:after:absolute md:after:bottom-0 md:after:h-12 md:after:w-full md:after:bg-gradient-to-t md:after:from-neutral-200 dark:md:after:from-stone-700 md:after:content-[''] " :class="expanded ? 'after:hidden' : ''" x-show="expanded" x-collapse.min.50px>
|
||||
<div class="relative flex flex-col gap-4 max-sm:h-auto! md:after:absolute md:after:bottom-0 md:after:h-12 md:after:w-full md:after:bg-linear-to-t md:after:from-neutral-200 dark:md:after:from-stone-700 md:after:content-[''] " :class="expanded ? 'after:hidden' : ''" x-show="expanded" x-collapse.min.50px>
|
||||
{experience.responsibilities && (
|
||||
<div class="flex flex-col gap-1">
|
||||
<h4 class="text-header font-semibold">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import FeaturesCard from '@components/cards/FeaturesCard.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
---
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
import { readItems } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BlogCard from '@components/blog/BlogCard.astro';
|
||||
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
filter: { published: { _eq: true } },
|
||||
fields: ['*'],
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const recentPosts = posts
|
||||
.sort((a: Post, b: Post) => (new Date(b.published_date).getTime()) - (new Date(a.published_date).getTime()))
|
||||
.slice(0, 3);
|
||||
---
|
||||
|
||||
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
|
||||
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
|
||||
<h1 class="smooth-reveal card-text-header block">
|
||||
Latest Posts
|
||||
</h1>
|
||||
<div class="smooth-reveal mx-auto mt-5 max-w-3xl text-center">
|
||||
<span class="card-text-header-description">
|
||||
Checkout my most recent thoughts here
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{recentPosts.map((b) => <BlogCard post={b} />)}
|
||||
</div>
|
||||
</section>
|
||||
@@ -3,8 +3,8 @@ import { readItems } from '@directus/sdk';
|
||||
|
||||
import type { Project } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import HighlightsCard from '@components/cards/HighlightsCard.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
const projects = ((await directus.request(
|
||||
readItems('site_projects' as any, {
|
||||
|
||||
29
src/components/sections/RecentPostsSection.astro
Normal file
29
src/components/sections/RecentPostsSection.astro
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import BlogCard from '@components/cards/BlogCard.astro';
|
||||
|
||||
interface Props {
|
||||
posts: Post[];
|
||||
title: string;
|
||||
subTitle?: string;
|
||||
}
|
||||
|
||||
const { posts, title, subTitle } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
|
||||
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
|
||||
<h1 class="smooth-reveal card-text-header block">
|
||||
{title}
|
||||
</h1>
|
||||
<div class="smooth-reveal mx-auto mt-5 max-w-3xl text-center">
|
||||
<span class="card-text-header-description">
|
||||
{subTitle}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{posts.map((b) => <BlogCard post={b} />)}
|
||||
</div>
|
||||
</section>
|
||||
35
src/components/sections/SelectedPostsSection.astro
Normal file
35
src/components/sections/SelectedPostsSection.astro
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import LargeBlogLeftCard from '@components/cards/LargeBlogLeftCard.astro';
|
||||
import LargeBlogRightCard from '@components/cards/LargeBlogRightCard.astro';
|
||||
|
||||
interface Props {
|
||||
posts: Post[];
|
||||
}
|
||||
|
||||
const { posts } = Astro.props;
|
||||
---
|
||||
|
||||
<section class="smooth-reveal">
|
||||
{posts.map((post, index) => index % 2 === 0 ? (
|
||||
<LargeBlogLeftCard
|
||||
title={post.title}
|
||||
subTitle={post.description}
|
||||
url={`/blog/${post.slug}`}
|
||||
img={post.image}
|
||||
imgAlt={post.image_alt}
|
||||
/>
|
||||
) : (
|
||||
<LargeBlogRightCard
|
||||
title={post.title}
|
||||
subTitle={post.description}
|
||||
url={`/blog/${post.slug}`}
|
||||
single={!post.image_second}
|
||||
imgOne={post.image}
|
||||
imgOneAlt={post.image_alt}
|
||||
imgTwo={post?.image_second}
|
||||
imgTwoAlt={post?.image_second_alt}
|
||||
/>
|
||||
))}
|
||||
</section>
|
||||
@@ -3,6 +3,7 @@ import WeatherCard from '@components/cards/WeatherCard.astro';
|
||||
import { getFiveDayForecast } from '@support/weather';
|
||||
|
||||
const { latitude = "44.95", longitude = "-93.09", cityName = "St. Paul, Minnesota", timezone = "America/Chicago" } = Astro.props;
|
||||
|
||||
const { forecastDays, error } = await getFiveDayForecast(latitude, longitude, timezone);
|
||||
---
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ const global = await directus.request(readSingleton('site_global'));
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
<section class="mt-20 grid place-content-center">
|
||||
<div class="mx-auto max-w-7xl px-4 py-8 lg:px-6 lg:py-16">
|
||||
<div class="mx-auto max-w-screen-sm text-center">
|
||||
@@ -67,6 +68,7 @@ const global = await directus.request(readSingleton('site_global'));
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||
import getReadingTime from 'reading-time';
|
||||
import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import { marked } from 'marked';
|
||||
import markedShiki from 'marked-shiki';
|
||||
import { createHighlighter } from 'shiki';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import Image from '@components/ui/images/Image.astro';
|
||||
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import directus from '@lib/directus';
|
||||
import { getDirectusImageURL } from '@lib/directusFunctions';
|
||||
import { formatDateTime } from '@support/time';
|
||||
|
||||
const post = Astro.props;
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await directus.request(readItems('posts'));
|
||||
return posts.map((post) => ({
|
||||
@@ -20,18 +22,19 @@ export async function getStaticPaths() {
|
||||
props: post,
|
||||
}));
|
||||
}
|
||||
const post = Astro.props;
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
const category: CollectionEntry<'categories'> = (await getCollection('categories'))
|
||||
.filter((c) => c.slug === post.category)
|
||||
.pop() as CollectionEntry<'categories'>;
|
||||
|
||||
const readingTime = getReadingTime(post.content);
|
||||
|
||||
const highlighter = await createHighlighter({
|
||||
themes: ['github-light', 'github-dark', 'monokai'],
|
||||
langs: ['typescript', 'python', 'css', 'html', 'yaml', 'bash', 'json'],
|
||||
});
|
||||
|
||||
marked.use(markedShiki({
|
||||
highlight(code, lang) {
|
||||
return highlighter.codeToHtml(code, {
|
||||
@@ -44,6 +47,7 @@ marked.use(markedShiki({
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
const content = marked.parse(post.content);
|
||||
---
|
||||
|
||||
@@ -79,6 +83,7 @@ const content = marked.parse(post.content);
|
||||
],
|
||||
}}
|
||||
>
|
||||
|
||||
<section class="mx-auto max-w-6xl px-4 pt-8 pb-12 sm:px-6 lg:px-8 lg:pt-12">
|
||||
<div class="smooth-reveal relative w-full">
|
||||
<div class="mt-4 rounded-2xl shadow-none sm:mt-0 sm:shadow-sm">
|
||||
@@ -171,6 +176,7 @@ const content = marked.parse(post.content);
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style is:inline>
|
||||
code[data-theme*=' '],
|
||||
code[data-theme*=' '] span {
|
||||
@@ -184,6 +190,7 @@ const content = marked.parse(post.content);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -3,11 +3,12 @@ import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import BlogSelectedArticles from '@components/blog/BlogSelectedArticles.astro';
|
||||
import BlogRecentArticles from '@components/blog/BlogRecentArticles.astro';
|
||||
import HeroSection from '@components/sections/HeroSection.astro';
|
||||
import SelectedPostsSection from '@components/sections/SelectedPostsSection.astro';
|
||||
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
import blogImg from '@images/autumn_tree.png';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
@@ -18,10 +19,11 @@ const posts = await directus.request(
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
const selectedPosts: Post[] = posts.filter((p) => p.selected).slice(0, 4);
|
||||
|
||||
const selectedPosts: Post[] = posts.filter((p) => p.selected).slice(0, 3);
|
||||
const recentPosts: Post[] = posts.filter(
|
||||
(p) => !selectedPosts.some((selected) => selected.slug === p.slug)
|
||||
).slice(0, 6);
|
||||
).slice(0, 9);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -43,10 +45,21 @@ const recentPosts: Post[] = posts.filter(
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HeroSection title="Blog" subTitle={global.about_blog} src={blogImg} alt={global.blog_image_alt} />
|
||||
|
||||
<BlogSelectedArticles posts={selectedPosts} />
|
||||
<BlogRecentArticles posts={recentPosts} />
|
||||
<HeroSection
|
||||
title="Blog"
|
||||
subTitle={global.about_blog}
|
||||
src={blogImg}
|
||||
alt={global.blog_image_alt}
|
||||
/>
|
||||
|
||||
<SelectedPostsSection posts={selectedPosts} />
|
||||
|
||||
<RecentPostsSection
|
||||
posts={recentPosts}
|
||||
title="Recent Posts"
|
||||
/>
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
import { getCollection } from 'astro:content';
|
||||
import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import BlogCard from '@components/blog/BlogCard.astro';
|
||||
|
||||
import BlogCard from '@components/cards/BlogCard.astro';
|
||||
import HeaderSection from '@components/sections/HeaderSection.astro';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import directus from '@lib/directus';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const categories = await getCollection('categories');
|
||||
@@ -26,6 +27,7 @@ const posts = await directus.request(
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const categoriesPosts = posts
|
||||
.sort((a: Post, b: Post) => b.published_date.valueOf() - a.published_date.valueOf())
|
||||
.filter((b) => {
|
||||
@@ -51,6 +53,7 @@ const categoriesPosts = posts
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
<HeaderSection
|
||||
title={category.data.title}
|
||||
subTitle={category.data.description}
|
||||
@@ -59,9 +62,12 @@ const categoriesPosts = posts
|
||||
btnURL="/categories"
|
||||
/>
|
||||
|
||||
<section class="mx-auto mt-10 mb-10 max-w-[85rem] px-4 py-8 sm:px-6 lg:px-8 2xl:max-w-full">
|
||||
<section class="max-w-340 2xl:max-w-full mx-auto mt-10 mb-10 px-4 py-8 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{categoriesPosts.map((b) => <BlogCard post={b} />)}
|
||||
{categoriesPosts.map((b) =>
|
||||
<BlogCard post={b} />
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
@@ -1,78 +1,14 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import BlogCategoryCard from '@components/blog/BlogCategoryCard.astro';
|
||||
import HeroSection from '@components/sections/HeroSection.astro';
|
||||
import { timeago } from '@support/time';
|
||||
import CategorySection from '@components/sections/CategorySection.astro';
|
||||
|
||||
import categoryImg from '@images/autumn_bench.png';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
filter: { published: { _eq: true } },
|
||||
fields: ['*'],
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const postMap: Map<string, Post[]> = posts
|
||||
.sort((a: Post, b: Post) => b.published_date.valueOf() - a.published_date.valueOf())
|
||||
.reduce((acc, obj) => {
|
||||
let posts = acc.get(obj.category);
|
||||
if (!posts) {
|
||||
posts = [];
|
||||
}
|
||||
posts.push(obj);
|
||||
|
||||
acc.set(obj.category, posts);
|
||||
|
||||
return acc;
|
||||
}, new Map<string, Post[]>());
|
||||
|
||||
const layoutPattern = [
|
||||
{ col: 2, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
];
|
||||
|
||||
const categories = (await getCollection('categories'))
|
||||
.sort((a, b) => {
|
||||
const aCount = postMap.get(a.slug)?.length ?? 0;
|
||||
const bCount = postMap.get(b.slug)?.length ?? 0;
|
||||
return bCount - aCount;
|
||||
})
|
||||
.map((c, index) => {
|
||||
const posts = postMap.get(c.slug);
|
||||
const pattern = layoutPattern[index % layoutPattern.length];
|
||||
const smColSpan = Math.min(pattern.col, 2);
|
||||
const mdColSpan = Math.min(pattern.col, 4);
|
||||
const rowSpan = pattern.row;
|
||||
const rowSpanClass = rowSpan > 1 ? `row-span-${rowSpan}` : 'row-span-1';
|
||||
const gridItemClass = `col-span-${smColSpan} md:col-span-${mdColSpan} ${rowSpanClass} smooth-reveal-cards rounded-xl transition-all duration-300 shadow-xs hover:shadow-md dark:shadow-md dark:hover:shadow-lg border border-stone-200/50 dark:border-stone-700/50`;
|
||||
return {
|
||||
...c,
|
||||
posts,
|
||||
gridItemClass,
|
||||
layoutPattern: {
|
||||
smCol: smColSpan,
|
||||
mdCol: mdColSpan,
|
||||
row: rowSpan,
|
||||
index,
|
||||
},
|
||||
};
|
||||
});
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -94,6 +30,7 @@ const categories = (await getCollection('categories'))
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
<HeroSection
|
||||
title="Categories"
|
||||
subTitle={global.about_categories}
|
||||
@@ -101,28 +38,8 @@ const categories = (await getCollection('categories'))
|
||||
alt={global.categories_image_alt}
|
||||
/>
|
||||
|
||||
<section class="mx-auto px-4 py-10 sm:px-6 lg:px-8 lg:py-14 lg:pt-10 2xl:max-w-full">
|
||||
<div class="grid grid-flow-row-dense grid-cols-2 gap-4 md:grid-cols-4">
|
||||
{
|
||||
categories.map((category) => {
|
||||
return (
|
||||
<div
|
||||
class={category.gridItemClass}
|
||||
style={category.layoutPattern.row > 1 ? 'grid-row: span 2 / span 2;' : ''}
|
||||
>
|
||||
<BlogCategoryCard
|
||||
slug={category.slug}
|
||||
title={category.data.title}
|
||||
description={category.data.description}
|
||||
count={postMap.get(category.slug)?.length ?? 0}
|
||||
publishDate={timeago(postMap.get(category.slug)?.[0]?.published_date)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
<CategorySection />
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
---
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
import { readSingleton, readItems } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import HeroSection from '@components/sections/HeroSection.astro';
|
||||
import FeaturesSection from '@components/sections/FeaturesSection.astro';
|
||||
import FeatureSection from '@components/sections/FeatureSection.astro';
|
||||
import WeatherSection from '@components/sections/WeatherSection.astro';
|
||||
import LatestPostsSection from '@components/sections/LatestPostsSection.astro';
|
||||
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
||||
import GiteaSection from '@components/sections/GiteaSection.astro';
|
||||
|
||||
import homeImg from '@images/autumn_mountain.png';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
const weather = await directus.request(readSingleton('site_weather'));
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
filter: { published: { _eq: true } },
|
||||
fields: ['*'],
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const recentPosts = posts
|
||||
.sort((a: Post, b: Post) => (new Date(b.published_date).getTime()) - (new Date(a.published_date).getTime()))
|
||||
.slice(0, 3);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -34,6 +47,7 @@ const weather = await directus.request(readSingleton('site_weather'));
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
<HeroSection
|
||||
title={`Hello, I'm <span class="text-steel dark:text-steel">Alex Lebens</span>`}
|
||||
subTitle={global.about_description}
|
||||
@@ -43,24 +57,28 @@ const weather = await directus.request(readSingleton('site_weather'));
|
||||
alt={global.home_image_alt}
|
||||
/>
|
||||
|
||||
<FeaturesSection />
|
||||
<FeatureSection />
|
||||
|
||||
<WeatherSection
|
||||
server:defer
|
||||
latitude={weather.latitude}
|
||||
longitude={weather.longitude}
|
||||
latitude={weather.latitude}
|
||||
longitude={weather.longitude}
|
||||
cityName={weather.location}
|
||||
timezone={weather.timezone}
|
||||
>
|
||||
</WeatherSection>
|
||||
/>
|
||||
|
||||
<LatestPostsSection />
|
||||
<RecentPostsSection
|
||||
posts={recentPosts}
|
||||
title="Latest Posts"
|
||||
subTitle="Checkout my most recent thoughts here"
|
||||
/>
|
||||
|
||||
<GiteaSection
|
||||
title="Follow me on Gitea"
|
||||
subTitle="I love open source and have my code availabile on my Gitea server."
|
||||
url="https://gitea.alexlebens.dev"
|
||||
/>
|
||||
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
@utility button-bg-teal {
|
||||
@apply transition-all duration-300
|
||||
bg-bermuda hover:bg-turquoise dark:bg-turquoise dark:hover:bg-bermuda
|
||||
bg-bermuda hover:bg-turquoise group-hover:bg-turquoise dark:bg-turquoise dark:hover:bg-bermuda dark:group-hover:bg-bermuda
|
||||
}
|
||||
|
||||
@utility button-bg-neutral {
|
||||
@@ -53,12 +53,20 @@
|
||||
|
||||
/* Card classes */
|
||||
@utility card-base {
|
||||
@apply rounded-xl
|
||||
@apply transition-all duration-300
|
||||
rounded-xl
|
||||
border border-neutral-100 dark:border-stone-500/20
|
||||
bg-neutral-100/80 hover:bg-neutral-100 dark:bg-neutral-800/60 dark:hover:bg-neutral-800/90
|
||||
shadow-xs hover:shadow-md dark:shadow-md dark:hover:shadow-lg
|
||||
}
|
||||
|
||||
@utility card-base-hidden {
|
||||
@apply transition-all duration-300
|
||||
rounded-xl
|
||||
border border-transparent
|
||||
hover:bg-neutral-400/20 dark:hover:bg-neutral-800/40
|
||||
}
|
||||
|
||||
@utility card-hover-icon-color {
|
||||
@apply transition-all duration-300
|
||||
text-primary
|
||||
@@ -79,9 +87,8 @@
|
||||
|
||||
@utility card-text-header-minor {
|
||||
@apply text-header
|
||||
md:text-3xl
|
||||
text-2xl
|
||||
font-semibold
|
||||
text-2xl md:text-3xl
|
||||
font-semibold leading-tight tracking-tight text-balance
|
||||
}
|
||||
|
||||
@utility card-text-header-description {
|
||||
@@ -95,6 +102,12 @@
|
||||
font-bold
|
||||
}
|
||||
|
||||
@utility card-text-title-major {
|
||||
@apply text-header
|
||||
text-4xl md:text-3xl
|
||||
font-bold leading-tight tracking-tight text-balance
|
||||
}
|
||||
|
||||
@utility card-hover-text-title {
|
||||
@apply transition-all duration-300
|
||||
group-hover:text-main
|
||||
|
||||
Reference in New Issue
Block a user