diff --git a/astro.config.mjs b/astro.config.mjs index 227803528..095fac043 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -9,6 +9,7 @@ import metaTags from "astro-meta-tags"; import pagefind from "astro-pagefind"; import deleteUnusedImages from "astro-delete-unused-images"; import { execSync } from "node:child_process"; +import svelte from "@astrojs/svelte"; import compress from "astro-compress"; import tailwindcss from "@tailwindcss/vite"; @@ -66,6 +67,7 @@ export default defineConfig({ "@utils": path.resolve("./src/utils"), "@data": path.resolve("./src/data"), "@components": path.resolve("./src/components"), + "@stores": path.resolve("./src/stores"), "@sections": path.resolve("./src/components/sections"), "@layouts": path.resolve("./src/layouts"), "@ui": path.resolve("./src/components/ui"), @@ -116,6 +118,7 @@ export default defineConfig({ metaTags(), pagefind(), deleteUnusedImages(), + svelte(), compress({ HTML: false, CSS: false, diff --git a/package.json b/package.json index 78f94e410..268927f81 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,10 @@ "@astrojs/check": "^0.9.4", "@astrojs/mdx": "^4.3.0", "@astrojs/sitemap": "^3.4.0", - "@astrojs/tailwind": "^5.1.5", + "@astrojs/svelte": "^7.0.13", "@astrojs/ts-plugin": "^1.10.4", "@fortawesome/fontawesome-free": "^6.7.2", + "@nanostores/persistent": "^1.0.0", "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.1.7", "astro": "^5.8.0", @@ -32,11 +33,13 @@ "hastscript": "^9.0.1", "js-yaml": "^4.1.0", "marked": "^15.0.12", + "nanostores": "^1.0.1", "pagefind": "^1.3.0", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", "remark-toc": "^9.0.0", "sharp": "^0.34.2", + "svelte": "^5.30.2", "tailwindcss": "^4.1.7", "typescript": "^5.8.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9ac32c1d..c96487acc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,15 +20,18 @@ importers: '@astrojs/sitemap': specifier: ^3.4.0 version: 3.4.0 - '@astrojs/tailwind': - specifier: ^5.1.5 - version: 5.1.5(astro@5.8.0(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.41.0)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@4.1.7) + '@astrojs/svelte': + specifier: ^7.0.13 + version: 7.1.0(@types/node@22.15.21)(astro@5.8.0(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.41.0)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0))(jiti@2.4.2)(lightningcss@1.30.1)(svelte@5.33.3)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0) '@astrojs/ts-plugin': specifier: ^1.10.4 version: 1.10.4 '@fortawesome/fontawesome-free': specifier: ^6.7.2 version: 6.7.2 + '@nanostores/persistent': + specifier: ^1.0.0 + version: 1.0.0(nanostores@1.0.1) '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.16(tailwindcss@4.1.7) @@ -71,6 +74,9 @@ importers: marked: specifier: ^15.0.12 version: 15.0.12 + nanostores: + specifier: ^1.0.1 + version: 1.0.1 pagefind: specifier: ^1.3.0 version: 1.3.0 @@ -86,6 +92,9 @@ importers: sharp: specifier: ^0.34.2 version: 0.34.2 + svelte: + specifier: ^5.30.2 + version: 5.33.3 tailwindcss: specifier: ^4.1.7 version: 4.1.7 @@ -160,11 +169,13 @@ packages: '@astrojs/sitemap@3.4.0': resolution: {integrity: sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ==} - '@astrojs/tailwind@5.1.5': - resolution: {integrity: sha512-1diguZEau7FZ9vIjzE4BwavGdhD3+JkdS8zmibl1ene+EHgIU5hI0NMgRYG3yea+Niaf7cyMwjeWeLvzq/maxg==} + '@astrojs/svelte@7.1.0': + resolution: {integrity: sha512-nNAO7iFgCZXCN31N4xBSS/k7vZAZxeZ/v8V6VWZOKG47gVlxeAJBHzn2GlXMMVkxIamr6dhrkDrhYFKIPzoGpw==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} peerDependencies: - astro: ^3.0.0 || ^4.0.0 || ^5.0.0 - tailwindcss: ^3.0.24 + astro: ^5.0.0 + svelte: ^5.1.16 + typescript: ^5.3.3 '@astrojs/telemetry@3.3.0': resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} @@ -627,6 +638,12 @@ packages: '@mdx-js/mdx@3.1.0': resolution: {integrity: sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==} + '@nanostores/persistent@1.0.0': + resolution: {integrity: sha512-iuucWTxcxSLwHvcxBTIAwofDc+KO7cw5EiQklAltJX6Ynx/CKTecOCUG76kF42yNnCZZQcMeuIcl99DkxekIig==} + engines: {node: ^20.0.0 || >=22.0.0} + peerDependencies: + nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -811,6 +828,26 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@sveltejs/acorn-typescript@1.0.5': + resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': + resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^5.0.0 + svelte: ^5.0.0 + vite: ^6.0.0 + + '@sveltejs/vite-plugin-svelte@5.0.3': + resolution: {integrity: sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.0.0 + '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} @@ -1093,13 +1130,6 @@ packages: engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true - autoprefixer@10.4.21: - resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1167,11 +1197,6 @@ packages: brotli@1.3.3: resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} - browserslist@4.24.5: - resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -1189,9 +1214,6 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001718: - resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} - ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1360,10 +1382,17 @@ packages: decode-named-character-reference@1.1.0: resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + dedent-js@1.0.1: + resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==} + deepmerge-ts@7.1.5: resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} engines: {node: '>=16.0.0'} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -1425,9 +1454,6 @@ packages: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} - electron-to-chromium@1.5.155: - resolution: {integrity: sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==} - emmet@2.4.11: resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} @@ -1486,11 +1512,17 @@ packages: engines: {node: '>=6.0'} hasBin: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + esrap@1.4.6: + resolution: {integrity: sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -1575,9 +1607,6 @@ packages: fontkit@2.0.4: resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1744,6 +1773,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -1910,16 +1942,15 @@ packages: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} lite-youtube-embed@0.3.3: resolution: {integrity: sha512-gFfVVnj6NRjxVfJKo3qoLtpi0v5mn3AcR4eKD45wrxQuxzveFJUb+7Cr6uV6n+DjO8X3p0UzPPquhGt0H/y+NA==} + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + lodash.castarray@4.4.0: resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} @@ -2170,6 +2201,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanostores@1.0.1: + resolution: {integrity: sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==} + engines: {node: ^20.0.0 || >=22.0.0} + neotraverse@0.6.18: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} @@ -2199,17 +2234,10 @@ packages: node-mock-http@1.0.0: resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==} - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -2298,25 +2326,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} @@ -2609,6 +2622,16 @@ packages: suf-log@2.5.3: resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==} + svelte2tsx@0.7.39: + resolution: {integrity: sha512-NX8a7eSqF1hr6WKArvXr7TV7DeE+y0kDFD7L5JP7TWqlwFidzGKaG415p992MHREiiEWOv2xIWXJ+mlONofs0A==} + peerDependencies: + svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 + typescript: ^4.9.4 || ^5.0.0 + + svelte@5.33.3: + resolution: {integrity: sha512-NOw+amc+BLyAx1DbMKPY76lvuS2TKJxX5n+1c4Qva+fpAGuCXe+GJmTM5MoTtgoXT1uzZBsLgp0GVvW5RY+k+A==} + engines: {node: '>=18'} + svgo@3.3.2: resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} engines: {node: '>=14.0.0'} @@ -2818,12 +2841,6 @@ packages: uploadthing: optional: true - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3077,6 +3094,9 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + zod-to-json-schema@3.24.5: resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: @@ -3202,15 +3222,27 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.25.20 - '@astrojs/tailwind@5.1.5(astro@5.8.0(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.41.0)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@4.1.7)': + '@astrojs/svelte@7.1.0(@types/node@22.15.21)(astro@5.8.0(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.41.0)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0))(jiti@2.4.2)(lightningcss@1.30.1)(svelte@5.33.3)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0)': dependencies: + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) astro: 5.8.0(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.41.0)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0) - autoprefixer: 10.4.21(postcss@8.5.3) - postcss: 8.5.3 - postcss-load-config: 4.0.2(postcss@8.5.3) - tailwindcss: 4.1.7 + svelte: 5.33.3 + svelte2tsx: 0.7.39(svelte@5.33.3)(typescript@5.8.3) + typescript: 5.8.3 + vite: 6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) transitivePeerDependencies: - - ts-node + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml '@astrojs/telemetry@3.3.0': dependencies: @@ -3582,6 +3614,10 @@ snapshots: - acorn - supports-color + '@nanostores/persistent@1.0.0(nanostores@1.0.1)': + dependencies: + nanostores: 1.0.1 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3735,6 +3771,32 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@sveltejs/acorn-typescript@1.0.5(acorn@8.14.1)': + dependencies: + acorn: 8.14.1 + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)))(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) + debug: 4.4.1 + svelte: 5.33.3 + vite: 6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)))(svelte@5.33.3)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) + debug: 4.4.1 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.17 + svelte: 5.33.3 + vite: 6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + vitefu: 1.0.6(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) + transitivePeerDependencies: + - supports-color + '@swc/helpers@0.5.17': dependencies: tslib: 2.8.1 @@ -4251,16 +4313,6 @@ snapshots: - uploadthing - yaml - autoprefixer@10.4.21(postcss@8.5.3): - dependencies: - browserslist: 4.24.5 - caniuse-lite: 1.0.30001718 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - axobject-query@4.1.0: {} b4a@1.6.7: {} @@ -4321,13 +4373,6 @@ snapshots: dependencies: base64-js: 1.5.1 - browserslist@4.24.5: - dependencies: - caniuse-lite: 1.0.30001718 - electron-to-chromium: 1.5.155 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.5) - buffer-crc32@0.2.13: {} buffer-from@1.1.2: {} @@ -4341,8 +4386,6 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001718: {} - ccount@2.0.1: {} chalk@5.4.1: {} @@ -4485,8 +4528,12 @@ snapshots: dependencies: character-entities: 2.0.2 + dedent-js@1.0.1: {} + deepmerge-ts@7.1.5: {} + deepmerge@4.3.1: {} + defu@6.1.4: {} degenerator@5.0.1: @@ -4544,8 +4591,6 @@ snapshots: dset@3.1.4: {} - electron-to-chromium@1.5.155: {} - emmet@2.4.11: dependencies: '@emmetio/abbreviation': 2.3.3 @@ -4630,8 +4675,14 @@ snapshots: optionalDependencies: source-map: 0.6.1 + esm-env@1.2.2: {} + esprima@4.0.1: {} + esrap@1.4.6: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + estraverse@5.3.0: {} estree-util-attach-comments@3.0.0: @@ -4734,8 +4785,6 @@ snapshots: unicode-properties: 1.4.1 unicode-trie: 2.0.0 - fraction.js@4.3.7: {} - fsevents@2.3.3: optional: true @@ -4994,6 +5043,10 @@ snapshots: is-plain-obj@4.1.0: {} + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.7 + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -5110,12 +5163,12 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 - lilconfig@3.1.3: {} - lines-and-columns@1.2.4: {} lite-youtube-embed@0.3.3: {} + locate-character@3.0.0: {} + lodash.castarray@4.4.0: {} lodash.isplainobject@4.0.6: {} @@ -5624,6 +5677,8 @@ snapshots: nanoid@3.3.11: {} + nanostores@1.0.1: {} + neotraverse@0.6.18: {} netmask@2.0.2: {} @@ -5645,12 +5700,8 @@ snapshots: node-mock-http@1.0.0: {} - node-releases@2.0.19: {} - normalize-path@3.0.0: {} - normalize-range@0.1.2: {} - nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -5770,20 +5821,11 @@ snapshots: picomatch@4.0.2: {} - postcss-load-config@4.0.2(postcss@8.5.3): - dependencies: - lilconfig: 3.1.3 - yaml: 2.8.0 - optionalDependencies: - postcss: 8.5.3 - postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-value-parser@4.2.0: {} - postcss@8.5.3: dependencies: nanoid: 3.3.11 @@ -6257,6 +6299,30 @@ snapshots: dependencies: s.color: 0.0.15 + svelte2tsx@0.7.39(svelte@5.33.3)(typescript@5.8.3): + dependencies: + dedent-js: 1.0.1 + pascal-case: 3.1.2 + svelte: 5.33.3 + typescript: 5.8.3 + + svelte@5.33.3: + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1) + '@types/estree': 1.0.7 + acorn: 8.14.1 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 1.4.6 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.17 + zimmerframe: 1.1.2 + svgo@3.3.2: dependencies: '@trysound/sax': 0.2.0 @@ -6445,12 +6511,6 @@ snapshots: ofetch: 1.4.1 ufo: 1.6.1 - update-browserslist-db@1.1.3(browserslist@4.24.5): - dependencies: - browserslist: 4.24.5 - escalade: 3.2.0 - picocolors: 1.1.1 - util-deprecate@1.0.2: {} vfile-location@5.0.3: @@ -6701,6 +6761,8 @@ snapshots: yoctocolors@2.1.1: {} + zimmerframe@1.1.2: {} + zod-to-json-schema@3.24.5(zod@3.25.20): dependencies: zod: 3.25.20 diff --git a/public/images/placeholder.png b/public/images/placeholder.png new file mode 100644 index 000000000..f607ae0a9 Binary files /dev/null and b/public/images/placeholder.png differ diff --git a/src/components/island/CodeHeart.svelte b/src/components/island/CodeHeart.svelte new file mode 100644 index 000000000..1f0744570 --- /dev/null +++ b/src/components/island/CodeHeart.svelte @@ -0,0 +1,44 @@ + + +{#if !mini} + +{:else if isFavorite} +
❤️
+{/if} diff --git a/src/components/schedule/session.astro b/src/components/schedule/session.astro index 918c206cf..eb143f849 100644 --- a/src/components/schedule/session.astro +++ b/src/components/schedule/session.astro @@ -1,10 +1,12 @@ --- +import CodeHeart from "@components/island/CodeHeart.svelte"; import Speakers from "./speakers.astro"; import { slugify } from "@utils/content"; export interface props { style: any; session: { + code: string; slug?: string; title: string; start: Date; @@ -25,7 +27,10 @@ const hasSpeakers = session.speakers && session.speakers.length > 0; const hasFooter = true; --- -
+
-
- - {session.rooms.length === 1 && ( -
- Room: - {session.rooms && session.rooms.join(", ")} -
- )} -
- +
+ { + session.rooms.length === 1 && ( +
+ Room: + {session.rooms && session.rooms.join(", ")} +
+ ) + } +
-

{session.title}

+ +

+ {session.title} +

{ hasFooter && ( @@ -114,8 +127,7 @@ const hasFooter = true; .room-info { display: block; - text-align:center; - + text-align: center; @media screen and (min-width: 800px) { display: none; @@ -145,9 +157,9 @@ const hasFooter = true; header { /*text-align:right;*/ } - .session h2{ - padding:0 8px ; - margin:0; + .session h2 { + padding: 0 8px; + margin: 0; } .session > .time { @@ -193,8 +205,8 @@ const hasFooter = true; in srgb, var(--color-body-background), white 50% - ); - border: 1px solid #E9714D; + ); + border: 1px solid #e9714d; } diff --git a/src/components/sessions/list-sessions.astro b/src/components/sessions/list-sessions.astro index 8d09444a7..46f2811d6 100644 --- a/src/components/sessions/list-sessions.astro +++ b/src/components/sessions/list-sessions.astro @@ -2,11 +2,13 @@ const { sessions } = Astro.props; import Prose from "@ui/Prose.astro"; import Tag from "@ui/Tag.astro"; +import CodeHeart from "@components/island/CodeHeart.svelte"; import SessionSpeakers from "./session-speakers.astro"; type Session = { data: { title: string; + code: string; speakers: Array<{ id: string; collection: "speakers"; @@ -34,6 +36,13 @@ type Session = { {session.data.title} + +

Speakers: diff --git a/src/components/ui/Note.astro b/src/components/ui/Note.astro index 0177cbe2b..9019c0b84 100644 --- a/src/components/ui/Note.astro +++ b/src/components/ui/Note.astro @@ -45,7 +45,7 @@ const noteIcon = icon || currentStyle.defaultIcon; const noteTitle = title || currentStyle.defaultTitle; --- -

+

{ noteIcon && } diff --git a/src/layouts/ScheduleLayout.astro b/src/layouts/ScheduleLayout.astro index ce3606d11..189b43855 100644 --- a/src/layouts/ScheduleLayout.astro +++ b/src/layouts/ScheduleLayout.astro @@ -18,6 +18,7 @@ const { title, description } = Astro.props;

This is an early version of the schedule and may still change. If you're planning travel around specific sessions, please keep that in mind. + Mark talks as favorites by opening their details and tapping the ❤️ icon. Your selections are saved locally and will only be visible on this device.
diff --git a/src/pages/session/[slug].astro b/src/pages/session/[slug].astro index 781530e4a..f38fe4b87 100644 --- a/src/pages/session/[slug].astro +++ b/src/pages/session/[slug].astro @@ -8,6 +8,7 @@ import { YouTube } from "@astro-community/astro-embed-youtube"; import { Picture } from "astro:assets"; import Markdown from "@ui/Markdown.astro"; import Section from "@ui/Section.astro"; +import CodeHeart from "@components/island/CodeHeart.svelte"; import Button from "@ui/Button.astro"; export async function getStaticPaths() { @@ -27,7 +28,7 @@ const speakers = await getEntries(entry.data.speakers); // Resolve session codes to session data const resolveSessions = (codes: string[]) => - codes.map(code => sessions.find(s => s.data.code === code)!); + codes.map((code) => sessions.find((s) => s.data.code === code)!); // Filter out sessions with room "Exhibit Hall" const filteredSessions = sessions.filter( @@ -60,6 +61,13 @@ const nextSessionsOrdered = sameRoomNextSession class="relative font-title text-text font-bold mb-[0.6em] [&>a]:border-0 [&>a]:text-inherit text-pretty" > {entry.data.title} + + + @@ -166,7 +174,13 @@ const nextSessionsOrdered = sameRoomNextSession The speaker{speakers.length > 1 ? "s" : ""} {speakers.map((speaker) => ( -
+
{speaker.data.avatar && (
@@ -256,6 +270,6 @@ const nextSessionsOrdered = sameRoomNextSession const expectedUrl = `/session/${slug}`; if (currentUrl !== expectedUrl) { - window.history.replaceState({}, '', expectedUrl); + window.history.replaceState({}, "", expectedUrl); } diff --git a/src/pages/speaker/[slug].astro b/src/pages/speaker/[slug].astro index 9f9639c82..4187a8fae 100644 --- a/src/pages/speaker/[slug].astro +++ b/src/pages/speaker/[slug].astro @@ -6,6 +6,7 @@ import { Image } from "astro:assets"; import Markdown from "@ui/Markdown.astro"; import Headline from "@ui/Headline.astro"; import Section from "@ui/Section.astro" +import CodeHeart from "@components/island/CodeHeart.svelte"; export async function getStaticPaths() { @@ -249,6 +250,13 @@ function getGitHosting(url: string): string | undefined { > {session.data.title} + + )) } diff --git a/src/stores/favorites.js b/src/stores/favorites.js new file mode 100644 index 000000000..a6d9ab58e --- /dev/null +++ b/src/stores/favorites.js @@ -0,0 +1,10 @@ +import { persistentMap } from "@nanostores/persistent"; + +export const favorites = persistentMap( + "codeheart_v2:", + {}, + { + encode: JSON.stringify, + decode: JSON.parse, + } +); diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 000000000..cf44f387a --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,5 @@ +import { vitePreprocess } from "@astrojs/svelte"; + +export default { + preprocess: vitePreprocess(), +}; diff --git a/tsconfig.json b/tsconfig.json index a8a536cb7..8adfb1771 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "@utils/*": ["./src/utils/*"], "@data/*": ["./src/data/*"], "@components/*": ["./src/components/*"], + "@stores/*": ["./src/stores/*"], "@sections/*": ["./src/components/sections/*"], "@ui/*": ["./src/components/ui/*"], "@layouts/*": ["./src/layouts/*"],