Compare commits
No commits in common. "003ad9395b975b845d6dd59313ab47427a87a46a" and "8b66bdaab9615b2461d408911507fc5a5046edcc" have entirely different histories.
003ad9395b
...
8b66bdaab9
6
SETUP.md
|
@ -3,9 +3,9 @@
|
|||
## Quick Start
|
||||
```bash
|
||||
# Clone and initialize the blog repository
|
||||
git clone https://gitea.argobox.com/InovinLabs/argobox.git # Updated URL
|
||||
cd argobox # Updated directory name
|
||||
# ./scripts/init-blog-repo.sh # This script might need review/removal depending on its purpose
|
||||
git clone https://git.argobox.com/KeyArgo/laforceit-blog.git
|
||||
cd laforceit-blog
|
||||
./scripts/init-blog-repo.sh
|
||||
```
|
||||
|
||||
## What This Does
|
||||
|
|
|
@ -3,19 +3,19 @@ import { defineConfig } from 'astro/config';
|
|||
import mdx from '@astrojs/mdx';
|
||||
import sitemap from '@astrojs/sitemap';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import cloudflare from '@astrojs/cloudflare'; // Import cloudflare adapter
|
||||
// import cloudflare from '@astrojs/cloudflare'; // Commented out for local development
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://argobox.com', // Keep original site URL
|
||||
site: 'https://argobox.com', // Updated site URL for ArgoBox
|
||||
output: 'static',
|
||||
adapter: cloudflare(), // Enable cloudflare adapter
|
||||
// adapter: cloudflare(), // Commented out for local development
|
||||
integrations: [
|
||||
mdx(),
|
||||
sitemap(),
|
||||
tailwind(),
|
||||
],
|
||||
markdown: { // Add markdown config
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
theme: 'one-dark-pro',
|
||||
wrap: true
|
||||
|
@ -24,7 +24,7 @@ export default defineConfig({
|
|||
rehypePlugins: []
|
||||
},
|
||||
compressHTML: false, // Disable HTML compression to avoid parsing errors
|
||||
build: { // Add build format
|
||||
format: 'file',
|
||||
build: {
|
||||
format: 'file', // Use 'file' instead of 'directory' format
|
||||
}
|
||||
});
|
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"name": "argobox-astro",
|
||||
"name": "laforceit-blog",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "argobox-astro",
|
||||
"name": "laforceit-blog",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.5.0",
|
||||
"@astrojs/mdx": "4.2.4",
|
||||
"@astrojs/rss": "4.0.11",
|
||||
"@astrojs/sitemap": "3.3.0",
|
||||
"@astrojs/tailwind": "6.0.2",
|
||||
"astro": "5.7.4",
|
||||
"@astrojs/cloudflare": "latest",
|
||||
"@astrojs/mdx": "latest",
|
||||
"@astrojs/rss": "latest",
|
||||
"@astrojs/sitemap": "latest",
|
||||
"@astrojs/tailwind": "latest",
|
||||
"astro": "latest",
|
||||
"nodemailer": "^6.10.1",
|
||||
"resend": "^4.4.1",
|
||||
"tailwindcss": "3.4.17"
|
||||
"tailwindcss": "^3.0.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16"
|
||||
|
@ -280,9 +280,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workerd-darwin-64": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250424.0.tgz",
|
||||
"integrity": "sha512-E+9tyQfwKwg7iz+vI50UeF9m9MhO6uCTnn6VPBTobhgi0rKcfmCteUGz6YJejG6ex9OIfFHg/tIcr1+ywGZtiA==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250417.0.tgz",
|
||||
"integrity": "sha512-4Adfl92aKepjxb8e6af2d+xpD2sBOADgHqvkyXsFmoLb80weMEDDRGJi1p1m5q1M78/oVnGcpdmuRCAathanRg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -296,9 +296,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workerd-darwin-arm64": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250424.0.tgz",
|
||||
"integrity": "sha512-5vReSs+Gx4vPNR3zoU3a7BVBoTEc7aoe2gGcaxSSQKMOvVkp3bo9poOGZbISodhYnCCRXltZcl8Vgyi0l/YZLA==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250417.0.tgz",
|
||||
"integrity": "sha512-dSlk18F4i3T1OTzFBxx3pKpXRMP6w2xZ26+oIV32BFWrCi/HxGzUd6gVA0q37oLGqITRt8xU693J4Gl1CwC/Ag==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -312,9 +312,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workerd-linux-64": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250424.0.tgz",
|
||||
"integrity": "sha512-8kBNy7LpW/E4XKGrx/1Xql3Hfy8viDb+tFudu+sN/b6A2tNczNoOzDyNeWeWa99/zfyzncah1l0Wl2RBmVvY+Q==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250417.0.tgz",
|
||||
"integrity": "sha512-27MVzOa/lENcqewC2L9EcqstXW843UhjBMcwV1umDfsjwLyZOEv6Gtm/6j5r0L0gASvkRTam3fAmtPk/gt48TA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -328,9 +328,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workerd-linux-arm64": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250424.0.tgz",
|
||||
"integrity": "sha512-R4wLZNobQo5K96e3BEaTwCbZhyspeoW81k/yrkSRseLpSoIpLNguw6ckk5sGCjUkXEZQyu9TG6PzdYqlQo70gw==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250417.0.tgz",
|
||||
"integrity": "sha512-34qBk0htAXmUneOTQxW6/g6pjNVR91r0vJzz2FID84cAIOYVl4hZLijkjmVl+MMDU6boXUs+yDwhItdg06YvAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -344,9 +344,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workerd-windows-64": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250424.0.tgz",
|
||||
"integrity": "sha512-uwzZhNaKjJKq6NGFPd0hQWecpf5OTZCrlWKQZm4kkufZ7uIzkn5t3kOjh/J3L9puM/GvIPxCiDUE2aG66P6YxA==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250417.0.tgz",
|
||||
"integrity": "sha512-PDwATFioff+geVHfgTzSWsxgwjgotrdXStb0EL0lMyMT5zNmHArAnOx83CbDtud63Uv9rVX1BAfPP4tyD1O+5A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -360,9 +360,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workers-types": {
|
||||
"version": "4.20250428.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20250428.0.tgz",
|
||||
"integrity": "sha512-r/K1xuR+lW6SeGKRloVdR+BnK+9shBQci717070EBB2VLbcrZCCh0eo6NweLFa1rD8use5rE5JTVDZ/mXqMeNg==",
|
||||
"version": "4.20250423.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20250423.0.tgz",
|
||||
"integrity": "sha512-uzy7fvgYIs9YCEaPScC+RnZvd+yJJCqLCEe/n/6p2PZTxWbDmiZjtJQiP5Zx6G0p64ZD/0ZRmtALfDZDNYBDHg==",
|
||||
"license": "MIT OR Apache-2.0"
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
|
@ -1406,9 +1406,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz",
|
||||
"integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
|
||||
"integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1419,9 +1419,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz",
|
||||
"integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
|
||||
"integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1432,9 +1432,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz",
|
||||
"integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
|
||||
"integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1445,9 +1445,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz",
|
||||
"integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
|
||||
"integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1458,9 +1458,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz",
|
||||
"integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
|
||||
"integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1471,9 +1471,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz",
|
||||
"integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
|
||||
"integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1484,9 +1484,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz",
|
||||
"integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
|
||||
"integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1497,9 +1497,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz",
|
||||
"integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
|
||||
"integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1510,9 +1510,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1523,9 +1523,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz",
|
||||
"integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
|
||||
"integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1536,9 +1536,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
|
@ -1549,9 +1549,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
@ -1562,9 +1562,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -1575,9 +1575,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz",
|
||||
"integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
|
||||
"integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -1588,9 +1588,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
@ -1601,9 +1601,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz",
|
||||
"integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
|
||||
"integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1614,9 +1614,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz",
|
||||
"integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
|
||||
"integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1627,9 +1627,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz",
|
||||
"integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
|
||||
"integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1640,9 +1640,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz",
|
||||
"integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
|
||||
"integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -1653,9 +1653,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz",
|
||||
"integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
|
||||
"integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1834,9 +1834,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz",
|
||||
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
|
||||
"version": "22.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
|
||||
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
|
@ -2890,9 +2890,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.143",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.143.tgz",
|
||||
"integrity": "sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==",
|
||||
"version": "1.5.140",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz",
|
||||
"integrity": "sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
|
@ -2901,6 +2901,12 @@
|
|||
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex-xs": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz",
|
||||
"integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz",
|
||||
|
@ -3374,19 +3380,19 @@
|
|||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/h3": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.3.tgz",
|
||||
"integrity": "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ==",
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.1.tgz",
|
||||
"integrity": "sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie-es": "^1.2.2",
|
||||
"crossws": "^0.3.4",
|
||||
"crossws": "^0.3.3",
|
||||
"defu": "^6.1.4",
|
||||
"destr": "^2.0.5",
|
||||
"destr": "^2.0.3",
|
||||
"iron-webcrypto": "^1.2.1",
|
||||
"node-mock-http": "^1.0.0",
|
||||
"radix3": "^1.1.2",
|
||||
"ufo": "^1.6.1",
|
||||
"ufo": "^1.5.4",
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
|
@ -5144,9 +5150,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/miniflare": {
|
||||
"version": "4.20250424.1",
|
||||
"resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20250424.1.tgz",
|
||||
"integrity": "sha512-CqBzp8DPO76DLRBSx5/1GM200B5SbfpkNA9n/IxFGY7n6YNc1ypPYy/J0tQqj7vOA62jyD/3kPVbUXxbPKe5SQ==",
|
||||
"version": "4.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20250417.0.tgz",
|
||||
"integrity": "sha512-bROKLQKr4CoS93tnGuw5e08VaNwM3VowTL3Z2Cps1HzY6a4Bq8uNtggQ7WogriMq77jcHn6kbz64bvWyF//Jkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "0.8.1",
|
||||
|
@ -5156,7 +5162,7 @@
|
|||
"glob-to-regexp": "0.4.1",
|
||||
"stoppable": "1.1.0",
|
||||
"undici": "^5.28.5",
|
||||
"workerd": "1.20250424.0",
|
||||
"workerd": "1.20250417.0",
|
||||
"ws": "8.18.0",
|
||||
"youch": "3.3.4",
|
||||
"zod": "3.22.3"
|
||||
|
@ -5389,18 +5395,19 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/oniguruma-parser": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.0.tgz",
|
||||
"integrity": "sha512-fD9o5ebCmEAA9dLysajdQvuKzLL7cj+w7DQjuO3Cb6IwafENfx6iL+RGkmyW82pVRsvgzixsWinHvgxTMJvdIA==",
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.11.2.tgz",
|
||||
"integrity": "sha512-F7Ld4oDZJCI5/wCZ8AOffQbqjSzIRpKH7I/iuSs1SkhZeCj0wS6PMZ4W6VA16TWHrAo0Y9bBKEJOe7tvwcTXnw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/oniguruma-to-es": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.1.tgz",
|
||||
"integrity": "sha512-VtX1kepWO+7HG7IWV5v72JhiqofK7XsiHmtgnvurnNOTdIvE5mrdWYtsOrQyrXCv1L2Ckm08hywp+MFO7rC4Ug==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.2.0.tgz",
|
||||
"integrity": "sha512-MDPs6KSOLS0tKQ7joqg44dRIRZUyotfTy0r+7oEEs6VwWWP0+E2PPDYWMFN0aqOjRyWHBYq7RfKw9GQk2S2z5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"oniguruma-parser": "^0.12.0",
|
||||
"emoji-regex-xs": "^1.0.0",
|
||||
"oniguruma-parser": "^0.11.0",
|
||||
"regex": "^6.0.1",
|
||||
"regex-recursion": "^6.0.2"
|
||||
}
|
||||
|
@ -6307,9 +6314,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz",
|
||||
"integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
|
||||
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
|
@ -6322,26 +6329,26 @@
|
|||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.40.1",
|
||||
"@rollup/rollup-android-arm64": "4.40.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.40.1",
|
||||
"@rollup/rollup-darwin-x64": "4.40.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.40.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.40.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.40.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.40.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.40.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.40.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.40.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.40.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.40.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.40.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.40.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.40.0",
|
||||
"@rollup/rollup-android-arm64": "4.40.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.40.0",
|
||||
"@rollup/rollup-darwin-x64": "4.40.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.40.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.40.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.40.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.40.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.40.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.40.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.40.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.40.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.40.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.40.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.40.0",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
@ -6536,9 +6543,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/smol-toml": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz",
|
||||
"integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==",
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.3.tgz",
|
||||
"integrity": "sha512-KMVLNWu490KlNfD0lbfDBUktJIEaZRBj1eeK0SMfdpO/rfyARIzlnPVI1Ge4l0vtSJmQUAiGKxMyLGrCT38iyA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
|
@ -6945,9 +6952,9 @@
|
|||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.40.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.1.tgz",
|
||||
"integrity": "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==",
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz",
|
||||
"integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
|
@ -7205,19 +7212,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/unstorage": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.16.0.tgz",
|
||||
"integrity": "sha512-WQ37/H5A7LcRPWfYOrDa1Ys02xAbpPJq6q5GkO88FBXVSQzHd7+BjEwfRqyaSWCv9MbsJy058GWjjPjcJ16GGA==",
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.15.0.tgz",
|
||||
"integrity": "sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "^3.1.3",
|
||||
"chokidar": "^4.0.3",
|
||||
"destr": "^2.0.5",
|
||||
"h3": "^1.15.2",
|
||||
"destr": "^2.0.3",
|
||||
"h3": "^1.15.0",
|
||||
"lru-cache": "^10.4.3",
|
||||
"node-fetch-native": "^1.6.6",
|
||||
"ofetch": "^1.4.1",
|
||||
"ufo": "^1.6.1"
|
||||
"ufo": "^1.5.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@azure/app-configuration": "^1.8.0",
|
||||
|
@ -7226,7 +7233,7 @@
|
|||
"@azure/identity": "^4.6.0",
|
||||
"@azure/keyvault-secrets": "^4.9.0",
|
||||
"@azure/storage-blob": "^12.26.0",
|
||||
"@capacitor/preferences": "^6.0.3 || ^7.0.0",
|
||||
"@capacitor/preferences": "^6.0.3",
|
||||
"@deno/kv": ">=0.9.0",
|
||||
"@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0",
|
||||
"@planetscale/database": "^1.19.0",
|
||||
|
@ -7403,17 +7410,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.3.tgz",
|
||||
"integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==",
|
||||
"version": "6.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.2.tgz",
|
||||
"integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"fdir": "^6.4.3",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
"tinyglobby": "^0.2.12"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
|
@ -7560,9 +7567,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/workerd": {
|
||||
"version": "1.20250424.0",
|
||||
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250424.0.tgz",
|
||||
"integrity": "sha512-3Nb69De9pfC21vLMW8Xpp5JXEPYd7e8MGcaEfo/6z1jOX9CFJVaqrAXr8RwYxDgN528ZahHqM51YQEcVlOu1Cw==",
|
||||
"version": "1.20250417.0",
|
||||
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250417.0.tgz",
|
||||
"integrity": "sha512-naz6oJiVODd3/Lkp9l3vtc56HKOOvx+AWDvEsTa5eSfi5SI9V0HYpLYSPblAwrfazbQ4ff1Vl3jkTl/5JxqCAA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
@ -7572,27 +7579,27 @@
|
|||
"node": ">=16"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@cloudflare/workerd-darwin-64": "1.20250424.0",
|
||||
"@cloudflare/workerd-darwin-arm64": "1.20250424.0",
|
||||
"@cloudflare/workerd-linux-64": "1.20250424.0",
|
||||
"@cloudflare/workerd-linux-arm64": "1.20250424.0",
|
||||
"@cloudflare/workerd-windows-64": "1.20250424.0"
|
||||
"@cloudflare/workerd-darwin-64": "1.20250417.0",
|
||||
"@cloudflare/workerd-darwin-arm64": "1.20250417.0",
|
||||
"@cloudflare/workerd-linux-64": "1.20250417.0",
|
||||
"@cloudflare/workerd-linux-arm64": "1.20250417.0",
|
||||
"@cloudflare/workerd-windows-64": "1.20250417.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrangler": {
|
||||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.13.2.tgz",
|
||||
"integrity": "sha512-CryA3MRzjNceFVef78ymqhxXrIYQoYKQIPITvvd/Yn3SX4UAADZOOrztatNcgRAyXssjdGH4JRw7fKoSnOaOog==",
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.12.1.tgz",
|
||||
"integrity": "sha512-jYrz8y2ffhsRqvQLO2dXFi9HLvPUJk3jn7U71GWfBBCHm0I6r2ik7Vs9ajpRcTGlbNw1RY0uIHVJBVR/7bEN5A==",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"dependencies": {
|
||||
"@cloudflare/kv-asset-handler": "0.4.0",
|
||||
"@cloudflare/unenv-preset": "2.3.1",
|
||||
"blake3-wasm": "2.1.5",
|
||||
"esbuild": "0.25.2",
|
||||
"miniflare": "4.20250424.1",
|
||||
"miniflare": "4.20250417.0",
|
||||
"path-to-regexp": "6.3.0",
|
||||
"unenv": "2.0.0-rc.15",
|
||||
"workerd": "1.20250424.0"
|
||||
"workerd": "1.20250417.0"
|
||||
},
|
||||
"bin": {
|
||||
"wrangler": "bin/wrangler.js",
|
||||
|
@ -7606,7 +7613,7 @@
|
|||
"sharp": "^0.33.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20250424.0"
|
||||
"@cloudflare/workers-types": "^4.20250417.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@cloudflare/workers-types": {
|
||||
|
|
16
package.json
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "argobox-astro",
|
||||
"name": "laforceit-blog",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
|
@ -9,15 +9,15 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.5.0",
|
||||
"@astrojs/mdx": "4.2.4",
|
||||
"@astrojs/rss": "4.0.11",
|
||||
"@astrojs/sitemap": "3.3.0",
|
||||
"@astrojs/tailwind": "6.0.2",
|
||||
"astro": "5.7.4",
|
||||
"@astrojs/cloudflare": "latest",
|
||||
"@astrojs/mdx": "latest",
|
||||
"@astrojs/rss": "latest",
|
||||
"@astrojs/sitemap": "latest",
|
||||
"@astrojs/tailwind": "latest",
|
||||
"astro": "latest",
|
||||
"nodemailer": "^6.10.1",
|
||||
"resend": "^4.4.1",
|
||||
"tailwindcss": "3.4.17"
|
||||
"tailwindcss": "^3.0.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16"
|
||||
|
|
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,9 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
After Width: | Height: | Size: 749 B |
Before Width: | Height: | Size: 104 KiB |
|
@ -0,0 +1 @@
|
|||
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCABAAIADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKACiiigAooooAKKKKACiiigAorH8Y+MdH8DaRLqWt6nY6PpluAZ7y/uEt7eEE4G+R2CqM9MkDNfOPx3/AOCt/wAFvhPdXFnJ4ys/EGoxlkjs/DsL37sR6soWEeu6ZW9qAPpeivgHXf8AgrT4nv8AxDLpujfCS61HTwcJfS6zNazjP8bQLZTBlHbcN3WvMPGH/BZ3xlcSyx+Gvh5pVn5RKrJq2oT3HL9SsQtgV4+6d2e9AH6F/Gj44eFvgJ4JuPEXizV7fRdIhkSFZpAzO8jsAFREBZ2JIAAAJJHv18x+F/8AgqX8KfFfiGz0uPU9Us7q9lEMU2oaFe2lsGPTfM8YjQY7yMoycZAJFfnd8U/jl8Qv2hdQ87xV4q1XW7GcmS1tJ5/KsR/dhgTCKRnoQDgc5ry7WNXS2UbGywUFztyAT3Jzzn+lAH9H+k6pa61p8N5ZzxXlncIJIpreQSRyKRkFWUkMD6EVPXwD/wAEh/jnqOrXGq+AtWupL6yt7dNR02aViXgQuskiAnkDcHwPRwOmK++aACiiigAooooAKKKKACvI/wBpz9rHwX+zD4ca91+9aXULiPfZaRZESX14OwRCRtTIBLsFUZ6kkA+uV+bP7UF/N+07+0lqlxbyFtKhuJIYPlyqWsSny/woGwvGdzkscmgDpvit/wAFNPiB8TI5YvDceneELA/LHLBCLrUZPRvNf5ExzjbHGcfxGvnXWdWvfEGotdX93cX93KAHmuZmllfHbcxyeB7/AErOTQY7eXft+Vdwww5BIwOB0B7jPervh7Ql1jWvJkb5TncVyDsHXA7ZwQCeOv0oA5/UpRGRFEGxyNmcDjqT9O30p9jpdxeXCxwRySO/AVBn8/T/APXXvNn8P9NigZYdOhMgwySPl2HHJDMc5+o49sVoQ+HbaJVX7PCoXJGIgMnBGeD3z+VSpsrlOCPL/D3wuuLaaNZreSSRyNwVSFX1z7fXB7ZzXrfhvwFc2JWTy2ji6KWUgj6Ajg+x59K6bRbGKLBjWP5ecCIHnrz6Y/l7V0Vrb71VchvU46Y9+MdfpUOpJkxopHOaH4eElu0Yjhj3LjBQY9D06H37fTnlv2atZn+B37Wfgm9h3Nb6hew6fOoOcxzkRZBx1BkTOMdO9eo6FY7djtAyY+YbCQwGexGeORkVyPx48Iv4q8H2ur20bS32hyi5TZ96SLOJFx6qu8gdtoHvVRlcbR+p9FYvgDxnb+O/A+ja9a7/ACNWsYL6LcMNtkjWRcj0O4VtVRIUUUUAFFFFABX5bfteeEvEXgf426ja6kZLiO6aWS3vQMLdRsSGDD+E4IKnqOCMMpx+pNcf8dPhLY/Gj4Y6toV1tSa4jL2tw6bvs9yo3RyAdSAwww/iVmGRmgD8sdN0+bUJ1WFZHkY5VQM7vbA6mvZPBHw7ijsnmvIlkknXeI+uF4HUdMAfzruPh7+zlNoWrTR3Fq9vcK5ErBgJOP73HzDHbjHSvXvDvwUW/wBMWTaMYBEecHdng5PQ+nH0PeoY0eU+BvBNxJcRlo9ix4AVQFwPZQAMDPsK9o8OeE4okUNGFVRnkYb6evTHPtxXc+GPg3b2e3zE24xnYpBx3x9Pp0rd1HwhHZWrNGvzAZHG7PoMetJ6DR50mi/ZmZnbyyyhdoUqGI6dOh6/h+VEulP5O7btZt2OcgY4HH4V0d5pTWzKdo27iMhhnkY6dCe351mzxKDjaoTg85wMdTk9KmwGfJ5i4X5V2nI6jH8umOD7da4H4y6QniD4da1CNu5baScZGQXtw0y/+QxXpl1aGRTtKsVGMg//AFqqmCOaIwyIsse4hlPVXQncD7gqQfqKpCZ5t+xh8SJvFnwjl0e6kaS88O3BtgW+9JbSfPC3pxlx9EFe111P7K/gC5+H3we+yx/ubrUWN9dJn/VNJgJGf9pI0jU+6muWrbkCiiikAUUUUAFFFFAHhH7YHwcj8XeHj4ksYFGraSgNwUXDXNuDg5x1KElfoWxnbzg/hF8fLjwzeR6fdzNNBOyqyP8Ae4Gc47HtnPQD3I/TuvlD9qH9lddS1abxJocYjulYzXltENqSrzukT0cZJI7gkHndjzsNbldzow83J8sj3P4ZfG601nTI8OskbKu5JBuVh3B9P0r1fRfiCt9b7lLbh1z1H+fw+or8xNC8Wa18MNbhmtpJFUOA8bNmOVScgg/hzX0N4G+OcN1bxs0jNIADJG5wy5HX+h9wazlTa2LVSMtGfV9/rkdy5kb5pOcZ/wD1d6pXl4u0/MWYdeDj3//XxXkWh/F+3vYY2jm3Y6g88Ht9e3QdK3o/Ho8tflYL94/Nz/n86i7NIxdrt2OrvAJFba3yqN2DnJ96yri5aGRlAZcfMNowSep9x+FZMvjpYtzbvl6q24kevHrWfeeNY4wrNIHyecHAHua0i2c1SSN9tTCx8MCw3dMEHsR7dv8AGsa2mmS7/dv5cyK2CF2hieOQM8/j0/Osm68Yx6hKy75G29H/AMMj86h0vxR9mvGlhbejR7cE5yOnPseK1S1Mmz7Q+GPhweFfAmkabuWR9PsobdpE+7IY41Usp9CQSPaugoooNCkFFFFAgooooAKKKKACiiigDH8VeB9H8Z2n2fVtNs9St/4UuoFk2H1U4O0+6kGvHfFf7Cuhak7zaVqF3pMjZIiY/aYc9wA21lHsWb/dHavdqKAPjjxp+x94i8P3DfYbCS+iVsbI3EM49MJJgMfZWPGBk15Z4k+CniSNW3aHdSRgFnEUfmKwxwAEJAGMnjAwRntX6HZGM1BdWUV9D5c0SSxtw0cihlYehB60XYrI/OG/8Iahp0zeY11as+Su+Jo2HPbcAD07E844qZLW4W2aSaG4dOSRsdmJ+gBP5V9++IfhH4X8SCSOS0FlNztuLQiNh7nGFYehBrx3xT+x7d2Lc2kbr03QyhkPqdk21hjtljx6UlMd0fJQsZbyRWjjboc71O32HHOM/StLTdJlK42yMVOflGcH07/5+le06n+zdf2J33VtuUZxujUOvuI3UuPcHGf4cGsPUPg/HZYZ9PvLbPXzIfPGPUSL+6/HK5q+cxdI2v2XfDUmufEizkk3C10+N7qZs4BIIWNQO/ztuPspr7Rqj4V8K2fgzw7Z6TYo0dpaJ5a7xhm5JLMe5JJJPua0BRYQtQooopgFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFR3FvHcxNHLGssbjDI6hlYeoI6iiigCrL4X06b79haP8A71sivt61Avhfw9b/APHhpVqnH/LHYmPyGKKKaXYTbJYYEgXbGiRr2VFCgfgBUlFFMQUUUUAFFFFABRRRQAUUUUAf/9k=
|
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 2.5 MiB |
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1200" height="600" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#050a18;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#0d1529;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="1200" height="600" fill="url(#grad1)"/>
|
||||
<text x="600" y="250" font-family="Arial" font-size="50" fill="#e2e8f0" text-anchor="middle">K3s Kubernetes</text>
|
||||
<text x="600" y="320" font-family="Arial" font-size="30" fill="#3b82f6" text-anchor="middle">Lightweight Kubernetes for Edge and IoT</text>
|
||||
<g transform="translate(550,150) scale(0.6)">
|
||||
<path d="M 50,50 L 150,50 L 150,150 L 50,150 Z" fill="none" stroke="#06b6d4" stroke-width="10"/>
|
||||
<path d="M 75,75 L 175,75 L 175,175 L 75,175 Z" fill="none" stroke="#3b82f6" stroke-width="10"/>
|
||||
<path d="M 100,100 L 200,100 L 200,200 L 100,200 Z" fill="none" stroke="#8b5cf6" stroke-width="10"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 2.4 MiB |
|
@ -23,15 +23,14 @@ const categories = [
|
|||
{ name: 'Docker Compose', path: '/resources/docker-compose' },
|
||||
{ name: 'Configuration Files', path: '/resources/config-files' },
|
||||
{ name: 'Infrastructure Code', path: '/resources/iac' },
|
||||
{ name: 'Tutorials', path: '/resources/tutorials' },
|
||||
{ name: 'All Resources', path: '/resources' } // Added Resources link
|
||||
{ name: 'Tutorials', path: '/resources/tutorials' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Projects',
|
||||
links: [
|
||||
{ name: 'HomeLab Setup', path: '/homelab' },
|
||||
{ name: 'Tech Stack', path: '/tech-stack' }, // Updated Tech Stack link
|
||||
{ name: 'HomeLab Setup', url: 'https://argobox.com' },
|
||||
{ name: 'Tech Stack', url: 'https://argobox.com/#services' },
|
||||
{ name: 'Github Repos', path: '/projects/github' },
|
||||
{ name: 'Live Services', path: '/projects/services' },
|
||||
{ name: 'Obsidian Templates', path: '/projects/obsidian' }
|
||||
|
@ -48,12 +47,12 @@ const socialLinks = [
|
|||
},
|
||||
{
|
||||
name: 'Twitter',
|
||||
url: 'https://www.x.com/danlaforce', // Updated Twitter URL
|
||||
url: 'https://twitter.com/yourusername',
|
||||
icon: '<path d="M23.643 4.937c-.835.37-1.732.62-2.675.733a4.67 4.67 0 0 0 2.048-2.578 9.3 9.3 0 0 1-2.958 1.13 4.66 4.66 0 0 0-7.938 4.25 13.229 13.229 0 0 1-9.602-4.868c-.4.69-.63 1.49-.63 2.342A4.66 4.66 0 0 0 3.96 9.824a4.647 4.647 0 0 1-2.11-.583v.06a4.66 4.66 0 0 0 3.737 4.568 4.692 4.692 0 0 1-2.104.08 4.661 4.661 0 0 0 4.352 3.234 9.348 9.348 0 0 1-5.786 1.995 9.5 9.5 0 0 1-1.112-.065 13.175 13.175 0 0 0 7.14 2.093c8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602a9.47 9.47 0 0 0 2.323-2.41l.002-.003z" />'
|
||||
},
|
||||
{
|
||||
name: 'LinkedIn',
|
||||
url: 'https://www.linkedin.com/in/danlaforce', // Updated LinkedIn URL
|
||||
url: 'https://linkedin.com/in/yourusername',
|
||||
icon: '<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.225 0z" />'
|
||||
},
|
||||
{
|
||||
|
@ -116,11 +115,7 @@ const services = [
|
|||
{socialLinks.map(social => (
|
||||
<a href={social.url} class="social-link" aria-label={social.name} target="_blank" rel="noopener">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
{/* Render SVG paths conditionally based on name */}
|
||||
{social.name === 'GitHub' && <path fill-rule="evenodd" clip-rule="evenodd" d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385c.6.105.825-.255.825-.57c0-.285-.015-1.23-.015-2.235c-3.015.555-3.795-.735-4.035-1.41c-.135-.345-.72-1.41-1.23-1.695c-.42-.225-1.02-.78-.015-.795c.945-.015 1.62.87 1.845 1.23c1.08 1.815 2.805 1.305 3.495.99c.105-.78.42-1.305.765-1.605c-2.67-.3-5.46-1.335-5.46-5.925c0-1.305.465-2.385 1.23-3.225c-.12-.3-.54-1.53.12-3.18c0 0 1.005-.315 3.3 1.23c.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23c.66 1.65.24 2.88.12 3.18c.765.84 1.23 1.905 1.23 3.225c0 4.605-2.805 5.625-5.475 5.925c.435.375.81 1.095.81 2.22c0 1.605-.015 2.895-.015 3.3c0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />}
|
||||
{social.name === 'Twitter' && <path d="M23.643 4.937c-.835.37-1.732.62-2.675.733a4.67 4.67 0 0 0 2.048-2.578 9.3 9.3 0 0 1-2.958 1.13 4.66 4.66 0 0 0-7.938 4.25 13.229 13.229 0 0 1-9.602-4.868c-.4.69-.63 1.49-.63 2.342A4.66 4.66 0 0 0 3.96 9.824a4.647 4.647 0 0 1-2.11-.583v.06a4.66 4.66 0 0 0 3.737 4.568 4.692 4.692 0 0 1-2.104.08 4.661 4.661 0 0 0 4.352 3.234 9.348 9.348 0 0 1-5.786 1.995 9.5 9.5 0 0 1-1.112-.065 13.175 13.175 0 0 0 7.14 2.093c8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602a9.47 9.47 0 0 0 2.323-2.41l.002-.003z" />}
|
||||
{social.name === 'LinkedIn' && <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.225 0z" />}
|
||||
{social.name === 'RSS Feed' && <path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16M6 19a1 1 0 1 1 0-2 1 1 0 0 1 0 2z" />}
|
||||
<Fragment set:html={social.icon} />
|
||||
</svg>
|
||||
</a>
|
||||
))}
|
||||
|
@ -180,8 +175,6 @@ const services = [
|
|||
<span class="link-divider">|</span>
|
||||
<a href="/terms" class="meta-link">Terms of Use</a>
|
||||
<span class="link-divider">|</span>
|
||||
<a href="/contact" class="meta-link">Contact</a>
|
||||
<span class="link-divider">|</span>
|
||||
<a href="/sitemap.xml" class="meta-link">Sitemap</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ const navItems = [
|
|||
{ name: 'Home Lab', url: '/homelab' }, // Updated URL
|
||||
{ name: 'Resources', url: '/resources' },
|
||||
{ name: 'About', url: 'https://ArgoBox.com' },
|
||||
{ name: 'Contact', url: '/contact' }
|
||||
{ name: 'Contact', url: 'https://ArgoBox.com/index.html#contact' }
|
||||
];
|
||||
|
||||
// Get current URL path for active nav item highlighting
|
||||
|
|
|
@ -413,49 +413,6 @@ const nodeTypeCounts = {
|
|||
setTimeout(() => { loadingEl.classList.add('hidden'); }, 500);
|
||||
}
|
||||
|
||||
// --- Fullscreen Toggle Functionality ---
|
||||
if (fullscreenToggle) {
|
||||
fullscreenToggle.addEventListener('click', toggleFullscreen);
|
||||
}
|
||||
|
||||
// Toggle fullscreen function
|
||||
function toggleFullscreen() {
|
||||
isFullscreen = !isFullscreen;
|
||||
|
||||
if (isFullscreen) {
|
||||
// Enable fullscreen mode
|
||||
graphWrapper.classList.add('fullscreen');
|
||||
fullscreenEnterIcon.classList.add('hidden');
|
||||
fullscreenExitIcon.classList.remove('hidden');
|
||||
|
||||
// Hide the node details panel if it's visible
|
||||
if (nodeDetailsEl) nodeDetailsEl.classList.remove('active');
|
||||
|
||||
// In fullscreen, we adjust the cytoscape layout to fit
|
||||
setTimeout(() => {
|
||||
cy.resize();
|
||||
cy.fit(null, 30);
|
||||
}, 300); // Wait for transition to complete
|
||||
} else {
|
||||
// Disable fullscreen mode
|
||||
graphWrapper.classList.remove('fullscreen');
|
||||
fullscreenEnterIcon.classList.remove('hidden');
|
||||
fullscreenExitIcon.classList.add('hidden');
|
||||
|
||||
// Hide the full post content panel
|
||||
if (fullPostContent) {
|
||||
fullPostContent.classList.remove('active');
|
||||
// Ensure display is set back to none if needed, though CSS handles visibility
|
||||
// fullPostContent.style.display = 'none';
|
||||
}
|
||||
|
||||
// Reset the cytoscape layout
|
||||
setTimeout(() => {
|
||||
cy.resize();
|
||||
cy.fit(null, 30);
|
||||
}, 300); // Wait for transition to complete
|
||||
}
|
||||
}
|
||||
// --- Fullscreen Toggle Functionality ---
|
||||
if (fullscreenToggle) {
|
||||
fullscreenToggle.addEventListener('click', toggleFullscreen);
|
||||
|
@ -807,7 +764,6 @@ const nodeTypeCounts = {
|
|||
if (nodeDetailsEl) nodeDetailsEl.classList.remove('active');
|
||||
if (isFullscreen && fullPostContent) {
|
||||
fullPostContent.classList.remove('active');
|
||||
fullPostContent.style.display = 'none'; // Ensure display is none
|
||||
}
|
||||
cy.elements().removeClass('selected highlighted faded');
|
||||
}
|
||||
|
@ -820,17 +776,6 @@ const nodeTypeCounts = {
|
|||
cy.elements().removeClass('highlighted faded');
|
||||
});
|
||||
}
|
||||
// Close full post panel button
|
||||
if (closeFullPostBtn) {
|
||||
closeFullPostBtn.addEventListener('click', () => {
|
||||
if (fullPostContent) {
|
||||
fullPostContent.classList.remove('active');
|
||||
fullPostContent.style.display = 'none'; // Ensure display is none
|
||||
}
|
||||
cy.$(':selected').unselect();
|
||||
cy.elements().removeClass('highlighted faded');
|
||||
});
|
||||
}
|
||||
|
||||
// Close full post panel button
|
||||
if (closeFullPostBtn) {
|
||||
|
@ -2034,350 +1979,4 @@ const nodeTypeCounts = {
|
|||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
/* Fullscreen mode styles */
|
||||
.graph-container-wrapper.fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-height: 100vh;
|
||||
z-index: 9999;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: var(--bg-primary);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
border-radius: 0;
|
||||
transition: all 0.5s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
|
||||
/* Adjust graph container in fullscreen mode */
|
||||
.graph-container-wrapper.fullscreen .graph-container {
|
||||
position: relative;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
/* Fullscreen Toggle Button */
|
||||
.fullscreen-toggle {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
background: rgba(30, 41, 59, 0.7);
|
||||
border: 1px solid var(--border-primary);
|
||||
color: var(--text-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
z-index: 4;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.fullscreen-toggle:hover {
|
||||
background: rgba(30, 41, 59, 0.9);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .fullscreen-toggle {
|
||||
top: 25px;
|
||||
right: 25px;
|
||||
}
|
||||
|
||||
/* Hide one of the fullscreen icons */
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Full Post Content Panel */
|
||||
.full-post-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 12px;
|
||||
opacity: 0;
|
||||
z-index: 4;
|
||||
border: 1px solid var(--card-border);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Full post panel in fullscreen mode */
|
||||
.graph-container-wrapper.fullscreen .full-post-content {
|
||||
position: relative;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
background: rgba(30, 41, 59, 0.7);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .full-post-content.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.full-post-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.full-post-title {
|
||||
font-size: 1.5rem;
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.full-post-metadata {
|
||||
padding: 1rem 1.5rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.full-post-category {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.full-post-tags {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.post-tag {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: #10B981;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.full-post-container {
|
||||
flex: 1;
|
||||
padding: 1.5rem;
|
||||
overflow-y: auto;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.full-post-container::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.full-post-container::-webkit-scrollbar-track {
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.full-post-container::-webkit-scrollbar-thumb {
|
||||
background: rgba(226, 232, 240, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.full-post-container::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(226, 232, 240, 0.2);
|
||||
}
|
||||
|
||||
.full-post-placeholder {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-secondary);
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.full-post-placeholder svg {
|
||||
margin-bottom: 1rem;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
line-height: 1.7;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.post-content h1, .post-content h2, .post-content h3,
|
||||
.post-content h4, .post-content h5, .post-content h6 {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.post-content p {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.post-content a {
|
||||
color: var(--accent-primary);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted var(--accent-primary);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.post-content a:hover {
|
||||
color: var(--accent-secondary);
|
||||
border-bottom-style: solid;
|
||||
}
|
||||
|
||||
.post-content pre {
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 1.5rem 0;
|
||||
border: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.post-content code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.post-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.post-content blockquote {
|
||||
border-left: 4px solid var(--accent-primary);
|
||||
padding-left: 1rem;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
font-style: italic;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.post-content ul, .post-content ol {
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.post-content li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.full-post-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
|
||||
color: var(--bg-primary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.full-post-link:hover {
|
||||
background: linear-gradient(90deg, var(--accent-secondary), var(--accent-primary));
|
||||
}
|
||||
|
||||
/* Media Queries */
|
||||
@media screen and (max-width: 992px) {
|
||||
/* Adjust fullscreen layout for smaller screens */
|
||||
.graph-container-wrapper.fullscreen {
|
||||
flex-direction: column;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .graph-container {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
margin-right: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .full-post-content {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.fullscreen-toggle {
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .graph-container {
|
||||
height: 40%;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .full-post-content {
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
.full-post-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.full-post-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.full-post-metadata {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.full-post-container {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.graph-container-wrapper.fullscreen {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .graph-container {
|
||||
height: 35%;
|
||||
}
|
||||
|
||||
.graph-container-wrapper.fullscreen .full-post-content {
|
||||
height: 65%;
|
||||
}
|
||||
|
||||
.full-post-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,230 +0,0 @@
|
|||
---
|
||||
// src/components/homelab/HeroSection.astro - Ultra minimal version
|
||||
const { servicesCount } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="home" class="hero">
|
||||
<div class="container">
|
||||
<div class="hero-content">
|
||||
<div class="hero-text">
|
||||
<h1 class="hero-title">
|
||||
Enterprise-Grade <span class="highlight">Home Lab</span> Environment
|
||||
</h1>
|
||||
<p class="hero-description">
|
||||
A production-ready infrastructure platform for DevOps experimentation, distributed systems, and automating everything with code.
|
||||
</p>
|
||||
|
||||
<!-- Simple stats display -->
|
||||
<div class="stats-box">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">Services:</div>
|
||||
<div class="stat-value">{servicesCount}+</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">CPU Cores:</div>
|
||||
<div class="stat-value">32+</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">Memory:</div>
|
||||
<div class="stat-value">64GB</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">Storage:</div>
|
||||
<div class="stat-value">12TB</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cta-buttons">
|
||||
<a href="/ansible-sandbox" class="btn btn-danger" id="ansible-sandbox-btn">
|
||||
<span class="btn-text">Try Ansible Sandbox</span>
|
||||
<span class="offline-badge">Offline</span>
|
||||
</a>
|
||||
<a href="#architecture" class="btn btn-outline">
|
||||
<span class="btn-text">Explore Architecture</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Simple status box instead of terminal -->
|
||||
<div class="status-box">
|
||||
<div class="status-header">
|
||||
<div class="status-title">System Status</div>
|
||||
</div>
|
||||
<div class="status-body">
|
||||
<div class="status-line">
|
||||
<span class="status-label">Nodes:</span>
|
||||
<span class="status-value">2 (Ready)</span>
|
||||
</div>
|
||||
<div class="status-line">
|
||||
<span class="status-label">Running Pods:</span>
|
||||
<span class="status-value">32</span>
|
||||
</div>
|
||||
<div class="status-line">
|
||||
<span class="status-label">Uptime:</span>
|
||||
<span class="status-value">154 days</span>
|
||||
</div>
|
||||
<div class="status-line">
|
||||
<span class="status-label">Load:</span>
|
||||
<span class="status-value">0.22, 0.18, 0.15</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.hero {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 6rem 0 4rem;
|
||||
background: linear-gradient(180deg, var(--bg-secondary), var(--bg-primary));
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: var(--primary, #3b82f6);
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: 1.125rem;
|
||||
margin-bottom: 2rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.stats-box {
|
||||
background-color: rgba(15, 23, 42, 0.7);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: var(--success, #10b981);
|
||||
}
|
||||
|
||||
.cta-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.375rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: var(--error, #ef4444);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.offline-badge {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.status-box {
|
||||
background-color: rgba(15, 23, 42, 0.9);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.status-header {
|
||||
padding: 0.75rem 1rem;
|
||||
background-color: rgba(30, 41, 59, 0.8);
|
||||
}
|
||||
|
||||
.status-title {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.status-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.status-value {
|
||||
color: var(--success, #10b981);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hero-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.stats-box {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.status-box {
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,119 +0,0 @@
|
|||
---
|
||||
// src/components/homelab/ProjectsSection.astro
|
||||
// Making sure we properly handle the projectsData prop
|
||||
const { projectsData } = Astro.props;
|
||||
|
||||
// If projectsData is undefined or not an array, provide a fallback
|
||||
const projects = Array.isArray(projectsData) ? projectsData : [];
|
||||
|
||||
// Debug logging
|
||||
console.log("ProjectsSection received projectsData:", !!projectsData);
|
||||
console.log("ProjectsSection projects count:", projects.length);
|
||||
---
|
||||
|
||||
<section id="projects" class="projects section-padding alt-bg">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Related Projects</h2>
|
||||
<p class="section-description">
|
||||
Explore associated projects and repositories related to the ArgoBox lab.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="projects-grid">
|
||||
{projects.length > 0 ? (
|
||||
projects.map(project => (
|
||||
<a
|
||||
href={project.url}
|
||||
class="project-card"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<div class="project-header">
|
||||
<div class="project-icon"><i class={project.icon}></i></div>
|
||||
<h3 class="project-title">{project.title}</h3>
|
||||
</div>
|
||||
<p class="project-description">{project.description}</p>
|
||||
<div class="project-tech">
|
||||
{project.tech && project.tech.map(tech => (
|
||||
<span class="tech-badge">{tech}</span>
|
||||
))}
|
||||
</div>
|
||||
</a>
|
||||
))
|
||||
) : (
|
||||
<div class="no-projects">
|
||||
<p>No projects available at this time.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.project-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.project-icon {
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 1.25rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.project-description {
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.project-tech {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.tech-badge {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--bg-secondary);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.no-projects {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
background-color: var(--bg-card);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
</style>
|
|
@ -1,80 +0,0 @@
|
|||
// src/components/homelab/ServiceCategory.astro
|
||||
|
||||
---
|
||||
const { category } = Astro.props;
|
||||
|
||||
function getCategoryIcon(categoryKey) {
|
||||
if (categoryKey === 'development') return 'fa-code';
|
||||
if (categoryKey === 'media') return 'fa-photo-video';
|
||||
if (categoryKey === 'utilities') return 'fa-tools';
|
||||
return 'fa-cogs'; // Default for infrastructure
|
||||
}
|
||||
|
||||
const categoryIcon = getCategoryIcon(category.key);
|
||||
const categoryTitle = category.key.charAt(0).toUpperCase() + category.key.slice(1);
|
||||
---
|
||||
|
||||
<div class="services-category" data-category={category.key}>
|
||||
<h3 class="category-title">
|
||||
<i class={`fas ${categoryIcon} category-icon`}></i>
|
||||
{categoryTitle} Tools
|
||||
</h3>
|
||||
<div class="service-items">
|
||||
{category.services.map(service => (
|
||||
<a
|
||||
href={service.available ? service.url : '#'}
|
||||
class={`service-item ${service.available ? 'available' : ''} service-${service.name.toLowerCase().replace(/\s+/g, '-')}`}
|
||||
target={service.available ? "_blank" : null}
|
||||
rel={service.available ? "noopener noreferrer" : null}
|
||||
aria-disabled={!service.available}
|
||||
data-service={service.name.toLowerCase().replace(/\s+/g, '-')}
|
||||
>
|
||||
<div class="service-icon"><i class={service.icon}></i></div>
|
||||
<div class="service-info">
|
||||
<div class="service-name">{service.name}</div>
|
||||
<p class="service-description">{service.description}</p>
|
||||
</div>
|
||||
<span class={`service-status ${service.status}`}>
|
||||
<span class="status-dot"></span>
|
||||
{service.status.charAt(0).toUpperCase() + service.status.slice(1)}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.services-category {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
margin-right: 0.75rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.service-items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
display: flex;
|
||||
padding: 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
color: var(--text-primary);
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
|
@ -1,201 +0,0 @@
|
|||
---
|
||||
// src/components/homelab/ServicesSection.astro
|
||||
// Making sure servicesData is properly handled
|
||||
|
||||
const { servicesData } = Astro.props;
|
||||
|
||||
// Helper functions
|
||||
function getCategoryIcon(category) {
|
||||
if (category === 'development') return 'fa-code';
|
||||
if (category === 'media') return 'fa-photo-video';
|
||||
if (category === 'utilities') return 'fa-tools';
|
||||
return 'fa-cogs'; // Default for infrastructure
|
||||
}
|
||||
|
||||
function formatServiceName(name) {
|
||||
return name.toLowerCase().replace(/\s+/g, '-');
|
||||
}
|
||||
|
||||
// Create a safe version of the data in case it's undefined
|
||||
const safeServicesData = servicesData || {};
|
||||
|
||||
// Prepare data for rendering to minimize template expressions
|
||||
const categoryEntries = Object.entries(safeServicesData).map(([key, services]) => {
|
||||
return {
|
||||
key,
|
||||
title: key.charAt(0).toUpperCase() + key.slice(1),
|
||||
services: Array.isArray(services) ? services : []
|
||||
};
|
||||
});
|
||||
|
||||
// Debug logging
|
||||
console.log("ServicesSection received servicesData:", !!servicesData);
|
||||
console.log("ServicesSection categories count:", categoryEntries.length);
|
||||
---
|
||||
|
||||
<section id="services" class="services section-padding">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Available Services</h2>
|
||||
<p class="section-description">
|
||||
Explore the various services and applications hosted in the ArgoBox environment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="services-info-banner">
|
||||
<i class="fas fa-info-circle info-icon"></i>
|
||||
<p>Some services require authentication and are restricted. Available public services are highlighted and clickable.</p>
|
||||
</div>
|
||||
|
||||
<div class="services-grid">
|
||||
{categoryEntries.length > 0 ? (
|
||||
categoryEntries.map(category => (
|
||||
<div class="services-category" data-category={category.key}>
|
||||
<h3 class="category-title">
|
||||
<i class={`fas ${getCategoryIcon(category.key)} category-icon`}></i>
|
||||
{category.title} Tools
|
||||
</h3>
|
||||
<div class="service-items">
|
||||
{category.services.map(service => (
|
||||
<a
|
||||
href={service.available ? service.url : '#'}
|
||||
class={`service-item ${service.available ? 'available' : ''} service-${formatServiceName(service.name)}`}
|
||||
target={service.available ? "_blank" : null}
|
||||
rel={service.available ? "noopener noreferrer" : null}
|
||||
aria-disabled={!service.available}
|
||||
>
|
||||
<div class="service-icon"><i class={service.icon}></i></div>
|
||||
<div class="service-info">
|
||||
<div class="service-name">{service.name}</div>
|
||||
<p class="service-description">{service.description}</p>
|
||||
</div>
|
||||
<span class={`service-status ${service.status}`}>
|
||||
<span class="status-dot"></span>
|
||||
{service.status.charAt(0).toUpperCase() + service.status.slice(1)}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div class="no-services">
|
||||
<p>No services available at this time.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.services-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.services-info-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border-radius: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
margin-right: 1rem;
|
||||
color: var(--primary, #3b82f6);
|
||||
}
|
||||
|
||||
.services-category {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
margin-right: 0.75rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.service-items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
display: flex;
|
||||
padding: 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
color: var(--text-primary);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.service-item.available:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.service-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.service-name {
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.service-description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.service-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 1rem;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.25rem;
|
||||
background-color: var(--success);
|
||||
}
|
||||
|
||||
.service-status.offline .status-dot {
|
||||
background-color: var(--error);
|
||||
}
|
||||
|
||||
.no-services {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
background-color: var(--bg-card);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
</style>
|
|
@ -35,6 +35,22 @@ const postsCollection = defineCollection({
|
|||
}),
|
||||
});
|
||||
|
||||
// Define the external posts collection (for external articles)
|
||||
const externalPostsCollection = defineCollection({
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string().optional(),
|
||||
pubDate: z.coerce.date(),
|
||||
url: z.string().url(),
|
||||
heroImage: z.string().optional(),
|
||||
source: z.string().optional(),
|
||||
category: z.string().optional(),
|
||||
categories: z.array(z.string()).optional(),
|
||||
tags: z.array(z.string()).default([]),
|
||||
}),
|
||||
});
|
||||
|
||||
// Define the configurations collection (for config files)
|
||||
const configurationsCollection = defineCollection({
|
||||
type: 'content',
|
||||
|
@ -78,6 +94,7 @@ const projectsCollection = defineCollection({
|
|||
// Export the collections
|
||||
export const collections = {
|
||||
posts: postsCollection,
|
||||
'external-posts': externalPostsCollection,
|
||||
configurations: configurationsCollection,
|
||||
projects: projectsCollection,
|
||||
};
|
|
@ -1,65 +0,0 @@
|
|||
---
|
||||
title: 'Getting Started with Infrastructure as Code'
|
||||
description: 'Learn the basics of Infrastructure as Code and how to start using it in your projects.'
|
||||
pubDate: '2023-11-15'
|
||||
heroImage: '/images/posts/blog-infrastructure-as-code.jpg'
|
||||
categories: ['Infrastructure', 'DevOps']
|
||||
tags: ['terraform', 'infrastructure', 'cloud', 'automation']
|
||||
minutesRead: '5 min'
|
||||
---
|
||||
|
||||
# Getting Started with Infrastructure as Code
|
||||
|
||||
Infrastructure as Code (IaC) is a key DevOps practice that involves managing and provisioning infrastructure through code instead of manual processes. This approach brings the same rigor, transparency, and version control to infrastructure that developers have long applied to application code.
|
||||
|
||||
## Why Infrastructure as Code?
|
||||
|
||||
IaC offers numerous benefits for modern DevOps teams:
|
||||
|
||||
- **Consistency**: Infrastructure deployments become reproducible and standardized
|
||||
- **Version Control**: Track changes to your infrastructure just like application code
|
||||
- **Automation**: Reduce manual errors and increase deployment speed
|
||||
- **Documentation**: Your code becomes self-documenting
|
||||
- **Testing**: Infrastructure can be tested before deployment
|
||||
|
||||
## Popular IaC Tools
|
||||
|
||||
There are several powerful tools for implementing IaC:
|
||||
|
||||
1. **Terraform**: Cloud-agnostic, works with multiple providers
|
||||
2. **AWS CloudFormation**: Specific to AWS infrastructure
|
||||
3. **Azure Resource Manager**: Microsoft's native IaC solution
|
||||
4. **Google Cloud Deployment Manager**: For Google Cloud resources
|
||||
5. **Pulumi**: Uses general-purpose programming languages
|
||||
|
||||
## Basic Terraform Example
|
||||
|
||||
Here's a simple example of Terraform code that provisions an AWS EC2 instance:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-west-2"
|
||||
}
|
||||
|
||||
resource "aws_instance" "web_server" {
|
||||
ami = "ami-0c55b159cbfafe1f0"
|
||||
instance_type = "t2.micro"
|
||||
|
||||
tags = {
|
||||
Name = "Web Server"
|
||||
Environment = "Development"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
To begin your IaC journey:
|
||||
|
||||
1. Choose a tool that fits your infrastructure needs
|
||||
2. Start small with a simple resource
|
||||
3. Learn about state management
|
||||
4. Implement CI/CD for your infrastructure code
|
||||
5. Consider using modules for reusability
|
||||
|
||||
Infrastructure as Code transforms how teams provision and manage resources, enabling more reliable, consistent deployments while reducing overhead and errors.
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: "Blog Posts Collection"
|
||||
description: "Documentation for blog posts"
|
||||
pubDate: 2025-04-18
|
||||
draft: true
|
||||
---
|
||||
|
||||
# Blog Posts Collection
|
||||
|
||||
This directory contains blog posts for the ArgoBox digital garden.
|
||||
|
||||
## Content Guidelines
|
||||
|
||||
- All posts should include proper frontmatter
|
||||
- Use Markdown for formatting content
|
||||
- Images should be placed in the public/blog/images directory
|
||||
|
||||
## Frontmatter Requirements
|
||||
|
||||
Every post needs at minimum:
|
||||
|
||||
```
|
||||
---
|
||||
title: "Post Title"
|
||||
pubDate: YYYY-MM-DD
|
||||
---
|
||||
```
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: This is a test
|
||||
description: How to set up Cloudflare Tunnels for secure remote access to your home lab services
|
||||
pubDate: Jul 22 2023
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
category: networking
|
||||
tags:
|
||||
- Tag A
|
||||
- Tag B
|
||||
- Tag C
|
||||
readTime: "7 min read"
|
||||
---
|
|
@ -2,7 +2,7 @@
|
|||
title: Secure Remote Access with Cloudflare Tunnels
|
||||
description: How to set up Cloudflare Tunnels for secure remote access to your home lab services
|
||||
pubDate: 2025-04-19
|
||||
heroImage: /images/posts/blog-cloudflare-tunnel.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
category: networking
|
||||
tags:
|
||||
- cloudflare
|
|
@ -10,7 +10,7 @@ tags:
|
|||
- kubernetes
|
||||
- docker
|
||||
- file-management
|
||||
heroImage: /images/posts/blog-filebrowser-setup.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
I've said it before, and I'll say it again - the journey to a well-organized digital life begins with proper file management. If you're like me, you've got files scattered across multiple devices, cloud services, and servers. What if I told you there's a lightweight, sleek solution that puts you back in control without relying on third-party services?
|
||||
|
|
|
@ -10,7 +10,7 @@ tags:
|
|||
- self-hosted
|
||||
- devops
|
||||
- kubernetes
|
||||
heroImage: /images/posts/blog-self-hosted-git.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
If you're a developer like me who values ownership and privacy, you've probably wondered if there's a way to get the convenience of GitHub or GitLab without handing over your code to a third party. Enter Gitea - a painless, self-hosted Git service written in Go that I've been using for my personal projects for the past year.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: GitOps with Flux CD
|
||||
description: Implementing GitOps workflows on Kubernetes using Flux CD
|
||||
pubDate: 2025-04-19
|
||||
heroImage: /images/posts/blog-gitops-with-flux-cd.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
category: devops
|
||||
tags:
|
||||
- kubernetes
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: "Setting Up a K3s Kubernetes Cluster"
|
||||
description: "A comprehensive guide to setting up a K3s cluster for your home lab or edge environment, with high availability and persistent storage."
|
||||
pubDate: "2023-11-15"
|
||||
heroImage: "/images/posts/guide-k3s-cluster.jpg"
|
||||
heroImage: "/blog/images/posts/k3installation.png"
|
||||
category: "Kubernetes"
|
||||
tags: ["kubernetes", "k3s", "homelab", "infrastructure"]
|
||||
draft: false
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: K3s Installation Guide
|
||||
description: A comprehensive guide to installing and configuring K3s for your home lab
|
||||
pubDate: 2025-04-19
|
||||
heroImage: /images/posts/guide-k3-installation.jpg
|
||||
heroImage: /images/posts/k3installation.png
|
||||
category: kubernetes
|
||||
tags:
|
||||
- kubernetes
|
|
@ -2,7 +2,7 @@
|
|||
title: "Monitoring Your Kubernetes Cluster with Prometheus and Grafana"
|
||||
description: "A comprehensive guide to setting up a robust monitoring solution for your Kubernetes cluster using Prometheus and Grafana."
|
||||
pubDate: "2023-09-25"
|
||||
heroImage: "/images/posts/blog-prometheus-monitoring.jpg"
|
||||
heroImage: "/blog/images/posts/prometheus-dashboard.svg"
|
||||
category: "Monitoring"
|
||||
tags: ["kubernetes", "prometheus", "grafana", "monitoring", "observability"]
|
||||
draft: false
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: Complete Proxmox VE Setup Guide
|
||||
description: A step-by-step guide to setting up Proxmox VE for your home lab virtualization needs
|
||||
pubDate: 2025-04-19
|
||||
heroImage: /images/posts/blog-proxmox-setup.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
category: infrastructure
|
||||
tags:
|
||||
- proxmox
|
||||
|
|
|
@ -10,7 +10,7 @@ tags:
|
|||
- digital-garden
|
||||
- knowledge-management
|
||||
- astro
|
||||
heroImage: /images/posts/blog-quartz-digital-garden.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
I've been taking digital notes for decades now. From simple `.txt` files to OneNote, Evernote, Notion, and now Obsidian. But for years, I've been wrestling with a question: how do I share my knowledge with others in a way that preserves the connections between ideas?
|
||||
|
|
|
@ -10,7 +10,7 @@ tags:
|
|||
- k3s
|
||||
- devops
|
||||
- containers
|
||||
heroImage: /images/posts/blog-home-lab-with-rancher.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
I've been running Kubernetes at home for years now, and I've tried just about every management tool out there. From kubectl and a bunch of YAML files to various dashboards and UIs, I've experimented with it all. But the one tool that's been a constant in my home lab journey is [Rancher](https://rancher.com/) - a complete container management platform that makes Kubernetes management almost... dare I say it... enjoyable?
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: "Starting My Digital Garden"
|
||||
description: "How and why I'm approaching this blog as a digital garden rather than a traditional chronological blog."
|
||||
pubDate: "2023-10-05"
|
||||
heroImage: "/images/posts/blog-digital-garden.jpg"
|
||||
heroImage: "/blog/images/placeholders/default.jpg"
|
||||
category: "Meta"
|
||||
tags: ["digital-garden", "knowledge-management", "learning-in-public"]
|
||||
draft: false
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: Test Post
|
||||
pubDate: 2024-03-20
|
||||
description: This is a test post to verify the blog setup
|
||||
category: Test
|
||||
tags:
|
||||
- test
|
||||
draft: true
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
# Test Post
|
||||
|
||||
This is a test post to verify that the blog setup is working correctly.
|
|
@ -10,7 +10,7 @@ tags:
|
|||
- self-hosted
|
||||
- coding
|
||||
- homelab
|
||||
heroImage: /images/posts/blog-vs-code-server.jpg
|
||||
heroImage: /images/posts/prometheusk8.png
|
||||
---
|
||||
|
||||
If you're like me, you probably find yourself coding on multiple devices - maybe a desktop at home, a laptop when traveling, or even occasionally on a tablet. For years, keeping development environments in sync was a pain point. Enter [VS Code Server](https://code.visualstudio.com/docs/remote/vscode-server), the solution that has completely transformed my development workflow.
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
export const servicesData = {
|
||||
development: [
|
||||
{ name: "Gitea", description: "Self-hosted Git service", url: "https://git.argobox.com", status: "live", icon: "fas fa-code-branch", available: true },
|
||||
{ name: "VS Code Server", description: "Remote development environment", url: "https://code.argobox.com", status: "live", icon: "fas fa-terminal", available: true },
|
||||
{ name: "Drone CI", description: "Continuous Integration server", url: "https://drone.argobox.com", status: "live", icon: "fas fa-cogs", available: true },
|
||||
],
|
||||
media: [
|
||||
{ name: "Plex", description: "Media streaming server", url: "https://plex.argobox.com", status: "live", icon: "fas fa-play-circle", available: true },
|
||||
{ name: "Jellyfin", description: "Open source media system", url: "https://jellyfin.argobox.com", status: "live", icon: "fas fa-film", available: true },
|
||||
{ name: "Sonarr", description: "TV show management", url: "#", status: "restricted", icon: "fas fa-tv", available: false },
|
||||
{ name: "Radarr", description: "Movie management", url: "#", status: "restricted", icon: "fas fa-video", available: false },
|
||||
{ name: "Prowlarr", description: "Indexer management", url: "#", status: "restricted", icon: "fas fa-search", available: false },
|
||||
],
|
||||
utilities: [
|
||||
{ name: "File Browser", description: "Web file manager", url: "https://files.argobox.com", status: "live", icon: "fas fa-folder-open", available: true },
|
||||
{ name: "Vaultwarden", description: "Password manager", url: "#", status: "restricted", icon: "fas fa-key", available: false },
|
||||
{ name: "Homepage", description: "Service dashboard", url: "https://dash.argobox.com", status: "live", icon: "fas fa-tachometer-alt", available: true },
|
||||
{ name: "Uptime Kuma", description: "Status monitoring", url: "https://status.argobox.com", status: "live", icon: "fas fa-heartbeat", available: true },
|
||||
],
|
||||
infrastructure: [
|
||||
{ name: "Proxmox VE", description: "Virtualization platform", url: "#", status: "restricted", icon: "fas fa-server", available: false },
|
||||
{ name: "Kubernetes (K3s)", description: "Container orchestration", url: "#", status: "restricted", icon: "fas fa-dharmachakra", available: false },
|
||||
{ name: "Traefik", description: "Ingress controller", url: "#", status: "restricted", icon: "fas fa-route", available: false },
|
||||
{ name: "OPNsense", description: "Firewall/Router", url: "#", status: "restricted", icon: "fas fa-shield-alt", available: false },
|
||||
]
|
||||
};
|
||||
|
||||
export const projectsData = [
|
||||
{ title: "Ansible Playbooks", description: "Collection of playbooks for automating system configuration and application deployment.", icon: "fab fa-ansible", tech: ["Ansible", "YAML", "Jinja2"], url: "/resources/iac" },
|
||||
{ title: "Kubernetes Manifests", description: "YAML definitions for deploying various applications and services on Kubernetes.", icon: "fas fa-dharmachakra", tech: ["Kubernetes", "YAML", "Helm"], url: "/resources/kubernetes" },
|
||||
{ title: "Monitoring Dashboards", description: "Grafana dashboards for visualizing infrastructure and application metrics.", icon: "fas fa-chart-line", tech: ["Grafana", "PromQL", "JSON"], url: "/resources/config-files" },
|
||||
{ title: "Cloudflare Tunnel Setup", description: "Securely exposing home lab services to the internet using Cloudflare Tunnels.", icon: "fas fa-cloud", tech: ["Cloudflare", "Networking", "Security"], url: "/posts/cloudflare-tunnel-setup" }
|
||||
];
|
||||
|
||||
export const dashboardsData = [
|
||||
{ title: "Infrastructure Overview", description: "Key metrics for Proxmox hosts, network devices, and storage.", previewClass: "infrastructure", url: "https://dash.argobox.com/goto/...", icon: "fas fa-server" },
|
||||
{ title: "Kubernetes Cluster", description: "Detailed view of K3s cluster resources, node status, and pod health.", previewClass: "kubernetes", url: "https://dash.argobox.com/goto/...", icon: "fas fa-dharmachakra" },
|
||||
{ title: "Network Traffic", description: "Real-time and historical network usage, firewall logs, and connection tracking.", previewClass: "network", url: "https://dash.argobox.com/goto/...", icon: "fas fa-network-wired" },
|
||||
{ title: "Service Performance", description: "Application-specific metrics, request latency, and error rates.", previewClass: "services", url: "https://dash.argobox.com/goto/...", icon: "fas fa-cogs" }
|
||||
];
|
|
@ -79,9 +79,6 @@ const {
|
|||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<!-- Theme CSS -->
|
||||
<link rel="stylesheet" href="/src/styles/theme.css" />
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
// src/layouts/MinimalLayout.astro
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Minimal Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,10 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
// Initialize Resend with API key from environment variables
|
||||
// IMPORTANT: Set RESEND_API_KEY in your deployment environment (e.g., Cloudflare Pages)
|
||||
const resend = new Resend(import.meta.env.RESEND_API_KEY);
|
||||
|
||||
// Define the expected structure of the form data
|
||||
interface FormData {
|
||||
name: string;
|
||||
|
@ -10,10 +14,6 @@ interface FormData {
|
|||
}
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
// Initialize Resend inside the handler to access runtime env vars/secrets
|
||||
// IMPORTANT: Set RESEND_API_KEY in your deployment environment (e.g., Cloudflare Pages)
|
||||
const resend = new Resend(import.meta.env.RESEND_API_KEY);
|
||||
|
||||
// Check if API key is configured
|
||||
if (!import.meta.env.RESEND_API_KEY) {
|
||||
console.error("Resend API key is not configured.");
|
||||
|
@ -56,7 +56,7 @@ export const POST: APIRoute = async ({ request }) => {
|
|||
<p><strong>Message:</strong></p>
|
||||
<p>${data.message.replace(/\n/g, '<br>')}</p>
|
||||
`,
|
||||
replyTo: data.email, // Set the reply-to header to the sender's email
|
||||
reply_to: data.email, // Set the reply-to header to the sender's email
|
||||
});
|
||||
|
||||
if (emailError) {
|
||||
|
|
|
@ -99,17 +99,17 @@ sortedPosts
|
|||
// Terminal commands for tech effect
|
||||
const commands = [
|
||||
{
|
||||
prompt: "[user@argobox]$ ",
|
||||
prompt: "[laforceit@argobox]$ ",
|
||||
command: "find ./posts -type f -name \"*.md\" | sort -n | wc -l",
|
||||
output: [`${allPosts.length} posts found`]
|
||||
},
|
||||
{
|
||||
prompt: "[user@argobox]$ ",
|
||||
prompt: "[laforceit@argobox]$ ",
|
||||
command: "ls -la ./tags",
|
||||
output: allTags.map(tag => `${tag}`)
|
||||
},
|
||||
{
|
||||
prompt: "[user@argobox]$ ",
|
||||
prompt: "[laforceit@argobox]$ ",
|
||||
command: "grep -r \"kubernetes\" --include=\"*.md\" ./posts | wc -l",
|
||||
output: [`${allPosts.filter(post =>
|
||||
post.data.tags?.includes('kubernetes') ||
|
||||
|
|
|
@ -1,56 +1,838 @@
|
|||
---
|
||||
// src/pages/homelab.astro - Fixed main file with proper component imports
|
||||
// src/pages/homelab.astro - Converted from static homelab.html
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import HeroSection from '../components/homelab/HeroSection.astro';
|
||||
import ServicesSection from '../components/homelab/ServicesSection.astro';
|
||||
import ProjectsSection from '../components/homelab/ProjectsSection.astro';
|
||||
import { servicesData, projectsData, dashboardsData } from '../data/homelabData';
|
||||
|
||||
const title = "Home Lab | ArgoBox - ArgoBox Tech Hub";
|
||||
const title = "Home Lab | Argobox - ArgoBox Tech Hub";
|
||||
const description = "ArgoBox - A production-grade Kubernetes homelab for DevOps experimentation, infrastructure automation, and containerized application deployment.";
|
||||
|
||||
// Calculate total services count for the hero section
|
||||
const servicesCount = Object.values(servicesData).flat().length;
|
||||
// Data for services (can be fetched or defined here)
|
||||
// Example structure - replace with actual data source if needed
|
||||
const servicesData = {
|
||||
development: [
|
||||
{ name: "Gitea", description: "Self-hosted Git service", url: "https://git.argobox.com", status: "live", icon: "fas fa-code-branch", available: true },
|
||||
{ name: "VS Code Server", description: "Remote development environment", url: "https://code.argobox.com", status: "live", icon: "fas fa-terminal", available: true },
|
||||
{ name: "Drone CI", description: "Continuous Integration server", url: "https://drone.argobox.com", status: "live", icon: "fas fa-cogs", available: true },
|
||||
],
|
||||
media: [
|
||||
{ name: "Plex", description: "Media streaming server", url: "https://plex.argobox.com", status: "live", icon: "fas fa-play-circle", available: true },
|
||||
{ name: "Jellyfin", description: "Open source media system", url: "https://jellyfin.argobox.com", status: "live", icon: "fas fa-film", available: true },
|
||||
{ name: "Sonarr", description: "TV show management", url: "#", status: "restricted", icon: "fas fa-tv", available: false },
|
||||
{ name: "Radarr", description: "Movie management", url: "#", status: "restricted", icon: "fas fa-video", available: false },
|
||||
{ name: "Prowlarr", description: "Indexer management", url: "#", status: "restricted", icon: "fas fa-search", available: false },
|
||||
],
|
||||
utilities: [
|
||||
{ name: "File Browser", description: "Web file manager", url: "https://files.argobox.com", status: "live", icon: "fas fa-folder-open", available: true },
|
||||
{ name: "Vaultwarden", description: "Password manager", url: "https://vault.argobox.com", status: "live", icon: "fas fa-key", available: true },
|
||||
{ name: "Homepage", description: "Service dashboard", url: "https://dash.argobox.com", status: "live", icon: "fas fa-tachometer-alt", available: true },
|
||||
{ name: "Uptime Kuma", description: "Status monitoring", url: "https://status.argobox.com", status: "live", icon: "fas fa-heartbeat", available: true },
|
||||
],
|
||||
infrastructure: [
|
||||
{ name: "Proxmox VE", description: "Virtualization platform", url: "#", status: "restricted", icon: "fas fa-server", available: false },
|
||||
{ name: "Kubernetes (K3s)", description: "Container orchestration", url: "#", status: "restricted", icon: "fas fa-dharmachakra", available: false },
|
||||
{ name: "Traefik", description: "Ingress controller", url: "#", status: "restricted", icon: "fas fa-route", available: false },
|
||||
{ name: "OPNsense", description: "Firewall/Router", url: "#", status: "restricted", icon: "fas fa-shield-alt", available: false },
|
||||
]
|
||||
};
|
||||
|
||||
// Data for projects (can be fetched or defined here)
|
||||
const projectsData = [
|
||||
{ title: "Ansible Playbooks", description: "Collection of playbooks for automating system configuration and application deployment.", icon: "fab fa-ansible", tech: ["Ansible", "YAML", "Jinja2"], url: "/resources/iac" }, // Link to relevant resource page
|
||||
{ title: "Kubernetes Manifests", description: "YAML definitions for deploying various applications and services on Kubernetes.", icon: "fas fa-dharmachakra", tech: ["Kubernetes", "YAML", "Helm"], url: "/resources/kubernetes" },
|
||||
{ title: "Monitoring Dashboards", description: "Grafana dashboards for visualizing infrastructure and application metrics.", icon: "fas fa-chart-line", tech: ["Grafana", "PromQL", "JSON"], url: "/resources/config-files" }, // Link to relevant resource page
|
||||
{ title: "Cloudflare Tunnel Setup", description: "Securely exposing home lab services to the internet using Cloudflare Tunnels.", icon: "fas fa-cloud", tech: ["Cloudflare", "Networking", "Security"], url: "/posts/cloudflare-tunnel-setup" } // Link to blog post
|
||||
];
|
||||
|
||||
// Data for dashboards (can be fetched or defined here)
|
||||
const dashboardsData = [
|
||||
{ title: "Infrastructure Overview", description: "Key metrics for Proxmox hosts, network devices, and storage.", previewClass: "infrastructure", url: "https://dash.argobox.com/goto/...", icon: "fas fa-server" },
|
||||
{ title: "Kubernetes Cluster", description: "Detailed view of K3s cluster resources, node status, and pod health.", previewClass: "kubernetes", url: "https://dash.argobox.com/goto/...", icon: "fas fa-dharmachakra" },
|
||||
{ title: "Network Traffic", description: "Real-time and historical network usage, firewall logs, and connection tracking.", previewClass: "network", url: "https://dash.argobox.com/goto/...", icon: "fas fa-network-wired" },
|
||||
{ title: "Service Performance", description: "Application-specific metrics, request latency, and error rates.", previewClass: "services", url: "https://dash.argobox.com/goto/...", icon: "fas fa-cogs" }
|
||||
];
|
||||
|
||||
// Data for contact form (if keeping it on this page)
|
||||
// const contactInfo = { email: "daniel.laforce@argobox.com", /* other info */ };
|
||||
|
||||
---
|
||||
|
||||
<BaseLayout {title} {description}>
|
||||
{/* Add Font Awesome if not loaded globally by BaseLayout */}
|
||||
{/* <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> */}
|
||||
<Header slot="header" />
|
||||
|
||||
<main class="homelab-page">
|
||||
<HeroSection servicesCount={servicesCount} />
|
||||
<ServicesSection servicesData={servicesData} />
|
||||
<ProjectsSection projectsData={projectsData} />
|
||||
|
||||
<!-- Hero Section -->
|
||||
<section id="home" class="hero">
|
||||
<div class="particles-container" id="particles-container"></div>
|
||||
<div class="container">
|
||||
<div class="hero-content">
|
||||
<div class="hero-text">
|
||||
<h1 class="hero-title">
|
||||
Enterprise-Grade <span class="highlight">Home Lab</span> Environment
|
||||
</h1>
|
||||
<p class="hero-description">
|
||||
A production-ready infrastructure platform for DevOps experimentation, distributed systems, and automating everything with code.
|
||||
</p>
|
||||
<div class="hero-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon"><i class="fas fa-microchip"></i></div>
|
||||
<div class="stat-detail">
|
||||
<div class="stat-value">32+</div>
|
||||
<div class="stat-name">CPU Cores</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon"><i class="fas fa-memory"></i></div>
|
||||
<div class="stat-detail">
|
||||
<div class="stat-value">64GB</div>
|
||||
<div class="stat-name">RAM</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon"><i class="fas fa-hdd"></i></div>
|
||||
<div class="stat-detail">
|
||||
<div class="stat-value">12TB</div>
|
||||
<div class="stat-name">Storage</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon"><i class="fas fa-server"></i></div>
|
||||
<div class="stat-detail">
|
||||
<div class="stat-value">{Object.values(servicesData).flat().length}+</div>
|
||||
<div class="stat-name">Services</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cta-buttons">
|
||||
{/* Link to the Astro page for Ansible Sandbox */}
|
||||
<a href="/ansible-sandbox" class="btn btn-danger" id="ansible-sandbox-btn">
|
||||
<i class="fab fa-ansible btn-icon"></i>
|
||||
<span class="btn-text">Try Ansible Sandbox</span>
|
||||
<span class="offline-badge">Offline</span> {/* Status updated by JS */}
|
||||
</a>
|
||||
<a href="#architecture" class="btn btn-outline">
|
||||
<i class="fas fa-network-wired btn-icon"></i>
|
||||
<span class="btn-text">Explore Architecture</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-terminal">
|
||||
<div class="terminal-header">
|
||||
<div class="terminal-buttons">
|
||||
<span class="terminal-btn close"></span>
|
||||
<span class="terminal-btn minimize"></span>
|
||||
<span class="terminal-btn maximize"></span>
|
||||
</div>
|
||||
<div class="terminal-title">argobox ~ k8s-status</div>
|
||||
</div>
|
||||
<div class="terminal-body">
|
||||
<div class="terminal-line">$ kubectl get nodes</div>
|
||||
<div class="terminal-line output">NAME STATUS ROLES AGE VERSION</div>
|
||||
<div class="terminal-line output">argobox Ready control-plane,master 154d v1.25.16+k3s1</div>
|
||||
<div class="terminal-line output">argobox-lite Ready worker 154d v1.25.16+k3s1</div>
|
||||
<div class="terminal-line blank"> </div>
|
||||
<div class="terminal-line">$ kubectl get pods -A | grep Running | wc -l</div>
|
||||
<div class="terminal-line output">32</div>
|
||||
<div class="terminal-line blank"> </div>
|
||||
<div class="terminal-line">$ uptime</div>
|
||||
<div class="terminal-line output">14:30:25 up 154 days, 23:12, 1 user, load average: 0.22, 0.18, 0.15</div>
|
||||
<div class="terminal-line blank"> </div>
|
||||
<div class="terminal-line">$ ansible-playbook status.yml</div>
|
||||
<div class="terminal-line output">PLAY [Check system status] *******************************************</div>
|
||||
<div class="terminal-line output">TASK [Gathering Facts] **********************************************</div>
|
||||
<div class="terminal-line output success">ok: [argobox]</div>
|
||||
<div class="terminal-line output success">ok: [argobox-lite]</div>
|
||||
<div class="terminal-line output">TASK [Check service status] *****************************************</div>
|
||||
<div class="terminal-line output success">ok: [argobox]</div>
|
||||
<div class="terminal-line output success">ok: [argobox-lite]</div>
|
||||
<div class="terminal-line output">PLAY RECAP **********************************************************</div>
|
||||
<div class="terminal-line output success">argobox : ok=2 changed=0 unreachable=0 failed=0 skipped=0</div>
|
||||
<div class="terminal-line output success">argobox-lite: ok=2 changed=0 unreachable=0 failed=0 skipped=0</div>
|
||||
<div class="terminal-line typing">$ <span class="cursor">|</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Architecture Section -->
|
||||
<section id="architecture" class="architecture section-padding">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Infrastructure Architecture</h2>
|
||||
<p class="section-description">
|
||||
Enterprise-grade network topology with redundancy, virtualization, and secure segmentation.
|
||||
</p>
|
||||
</div>
|
||||
{/* Consider replacing with an actual image or a more maintainable diagram component */}
|
||||
<img src="/images/homelab/argobox-architecture.svg" alt="ArgoBox Architecture Diagram" class="architecture-diagram-image" />
|
||||
{/* Fallback or simplified diagram if image isn't available */}
|
||||
<div class="architecture-details">
|
||||
<div class="detail-card">
|
||||
<div class="detail-icon"><i class="fas fa-shield-alt"></i></div>
|
||||
<h3 class="detail-title">Network Security</h3>
|
||||
<p class="detail-description">
|
||||
Enterprise firewall with network segmentation using VLANs and strict access controls. Redundant routing with automatic failover between OPNsense and OpenWrt.
|
||||
</p>
|
||||
</div>
|
||||
<div class="detail-card">
|
||||
<div class="detail-icon"><i class="fas fa-cloud"></i></div>
|
||||
<h3 class="detail-title">Virtualization</h3>
|
||||
<p class="detail-description">
|
||||
Proxmox virtualization platform with ZFS storage pools in RAID10 configuration. Optimized storage pools for VMs and containers with proper resource allocation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="detail-card">
|
||||
<div class="detail-icon"><i class="fas fa-route"></i></div>
|
||||
<h3 class="detail-title">High Availability</h3>
|
||||
<p class="detail-description">
|
||||
Full redundancy with failover routing, replicated storage, and resilient services. Automatic service recovery and load balancing across nodes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Technologies Section -->
|
||||
<section id="technologies" class="technologies section-padding alt-bg">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Core Technologies</h2>
|
||||
<p class="section-description">
|
||||
The ArgoBox lab leverages cutting-edge open source technologies to create a powerful, flexible infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
<div class="tech-grid">
|
||||
{/* Data could be externalized */}
|
||||
<div class="tech-card">
|
||||
<div class="tech-icon"><i class="fas fa-dharmachakra"></i></div>
|
||||
<h3 class="tech-title">Kubernetes (K3s)</h3>
|
||||
<p class="tech-description">Lightweight Kubernetes distribution running across multiple nodes for container orchestration. Powers all microservices and applications.</p>
|
||||
<div class="tech-features"><span class="tech-feature">Multi-node cluster</span><span class="tech-feature">Persistent volumes</span><span class="tech-feature">Traefik ingress</span><span class="tech-feature">Auto-healing</span></div>
|
||||
</div>
|
||||
<div class="tech-card featured">
|
||||
<div class="tech-icon"><i class="fab fa-ansible"></i></div>
|
||||
<h3 class="tech-title">Ansible Automation</h3>
|
||||
<p class="tech-description">Infrastructure as code platform for automated provisioning, configuration management, and application deployment across the entire environment.</p>
|
||||
<div class="tech-features"><span class="tech-feature">Playbook library</span><span class="tech-feature">Role-based configs</span><span class="tech-feature">Interactive sandbox</span><span class="tech-feature">Idempotent workflows</span></div>
|
||||
</div>
|
||||
<div class="tech-card">
|
||||
<div class="tech-icon"><i class="fas fa-server"></i></div>
|
||||
<h3 class="tech-title">Proxmox</h3>
|
||||
<p class="tech-description">Enterprise-class virtualization platform running virtual machines and containers with ZFS storage backend for data integrity.</p>
|
||||
<div class="tech-features"><span class="tech-feature">ZFS storage</span><span class="tech-feature">Resource balancing</span><span class="tech-feature">Live migration</span><span class="tech-feature">Hardware passthrough</span></div>
|
||||
</div>
|
||||
<div class="tech-card">
|
||||
<div class="tech-icon"><i class="fas fa-shield-alt"></i></div>
|
||||
<h3 class="tech-title">Zero Trust Security</h3>
|
||||
<p class="tech-description">Comprehensive security architecture with Cloudflare tunnels, network segmentation, and authentication at all service boundaries.</p>
|
||||
<div class="tech-features"><span class="tech-feature">Cloudflare tunnels</span><span class="tech-feature">OPNsense firewall</span><span class="tech-feature">VLAN segmentation</span><span class="tech-feature">WireGuard VPN</span></div>
|
||||
</div>
|
||||
<div class="tech-card">
|
||||
<div class="tech-icon"><i class="fas fa-database"></i></div>
|
||||
<h3 class="tech-title">PostgreSQL</h3>
|
||||
<p class="tech-description">Enterprise database cluster for application data storage with automated backups, replication, and performance optimization.</p>
|
||||
<div class="tech-features"><span class="tech-feature">Automated backups</span><span class="tech-feature">Connection pooling</span><span class="tech-feature">Optimized for K8s</span><span class="tech-feature">Multi-app support</span></div>
|
||||
</div>
|
||||
<div class="tech-card">
|
||||
<div class="tech-icon"><i class="fas fa-chart-line"></i></div>
|
||||
<h3 class="tech-title">Monitoring Stack</h3>
|
||||
<p class="tech-description">Comprehensive monitoring with Prometheus, Grafana, and AlertManager for real-time visibility into all infrastructure components.</p>
|
||||
<div class="tech-features"><span class="tech-feature">Prometheus metrics</span><span class="tech-feature">Grafana dashboards</span><span class="tech-feature">Automated alerts</span><span class="tech-feature">Historical data</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Services Section -->
|
||||
<section id="services" class="services section-padding">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Available Services</h2>
|
||||
<p class="section-description">
|
||||
Explore the various services and applications hosted in the ArgoBox environment.
|
||||
</p>
|
||||
</div>
|
||||
<div class="services-info-banner">
|
||||
<i class="fas fa-info-circle info-icon"></i>
|
||||
<p>Some services require authentication and are restricted. Available public services are highlighted and clickable.</p>
|
||||
</div>
|
||||
<div class="services-grid">
|
||||
{Object.entries(servicesData).map(([categoryKey, categoryServices]) => (
|
||||
<div class="services-category">
|
||||
<h3 class="category-title">
|
||||
<i class={`fas ${
|
||||
categoryKey === 'development' ? 'fa-code' :
|
||||
categoryKey === 'media' ? 'fa-photo-video' :
|
||||
categoryKey === 'utilities' ? 'fa-tools' :
|
||||
'fa-cogs' // Default for infrastructure
|
||||
} category-icon`}></i>
|
||||
{categoryKey.charAt(0).toUpperCase() + categoryKey.slice(1)} Tools
|
||||
</h3>
|
||||
<div class="service-items">
|
||||
{categoryServices.map(service => (
|
||||
<a
|
||||
href={service.available ? service.url : '#'}
|
||||
class:list={["service-item", { available: service.available }, `service-${service.name.toLowerCase().replace(/\s+/g, '-')}`]}
|
||||
target={service.available ? "_blank" : undefined}
|
||||
rel={service.available ? "noopener noreferrer" : undefined}
|
||||
aria-disabled={!service.available}
|
||||
>
|
||||
<div class="service-icon"><i class={service.icon}></i></div>
|
||||
<div class="service-info">
|
||||
<div class="service-name">{service.name}</div>
|
||||
<p class="service-description">{service.description}</p>
|
||||
</div>
|
||||
<span class={`service-status ${service.status}`}>
|
||||
<span class="status-dot"></span>
|
||||
{service.status.charAt(0).toUpperCase() + service.status.slice(1)}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Projects Section -->
|
||||
<section id="projects" class="projects section-padding alt-bg">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Related Projects & Code</h2>
|
||||
<p class="section-description">
|
||||
Explore associated projects, configurations, and code repositories related to the ArgoBox lab.
|
||||
</p>
|
||||
</div>
|
||||
<div class="projects-grid">
|
||||
{projectsData.map(project => (
|
||||
<a href={project.url} class="project-card" target={project.url.startsWith('http') ? '_blank' : undefined} rel={project.url.startsWith('http') ? 'noopener noreferrer' : undefined}>
|
||||
<div class="project-header">
|
||||
<div class="project-icon"><i class={project.icon}></i></div>
|
||||
<h3 class="project-title">{project.title}</h3>
|
||||
</div>
|
||||
<p class="project-description">{project.description}</p>
|
||||
<div class="project-tech">
|
||||
{project.tech.map(tech => <span class="tech-badge">{tech}</span>)}
|
||||
</div>
|
||||
<div class="project-cta">
|
||||
<span class="btn btn-sm btn-outline">
|
||||
{project.url.startsWith('http') ? 'View Project' : 'View Details'} <i class="fas fa-arrow-right"></i>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Dashboards Section -->
|
||||
<section id="dashboards" class="dashboards section-padding">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Live Dashboards</h2>
|
||||
<p class="section-description">
|
||||
Real-time monitoring dashboards providing insights into the lab's performance and status. (Authentication Required)
|
||||
</p>
|
||||
</div>
|
||||
<div class="services-info-banner"> {/* Reusing banner style */}
|
||||
<i class="fas fa-lock info-icon"></i>
|
||||
<p>Access to live dashboards requires authentication via Cloudflare Access.</p>
|
||||
</div>
|
||||
<div class="dashboard-grid">
|
||||
{dashboardsData.map(dash => (
|
||||
<a href={dash.url} class="dashboard-card" target="_blank" rel="noopener noreferrer">
|
||||
<div class={`dashboard-preview ${dash.previewClass}`}>
|
||||
<div class="dashboard-overlay">
|
||||
<div class="overlay-content">
|
||||
<div class="overlay-icon"><i class={dash.icon}></i></div>
|
||||
<div class="overlay-text">View Dashboard</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-info">
|
||||
<h3 class="dashboard-title">{dash.title}</h3>
|
||||
<p class="dashboard-description">{dash.description}</p>
|
||||
<div class="dashboard-cta">
|
||||
<span class="btn btn-sm btn-primary">Access Dashboard</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Contact Section - Optional: Can be moved to a separate page */}
|
||||
{/*
|
||||
<section id="contact" class="contact section-padding alt-bg">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Get In Touch</h2>
|
||||
<p class="section-description">Have questions or want to collaborate? Reach out!</p>
|
||||
</div>
|
||||
<div class="contact-grid">
|
||||
<div class="contact-info">
|
||||
<div class="contact-item">
|
||||
<div class="contact-icon"><i class="fas fa-envelope"></i></div>
|
||||
<h3 class="contact-title">Email</h3>
|
||||
<a href={`mailto:${contactInfo.email}`} class="contact-link">{contactInfo.email}</a>
|
||||
</div>
|
||||
Add other contact items like LinkedIn, GitHub etc.
|
||||
</div>
|
||||
<div class="contact-form-container">
|
||||
<form id="contact-form" class="contact-form">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" name="name" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject">Subject</label>
|
||||
<input type="text" id="subject" name="subject" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="message">Message</label>
|
||||
<textarea id="message" name="message" required></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Send Message</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
*/}
|
||||
|
||||
</main>
|
||||
|
||||
<Footer slot="footer" />
|
||||
</BaseLayout>
|
||||
|
||||
<style is:global>
|
||||
/* Global styles - can be moved to a separate CSS file if needed */
|
||||
.section-padding {
|
||||
padding: 5rem 0;
|
||||
/* Import relevant styles from styles.css, adapted for Astro */
|
||||
/* NOTE: General resets, body, typography, basic buttons are handled by global.css/theme.css */
|
||||
|
||||
/* Hero Section Specific Styles */
|
||||
.hero {
|
||||
min-height: 100vh; /* Use min-height instead of height */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding-top: 6rem; /* Adjust as needed */
|
||||
padding-bottom: 4rem; /* Add padding */
|
||||
background: linear-gradient(180deg, var(--bg-secondary), var(--bg-primary)); /* Use theme vars */
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 3rem;
|
||||
align-items: center;
|
||||
position: relative; /* Ensure content is above particles */
|
||||
z-index: 1;
|
||||
}
|
||||
.particles-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
.particle {
|
||||
position: absolute;
|
||||
background-color: var(--accent); /* Use theme var */
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
/* Animation will be added by script */
|
||||
}
|
||||
@keyframes float-particle { /* Keep keyframes */
|
||||
0% { transform: translateY(0) translateX(0); opacity: 0.3; }
|
||||
50% { transform: translateY(-100px) translateX(50px); opacity: 0.1; }
|
||||
100% { transform: translateY(0) translateX(0); opacity: 0.3; }
|
||||
}
|
||||
.hero-text { /* Styles seem okay */ }
|
||||
.hero-title {
|
||||
font-size: clamp(2.5rem, 5vw, 3.25rem); /* Adjust size */
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.2;
|
||||
font-weight: 700; /* Use theme font weight */
|
||||
color: var(--text-primary); /* Use theme var */
|
||||
}
|
||||
.hero-title .highlight {
|
||||
background: var(--accent-gradient); /* Use theme var */
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
position: relative;
|
||||
}
|
||||
.hero-title .highlight::after { /* Optional underline effect */
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 4px; /* Adjust thickness */
|
||||
bottom: 2px; /* Adjust position */
|
||||
left: 0;
|
||||
background: var(--accent-gradient);
|
||||
border-radius: 2px;
|
||||
opacity: 0.3;
|
||||
z-index: -1;
|
||||
}
|
||||
.hero-description {
|
||||
font-size: var(--font-size-lg); /* Use theme var */
|
||||
color: var(--text-secondary); /* Use theme var */
|
||||
margin-bottom: 2rem;
|
||||
max-width: 550px;
|
||||
}
|
||||
.hero-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.stat-item { display: flex; align-items: center; gap: 0.75rem; }
|
||||
.stat-icon {
|
||||
width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center;
|
||||
background: var(--accent-gradient); border-radius: 0.5rem; color: white; font-size: 1.25rem;
|
||||
}
|
||||
.stat-detail { display: flex; flex-direction: column; }
|
||||
.stat-value { font-weight: 700; font-size: 1.25rem; color: var(--text-primary); }
|
||||
.stat-name { font-size: 0.875rem; color: var(--text-secondary); }
|
||||
.cta-buttons { display: flex; flex-wrap: wrap; gap: 1rem; }
|
||||
/* Use Astro theme button classes (.cta-button.primary/secondary) if possible */
|
||||
/* Or adapt these styles */
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; justify-content: center; padding: 0.75rem 1.5rem;
|
||||
font-weight: 600; border-radius: 0.5rem; transition: all var(--transition-normal);
|
||||
cursor: pointer; position: relative; overflow: hidden; border: none; outline: none; gap: 0.75rem;
|
||||
text-decoration: none; /* Ensure links look like buttons */
|
||||
}
|
||||
.btn-primary { background: var(--accent-gradient); color: white; /* ... other styles */ }
|
||||
.btn-primary:hover { /* ... hover styles */ }
|
||||
.btn-outline { background-color: transparent; border: 2px solid var(--accent); color: var(--accent); }
|
||||
.btn-outline:hover { background-color: var(--accent); color: white; }
|
||||
.btn-danger { background-color: var(--error); border-color: var(--error); color: white; } /* Use theme error color */
|
||||
.btn-icon { font-size: 0.9rem; }
|
||||
.offline-badge, .online-badge { /* Styles from inline block */
|
||||
display: inline-block; padding: 0.25rem 0.5rem; border-radius: 0.25rem;
|
||||
font-size: 0.75rem; font-weight: 600; margin-left: 0.5rem;
|
||||
}
|
||||
.offline-badge { background-color: #991b1b; color: white; } /* Darker red */
|
||||
.online-badge { background-color: var(--success); color: white; display: none; } /* Use theme success */
|
||||
|
||||
/* Hero Terminal Styles */
|
||||
.hero-terminal {
|
||||
width: 100%; border-radius: 0.75rem; overflow: hidden;
|
||||
box-shadow: var(--card-shadow); /* Use theme shadow */
|
||||
background-color: #0d1117; /* Keep specific terminal bg */
|
||||
border: 1px solid var(--border); /* Use theme border */
|
||||
/* transform: perspective(1000px) rotateY(5deg) rotateX(2deg); */ /* Remove or adjust transform */
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
/* .hero-terminal:hover { transform: perspective(1000px) rotateY(0deg) rotateX(0deg); } */
|
||||
.terminal-header { display: flex; align-items: center; background-color: #161b22; padding: 0.5rem 1rem; border-bottom: 1px solid var(--border); }
|
||||
.terminal-buttons { display: flex; gap: 0.5rem; margin-right: 1rem; }
|
||||
.terminal-btn { width: 12px; height: 12px; border-radius: 50%; }
|
||||
.terminal-btn.close { background-color: #ff5f56; }
|
||||
.terminal-btn.minimize { background-color: #ffbd2e; }
|
||||
.terminal-btn.maximize { background-color: #27c93f; }
|
||||
.terminal-title { color: var(--text-secondary); font-size: 0.875rem; font-family: var(--font-mono); }
|
||||
.terminal-body { padding: 1rem; font-family: var(--font-mono); font-size: 0.875rem; color: var(--text-primary); line-height: 1.4; max-height: 400px; overflow-y: auto; }
|
||||
.terminal-line { margin-bottom: 0.25rem; white-space: pre-wrap; }
|
||||
.terminal-line.output { color: var(--text-secondary); }
|
||||
.terminal-line.success { color: var(--success); } /* Use theme color */
|
||||
.terminal-line.error { color: var(--error); } /* Use theme color */
|
||||
.terminal-line.typing { color: var(--accent); } /* Use theme color */
|
||||
.terminal-line .cursor { display: inline-block; width: 8px; height: 15px; background-color: var(--accent); animation: blink 1s step-end infinite; }
|
||||
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
||||
|
||||
/* Architecture Section */
|
||||
.architecture { /* Use section-padding */ }
|
||||
.section-header { text-align: center; margin-bottom: 3rem; } /* Adjust margin */
|
||||
.section-title { font-size: var(--font-size-3xl); margin-bottom: 1rem; position: relative; display: inline-block; color: var(--text-primary); }
|
||||
.section-title::after { content: ''; position: absolute; bottom: -0.5rem; left: 50%; transform: translateX(-50%); width: 80px; height: 4px; background: var(--accent-gradient); border-radius: 2px; }
|
||||
.section-description { max-width: 700px; margin: 0 auto; color: var(--text-secondary); font-size: var(--font-size-lg); }
|
||||
.architecture-diagram-image { display: block; max-width: 800px; margin: 3rem auto; border-radius: 8px; box-shadow: var(--card-shadow); }
|
||||
.architecture-details { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; margin-top: 3rem; }
|
||||
.detail-card { background-color: var(--card-bg); border: 1px solid var(--border); border-radius: 0.75rem; padding: 1.5rem; transition: all var(--transition-normal); }
|
||||
.detail-card:hover { transform: translateY(-5px); box-shadow: var(--card-shadow); border-color: var(--accent); }
|
||||
.detail-icon { font-size: 2rem; color: var(--accent); margin-bottom: 1rem; }
|
||||
.detail-title { font-size: 1.25rem; margin-bottom: 0.75rem; color: var(--text-primary); }
|
||||
.detail-description { color: var(--text-secondary); font-size: var(--font-size-sm); line-height: 1.6; }
|
||||
|
||||
/* Technologies Section */
|
||||
.technologies { /* Use section-padding alt-bg */ }
|
||||
.tech-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 2rem; margin-top: 3rem; }
|
||||
.tech-card { background-color: var(--card-bg); border: 1px solid var(--border); border-radius: 0.75rem; padding: 2rem; transition: all var(--transition-normal); display: flex; flex-direction: column; }
|
||||
.tech-card:hover { transform: translateY(-10px); box-shadow: var(--card-shadow); border-color: var(--accent); }
|
||||
.tech-card.featured { background: linear-gradient(145deg, rgba(59, 130, 246, 0.1), rgba(37, 99, 235, 0.05)); border-color: var(--accent); position: relative; overflow: hidden; }
|
||||
.tech-card.featured::before { content: ''; position: absolute; top: 0; right: 0; width: 100px; height: 100px; background: var(--accent-gradient); transform: rotate(45deg) translate(20px, -60px); opacity: 0.3; }
|
||||
.tech-icon { font-size: 2.5rem; color: var(--accent); margin-bottom: 1.5rem; transition: all var(--transition-normal); }
|
||||
.tech-card:hover .tech-icon { transform: scale(1.1); /* text-shadow: var(--accent-glow); */ } /* Glow might be too much */
|
||||
.tech-title { font-size: 1.5rem; margin-bottom: 1rem; color: var(--text-primary); }
|
||||
.tech-description { color: var(--text-secondary); margin-bottom: 1.5rem; flex-grow: 1; font-size: var(--font-size-sm); }
|
||||
.tech-features { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: auto; } /* Push to bottom */
|
||||
.tech-feature { background-color: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); color: var(--accent); font-size: 0.8rem; font-weight: 500; padding: 0.25rem 0.75rem; border-radius: 9999px; }
|
||||
|
||||
/* Services Section */
|
||||
.services { /* Use section-padding */ }
|
||||
.services-info-banner { display: flex; align-items: center; gap: 1rem; background-color: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.2); border-radius: 0.75rem; padding: 1rem 1.5rem; margin-bottom: 2rem; }
|
||||
.info-icon { font-size: 1.5rem; color: var(--accent); }
|
||||
.services-info-banner p { color: var(--text-secondary); margin: 0; font-size: var(--font-size-sm); }
|
||||
.services-grid { display: flex; flex-direction: column; gap: 2.5rem; margin-top: 2rem; }
|
||||
.services-category { background-color: var(--card-bg); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; transition: all var(--transition-normal); }
|
||||
.services-category:hover { transform: translateY(-5px); box-shadow: var(--card-shadow); border-color: var(--accent); }
|
||||
.category-title { display: flex; align-items: center; gap: 0.75rem; padding: 1.25rem; background-color: rgba(15, 23, 42, 0.5); border-bottom: 1px solid var(--border); font-size: 1.35rem; color: var(--text-primary); }
|
||||
.category-icon { color: var(--accent); }
|
||||
.service-items { display: flex; flex-direction: column; }
|
||||
.service-item { display: flex; align-items: center; padding: 1.25rem; border-bottom: 1px solid var(--border); transition: all var(--transition-normal); color: var(--text-primary); text-decoration: none; }
|
||||
.service-item:last-child { border-bottom: none; }
|
||||
.service-item.available { cursor: pointer; }
|
||||
.service-item.available:hover { background-color: rgba(15, 23, 42, 0.3); }
|
||||
.service-item:not(.available) { cursor: default; opacity: 0.6; } /* Dim unavailable */
|
||||
.service-icon { width: 2.5rem; height: 2.5rem; display: flex; align-items: center; justify-content: center; margin-right: 1rem; background-color: rgba(59, 130, 246, 0.1); border-radius: 0.5rem; font-size: 1.25rem; color: var(--accent); transition: all var(--transition-normal); flex-shrink: 0; }
|
||||
.service-item.available:hover .service-icon { background-color: rgba(59, 130, 246, 0.2); transform: scale(1.1); }
|
||||
.service-info { flex: 1; }
|
||||
.service-name { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.25rem; color: var(--text-primary); }
|
||||
.service-description { font-size: 0.9rem; color: var(--text-secondary); }
|
||||
.service-status { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; font-weight: 500; padding: 0.25rem 0.75rem; border-radius: 9999px; margin-left: 1rem; }
|
||||
.service-status.live { background-color: rgba(16, 185, 129, 0.1); color: var(--success); }
|
||||
.service-status.maintenance { background-color: rgba(245, 158, 11, 0.1); color: var(--warning); }
|
||||
.service-status.restricted { background-color: rgba(107, 114, 128, 0.1); color: var(--text-secondary); }
|
||||
.status-dot { width: 8px; height: 8px; border-radius: 50%; }
|
||||
.service-status.live .status-dot { background-color: var(--success); }
|
||||
.service-status.maintenance .status-dot { background-color: var(--warning); }
|
||||
.service-status.restricted .status-dot { background-color: var(--text-secondary); }
|
||||
/* Offline service styling from inline */
|
||||
.offline-service { position: relative; }
|
||||
.offline-service::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.3); border-radius: 0.5rem; pointer-events: none; z-index: 1; }
|
||||
.offline-service .service-icon { color: var(--error); }
|
||||
.offline-service .service-status.offline .status-dot { background-color: var(--error); box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); animation: pulse-red 2s infinite; }
|
||||
@keyframes pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
|
||||
|
||||
/* Projects Section */
|
||||
.projects { /* Use section-padding alt-bg */ }
|
||||
.projects-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 2rem; margin-top: 3rem; }
|
||||
.project-card { background-color: var(--card-bg); border: 1px solid var(--border); border-radius: 0.75rem; padding: 1.5rem; transition: all var(--transition-normal); display: flex; flex-direction: column; text-decoration: none; } /* Added text-decoration */
|
||||
.project-card:hover { transform: translateY(-10px); box-shadow: var(--card-shadow); border-color: var(--accent); }
|
||||
.project-header { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; }
|
||||
.project-icon { font-size: 1.75rem; color: var(--accent); transition: all var(--transition-normal); }
|
||||
.project-card:hover .project-icon { transform: scale(1.1); }
|
||||
.project-title { font-size: 1.25rem; margin: 0; color: var(--text-primary); }
|
||||
.project-description { color: var(--text-secondary); margin-bottom: 1.5rem; flex-grow: 1; font-size: var(--font-size-sm); }
|
||||
.project-tech { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem; }
|
||||
.tech-badge { background-color: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); color: var(--accent); font-size: 0.8rem; font-weight: 500; padding: 0.25rem 0.75rem; border-radius: 9999px; }
|
||||
.project-cta { margin-top: auto; }
|
||||
.btn-sm { padding: 0.5rem 1rem; font-size: 0.875rem; } /* Define btn-sm if not global */
|
||||
|
||||
/* Dashboards Section */
|
||||
.dashboards { /* Use section-padding */ }
|
||||
.dashboard-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem; margin-top: 3rem; } /* Use auto-fit */
|
||||
.dashboard-card { background: var(--card-bg); border-radius: 8px; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; border: 1px solid var(--border); text-decoration: none; }
|
||||
.dashboard-card:hover { transform: translateY(-5px); box-shadow: var(--card-shadow); border-color: var(--accent); }
|
||||
.dashboard-preview { height: 200px; background-size: cover; background-position: center; position: relative; background-color: var(--secondary-bg); /* Fallback bg */ }
|
||||
/* Add specific preview backgrounds if needed, or use actual images */
|
||||
.dashboard-preview.infrastructure { /* background-image: ... */ }
|
||||
.dashboard-preview.kubernetes { /* background-image: ... */ }
|
||||
.dashboard-preview.network { /* background-image: ... */ }
|
||||
.dashboard-preview.services { /* background-image: ... */ }
|
||||
.dashboard-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s ease; }
|
||||
.dashboard-card:hover .dashboard-overlay { opacity: 1; }
|
||||
.overlay-content { text-align: center; color: #ffffff; }
|
||||
.overlay-icon { font-size: 2rem; margin-bottom: 0.5rem; }
|
||||
.overlay-text { font-size: 1rem; opacity: 0.8; }
|
||||
.dashboard-info { padding: 1.5rem; }
|
||||
.dashboard-title { font-size: 1.25rem; margin-bottom: 0.5rem; color: var(--text-primary); }
|
||||
.dashboard-description { font-size: 0.9rem; color: var(--text-secondary); margin-bottom: 1rem; }
|
||||
.dashboard-cta .btn-sm { padding: 0.5rem 1rem; font-size: 0.9rem; }
|
||||
|
||||
/* General Responsive */
|
||||
.section-padding { padding: 4rem 1rem; } /* Add horizontal padding */
|
||||
.alt-bg {
|
||||
/* Use padding instead of negative margins for full bleed */
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
background-color: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border-secondary);
|
||||
border-bottom: 1px solid var(--border-secondary);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
.alt-bg > .container { /* Ensure container inside alt-bg keeps padding */
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.hero-content { grid-template-columns: 1fr; text-align: center; }
|
||||
.hero-text { order: 2; }
|
||||
.hero-terminal { order: 1; margin: 0 auto 2rem; max-width: 600px; }
|
||||
.hero-stats { justify-content: center; }
|
||||
.cta-buttons { justify-content: center; }
|
||||
}
|
||||
|
||||
.section-description {
|
||||
font-size: 1.125rem;
|
||||
color: var(--text-secondary);
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
@media (max-width: 768px) {
|
||||
.section-padding { padding: 3rem 1rem; }
|
||||
.alt-bg { padding-top: 3rem; padding-bottom: 3rem; }
|
||||
.hero { padding-top: 5rem; padding-bottom: 3rem; min-height: auto; }
|
||||
.hero-title { font-size: 2.25rem; }
|
||||
.section-title { font-size: var(--font-size-2xl); }
|
||||
.section-header { flex-direction: column; align-items: center; gap: 0.5rem; margin-bottom: 2rem; }
|
||||
.section-description { font-size: var(--font-size-base); }
|
||||
.tech-grid, .projects-grid, .dashboard-grid, .architecture-details { grid-template-columns: 1fr; }
|
||||
.services-grid { gap: 1.5rem; }
|
||||
.service-item { flex-direction: column; align-items: flex-start; }
|
||||
.service-status { margin-left: 0; margin-top: 0.5rem; }
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Adapted from script.js
|
||||
|
||||
// --- Particle Animation ---
|
||||
function createBackgroundParticles(count = 30) { // Reduced default count
|
||||
const particlesContainer = document.getElementById('particles-container');
|
||||
if (!particlesContainer) return;
|
||||
particlesContainer.innerHTML = ''; // Clear existing
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const particle = document.createElement('div');
|
||||
particle.classList.add('particle');
|
||||
const size = Math.random() * 3 + 1; // Smaller size
|
||||
particle.style.width = `${size}px`;
|
||||
particle.style.height = `${size}px`;
|
||||
particle.style.left = `${Math.random() * 100}%`;
|
||||
particle.style.top = `${Math.random() * 100}%`;
|
||||
particle.style.opacity = (Math.random() * 0.2 + 0.05).toString(); // More subtle
|
||||
particle.style.animation = `float-particle ${Math.random() * 25 + 15}s linear infinite`;
|
||||
particle.style.animationDelay = `${Math.random() * 15}s`;
|
||||
particlesContainer.appendChild(particle);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Terminal Cursor ---
|
||||
function initTerminalTyping() {
|
||||
const cursor = document.querySelector('.hero-terminal .cursor');
|
||||
if (cursor) {
|
||||
setInterval(() => {
|
||||
cursor.style.opacity = cursor.style.opacity === '0' ? '1' : '0';
|
||||
}, 600);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Status Checks (Placeholder - Requires actual API endpoints) ---
|
||||
function checkAnsibleSandboxStatus() {
|
||||
const btn = document.getElementById('ansible-sandbox-btn');
|
||||
const badge = btn?.querySelector('.offline-badge');
|
||||
if (!btn || !badge) return;
|
||||
|
||||
// Replace with actual API call
|
||||
const isOnline = false; // Simulate offline for now
|
||||
|
||||
if (isOnline) {
|
||||
btn.classList.remove('btn-danger');
|
||||
btn.classList.add('btn-primary', 'pulse'); // Add pulse if desired
|
||||
badge.textContent = 'Online';
|
||||
badge.classList.remove('offline-badge');
|
||||
badge.classList.add('online-badge');
|
||||
badge.style.display = 'inline-block';
|
||||
} else {
|
||||
btn.classList.remove('btn-primary', 'pulse');
|
||||
btn.classList.add('btn-danger');
|
||||
badge.textContent = 'Offline';
|
||||
badge.classList.remove('online-badge');
|
||||
badge.classList.add('offline-badge');
|
||||
badge.style.display = 'inline-block'; // Ensure it's shown
|
||||
}
|
||||
}
|
||||
|
||||
function checkLiveDashboardStatus() {
|
||||
const indicator = document.querySelector('.dashboard-link .live-indicator');
|
||||
if (!indicator) return;
|
||||
|
||||
// Replace with actual API call
|
||||
const isOnline = false; // Simulate offline
|
||||
|
||||
if (isOnline) {
|
||||
indicator.classList.remove('offline');
|
||||
} else {
|
||||
indicator.classList.add('offline');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Initialization ---
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('particles-container')) {
|
||||
createBackgroundParticles();
|
||||
// Optional: Add resize listener if particle count should change
|
||||
// window.addEventListener('resize', () => createBackgroundParticles(window.innerWidth <= 768 ? 15 : 30));
|
||||
}
|
||||
if (document.querySelector('.hero-terminal .cursor')) {
|
||||
initTerminalTyping();
|
||||
}
|
||||
// Initial status checks
|
||||
checkAnsibleSandboxStatus();
|
||||
checkLiveDashboardStatus();
|
||||
// Optional: Set interval to re-check status periodically
|
||||
// setInterval(checkAnsibleSandboxStatus, 60000); // Check every minute
|
||||
// setInterval(checkLiveDashboardStatus, 60000);
|
||||
});
|
||||
|
||||
// --- Contact Form Submission (If form is included on this page) ---
|
||||
/*
|
||||
const contactForm = document.getElementById('contact-form');
|
||||
if (contactForm) {
|
||||
contactForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const submitButton = contactForm.querySelector('button[type="submit"]');
|
||||
const originalButtonText = submitButton.innerHTML;
|
||||
const formMessages = contactForm.querySelector('.form-messages') || document.createElement('div'); // Add a div for messages if needed
|
||||
formMessages.className = 'form-messages';
|
||||
if (!contactForm.contains(formMessages)) {
|
||||
contactForm.insertBefore(formMessages, submitButton);
|
||||
}
|
||||
formMessages.innerHTML = ''; // Clear previous messages
|
||||
|
||||
try {
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
||||
|
||||
const formData = new FormData(contactForm);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
|
||||
const response = await fetch('/api/contact', { // Use the Astro API route
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
formMessages.innerHTML = `<div class="alert alert-success"><i class="fas fa-check-circle"></i> ${result.message}</div>`;
|
||||
contactForm.reset();
|
||||
} else {
|
||||
throw new Error(result.message || 'Failed to send message');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending contact form:', error);
|
||||
formMessages.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${error.message}</div>`;
|
||||
} finally {
|
||||
submitButton.disabled = false;
|
||||
submitButton.innerHTML = originalButtonText;
|
||||
setTimeout(() => { formMessages.innerHTML = ''; }, 5000); // Clear message after 5s
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
</script>
|
|
@ -6,6 +6,7 @@ import Header from '../components/Header.astro';
|
|||
import Footer from '../components/Footer.astro';
|
||||
import Terminal from '../components/Terminal.astro';
|
||||
import PostCard from '../components/PostCard.astro';
|
||||
import MiniKnowledgeGraph from '../components/MiniKnowledgeGraph.astro';
|
||||
import '../styles/card-animations.css';
|
||||
|
||||
const title = "ArgoBox | Enterprise-Grade Home Lab & DevOps Hub";
|
||||
|
@ -47,6 +48,32 @@ const projectHighlights = [
|
|||
}
|
||||
];
|
||||
|
||||
// Enhanced Graph Data for Homepage Feature
|
||||
const miniGraphData = {
|
||||
nodes: [
|
||||
{ id: 'kubernetes', label: 'Kubernetes', type: 'tag' },
|
||||
{ id: 'homelab', label: 'Home Lab', type: 'tag' },
|
||||
{ id: 'devops', label: 'DevOps', type: 'tag' },
|
||||
{ id: 'automation', label: 'Automation', type: 'tag' },
|
||||
{ id: 'infrastructure', label: 'Infrastructure', type: 'tag' },
|
||||
{ id: 'post1', label: 'K3s Cluster Setup', type: 'post' },
|
||||
{ id: 'post2', label: 'GitOps Workflow', type: 'post' },
|
||||
{ id: 'post3', label: 'Home Lab Monitoring', type: 'post' },
|
||||
{ id: 'post4', label: 'IaC Best Practices', type: 'post' },
|
||||
],
|
||||
edges: [
|
||||
{ source: 'post1', target: 'kubernetes', type: 'post-tag' },
|
||||
{ source: 'post1', target: 'homelab', type: 'post-tag' },
|
||||
{ source: 'post2', target: 'devops', type: 'post-tag' },
|
||||
{ source: 'post2', target: 'kubernetes', type: 'post-tag' },
|
||||
{ source: 'post2', target: 'automation', type: 'post-tag' },
|
||||
{ source: 'post3', target: 'homelab', type: 'post-tag' },
|
||||
{ source: 'post3', target: 'infrastructure', type: 'post-tag' },
|
||||
{ source: 'post4', target: 'infrastructure', type: 'post-tag' },
|
||||
{ source: 'post4', target: 'automation', type: 'post-tag' },
|
||||
]
|
||||
};
|
||||
|
||||
// Define Commands for Hero Terminal
|
||||
const heroCommands = [
|
||||
{ prompt: "[user@argobox]$ ", command: "uname -a", output: ["Linux argobox 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64 GNU/Linux"] },
|
||||
|
@ -72,7 +99,7 @@ const heroCommands = [
|
|||
</p>
|
||||
<div class="hero-cta">
|
||||
<a href="/blog" class="cta-button primary">Explore Guides</a>
|
||||
<a href="/blog#knowledge-graph" class="cta-button secondary">Discover Connections</a>
|
||||
<a href="#knowledge-graph" class="cta-button secondary">Discover Connections</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-container">
|
||||
|
@ -82,6 +109,24 @@ const heroCommands = [
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Knowledge Graph Feature - Moved up for impact -->
|
||||
<section id="knowledge-graph" class="graph-section section-padding">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">Knowledge Graph</h2>
|
||||
<p class="section-description">
|
||||
Explore connections between infrastructure components, technologies, and implementation guides.
|
||||
</p>
|
||||
</div>
|
||||
<div class="graph-container">
|
||||
<MiniKnowledgeGraph graphData={miniGraphData} height="450px" />
|
||||
</div>
|
||||
<div class="graph-link-container">
|
||||
<a href="/blog#knowledge-graph" class="cta-button primary">Explore Full Graph</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Intro Section - Reframed as community resource -->
|
||||
<section class="intro-section section-padding">
|
||||
<div class="container">
|
||||
|
@ -265,6 +310,27 @@ const heroCommands = [
|
|||
.hero-cta { display: flex; gap: 1rem; }
|
||||
.terminal-container { flex: 1; max-width: 550px; }
|
||||
|
||||
/* Graph Section - New Prominent Section */
|
||||
.graph-section {
|
||||
background: var(--bg-primary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.graph-container {
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-secondary);
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.graph-link-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Intro Section - Adjusted for community focus */
|
||||
.intro-section .section-title { text-align: center; margin-bottom: 1.5rem; }
|
||||
.intro-text {
|
||||
|
|
|
@ -1,470 +0,0 @@
|
|||
---
|
||||
// src/pages/projects/infrastructure-templates.astro
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
|
||||
const title = "Infrastructure as Code Templates | ArgoBox";
|
||||
const description = "Curated collection of reusable Terraform, Ansible, and Kubernetes manifests for building modern infrastructure environments.";
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description}>
|
||||
<Header slot="header" />
|
||||
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>Infrastructure as Code Templates</h1>
|
||||
<div class="header-accent"></div>
|
||||
</div>
|
||||
|
||||
<div class="coming-soon-container">
|
||||
<div class="coming-soon-card">
|
||||
<div class="icon-container">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="60" height="60" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="16 18 22 12 16 6"></polyline>
|
||||
<polyline points="8 6 2 12 8 18"></polyline>
|
||||
<line x1="12" y1="2" x2="12" y2="22"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<h2>IaC Templates Coming Soon</h2>
|
||||
<p class="description">
|
||||
This section will provide a comprehensive collection of reusable Infrastructure as Code templates for building modern tech environments. These templates are designed to help you accelerate your infrastructure deployments with best practices built in.
|
||||
</p>
|
||||
|
||||
<div class="template-categories">
|
||||
<div class="template-category">
|
||||
<div class="category-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
|
||||
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
|
||||
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
||||
<line x1="6" y1="18" x2="6.01" y2="18"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="category-content">
|
||||
<h3>Terraform Modules</h3>
|
||||
<p>Modular infrastructure components for cloud providers and on-premises environments.</p>
|
||||
<ul class="template-list">
|
||||
<li>Multi-cloud networking templates</li>
|
||||
<li>Kubernetes cluster provisioning</li>
|
||||
<li>Database deployment patterns</li>
|
||||
<li>Security & compliance configurations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="template-category">
|
||||
<div class="category-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 20V10"></path>
|
||||
<path d="M12 20V4"></path>
|
||||
<path d="M6 20v-6"></path>
|
||||
<path d="M18 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>
|
||||
<path d="M12 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>
|
||||
<path d="M6 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="category-content">
|
||||
<h3>Ansible Playbooks</h3>
|
||||
<p>Automation workflows for system configuration and application deployment.</p>
|
||||
<ul class="template-list">
|
||||
<li>Server hardening & compliance</li>
|
||||
<li>Application deployment patterns</li>
|
||||
<li>Monitoring setup automation</li>
|
||||
<li>Disaster recovery procedures</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="template-category">
|
||||
<div class="category-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 12H2"></path>
|
||||
<path d="M5 12l3-3"></path>
|
||||
<path d="M5 12l3 3"></path>
|
||||
<path d="M19 12l-3-3"></path>
|
||||
<path d="M19 12l-3 3"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="category-content">
|
||||
<h3>Kubernetes Manifests</h3>
|
||||
<p>Production-ready configurations for containerized applications.</p>
|
||||
<ul class="template-list">
|
||||
<li>Application deployment blueprints</li>
|
||||
<li>GitOps-ready repository structure</li>
|
||||
<li>Security policies & network configurations</li>
|
||||
<li>Stateful workload templates</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cta-container">
|
||||
<a href="/blog?tag=infrastructure-as-code" class="cta-button secondary">
|
||||
<span>Read Related Articles</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
<polyline points="12 5 19 12 12 19"></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
<button class="cta-button primary">
|
||||
<span>Notify Me When Available</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
|
||||
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Related Projects Section -->
|
||||
<div class="related-projects">
|
||||
<h2 class="section-title">Related Projects</h2>
|
||||
<div class="projects-grid">
|
||||
<a href="/projects/github" class="related-project">
|
||||
<div class="project-icon">
|
||||
<svg 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">
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>GitHub Repositories</h3>
|
||||
<p>Open-source infrastructure code and automation scripts.</p>
|
||||
<span class="project-link">View Project <span class="arrow">→</span></span>
|
||||
</a>
|
||||
|
||||
<a href="/projects/tech-stack" class="related-project">
|
||||
<div class="project-icon">
|
||||
<svg 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">
|
||||
<line x1="16.5" y1="9.4" x2="7.5" y2="4.21"></line>
|
||||
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
||||
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
|
||||
<line x1="12" y1="22.08" x2="12" y2="12"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Tech Stack</h3>
|
||||
<p>Explore the technologies used in the ArgoBox infrastructure.</p>
|
||||
<span class="project-link">View Project <span class="arrow">→</span></span>
|
||||
</a>
|
||||
|
||||
<a href="/homelab" class="related-project">
|
||||
<div class="project-icon">
|
||||
<svg 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">
|
||||
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
|
||||
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
|
||||
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
||||
<line x1="6" y1="18" x2="6.01" y2="18"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Home Lab Infrastructure</h3>
|
||||
<p>Enterprise-grade home lab environment with production services.</p>
|
||||
<span class="project-link">View Project <span class="arrow">→</span></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer slot="footer" />
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--container-padding, 1.5rem);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin: 3rem 0 4rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--font-size-4xl, 2.5rem);
|
||||
background: linear-gradient(90deg, var(--accent-secondary, #3b82f6), var(--accent-primary, #06b6d4));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.header-accent {
|
||||
width: 80px;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--accent-secondary, #3b82f6), var(--accent-primary, #06b6d4));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.coming-soon-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem 0 4rem;
|
||||
}
|
||||
|
||||
.coming-soon-card {
|
||||
background: var(--card-bg, #1e293b);
|
||||
border: 1px solid var(--card-border, #334155);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem;
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.coming-soon-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: radial-gradient(circle at 30% 50%, rgba(59, 130, 246, 0.1), transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--accent-secondary, #3b82f6);
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: var(--font-size-3xl, 1.875rem);
|
||||
color: var(--text-primary, #f1f5f9);
|
||||
}
|
||||
|
||||
.description {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
color: var(--text-secondary, #cbd5e1);
|
||||
font-size: var(--font-size-lg, 1.125rem);
|
||||
line-height: 1.7;
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.template-categories {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.template-category {
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
border: 1px solid var(--border-primary, #334155);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.template-category:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
|
||||
border-color: var(--accent-secondary, #3b82f6);
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
color: var(--accent-secondary, #3b82f6);
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.category-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.category-content h3 {
|
||||
font-size: var(--font-size-xl, 1.25rem);
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary, #f1f5f9);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.category-content p {
|
||||
color: var(--text-secondary, #cbd5e1);
|
||||
margin-bottom: 1.5rem;
|
||||
text-align: center;
|
||||
font-size: var(--font-size-md, 1rem);
|
||||
}
|
||||
|
||||
.template-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.template-list li {
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid rgba(203, 213, 225, 0.1);
|
||||
color: var(--text-tertiary, #94a3b8);
|
||||
font-size: var(--font-size-sm, 0.875rem);
|
||||
position: relative;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.template-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.template-list li::before {
|
||||
content: '→';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--accent-primary, #06b6d4);
|
||||
}
|
||||
|
||||
.cta-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.cta-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
font-size: var(--font-size-md, 1rem);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.cta-button.primary {
|
||||
background: linear-gradient(90deg, var(--accent-secondary, #3b82f6), var(--accent-primary, #06b6d4));
|
||||
color: var(--bg-primary, #0f172a);
|
||||
border: none;
|
||||
box-shadow: 0 5px 15px rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
|
||||
.cta-button.secondary {
|
||||
background: transparent;
|
||||
border: 1px solid var(--accent-secondary, #3b82f6);
|
||||
color: var(--accent-secondary, #3b82f6);
|
||||
}
|
||||
|
||||
.cta-button.primary:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.cta-button.secondary:hover {
|
||||
transform: translateY(-3px);
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
/* Related Projects Section */
|
||||
.related-projects {
|
||||
margin: 4rem 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: var(--font-size-2xl, 1.5rem);
|
||||
color: var(--text-primary, #f1f5f9);
|
||||
margin-bottom: 2rem;
|
||||
position: relative;
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.section-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 60px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--accent-secondary, #3b82f6), var(--accent-primary, #06b6d4));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.related-project {
|
||||
background: var(--card-bg, #1e293b);
|
||||
border: 1px solid var(--border-primary, #334155);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.related-project:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: var(--accent-primary, #06b6d4);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.project-icon {
|
||||
color: var(--accent-primary, #06b6d4);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.related-project h3 {
|
||||
font-size: var(--font-size-lg, 1.125rem);
|
||||
color: var(--text-primary, #f1f5f9);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.related-project p {
|
||||
color: var(--text-tertiary, #94a3b8);
|
||||
font-size: var(--font-size-sm, 0.875rem);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.project-link {
|
||||
color: var(--accent-secondary, #3b82f6);
|
||||
font-size: var(--font-size-sm, 0.875rem);
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
margin-left: 0.5rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.related-project:hover .arrow {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.template-categories {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.cta-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.coming-soon-card {
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--font-size-3xl, 1.875rem);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--font-size-2xl, 1.5rem);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,3 @@
|
|||
---
|
||||
// src/pages/resources/docker-compose.astro
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Header from '../../components/Header.astro';
|
||||
|
@ -65,7 +64,6 @@ const filters = ["all", "media", "networking", "utilities"]; // Example filters
|
|||
{filter.charAt(0).toUpperCase() + filter.slice(1)}
|
||||
</button>
|
||||
))}
|
||||
{/* <button class="filter-button active" data-filter="all">All</button> */} {/* Remove Placeholder */}
|
||||
</div>
|
||||
|
||||
<h2 class="section-title">Docker Compose Files</h2>
|
||||
|
@ -389,7 +387,7 @@ const filters = ["all", "media", "networking", "utilities"]; // Example filters
|
|||
}
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
<script>
|
||||
// Copy button functionality & Filter functionality
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Copy Button
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
// src/pages/test.astro
|
||||
import MinimalLayout from '../layouts/MinimalLayout.astro';
|
||||
---
|
||||
|
||||
<MinimalLayout>
|
||||
<h1>Test Page</h1>
|
||||
<p>This is a minimal test page to isolate the build issue.</p>
|
||||
</MinimalLayout>
|