[Archived] Archived WIP of vielle.dev

Compare changes

Choose any two refs to compare.

+1
.gitignore
··· 22 23 # jetbrains setting folder 24 .idea/
··· 22 23 # jetbrains setting folder 24 .idea/ 25 + .vscode/*
+3
.simple-git-hooks.json
···
··· 1 + { 2 + "pre-commit": "pnpm pretty-quick --staged" 3 + }
-3
.vscode/settings.json
··· 1 - { 2 - "cSpell.words": ["titlebar"] 3 - }
···
+15 -3
astro.config.mjs
··· 1 // @ts-check 2 import { defineConfig } from "astro/config"; 3 - 4 import mdx from "@astrojs/mdx"; 5 6 - import sitemap from "@astrojs/sitemap"; 7 8 // https://astro.build/config 9 export default defineConfig({ 10 integrations: [mdx(), sitemap()], 11 12 output: "server", 13 - 14 site: "https://vielle.dev", 15 });
··· 1 // @ts-check 2 import { defineConfig } from "astro/config"; 3 import mdx from "@astrojs/mdx"; 4 + import sitemap from "@astrojs/sitemap"; 5 6 + import { rehypeAccessibleEmojis } from "rehype-accessible-emojis"; 7 + import rehypeCustomHtml from "./rehype-custom-html"; 8 9 // https://astro.build/config 10 export default defineConfig({ 11 integrations: [mdx(), sitemap()], 12 13 output: "server", 14 site: "https://vielle.dev", 15 + 16 + markdown: { 17 + // @ts-expect-error idk why this gets flagged as wrong 18 + rehypePlugins: [rehypeAccessibleEmojis, rehypeCustomHtml], 19 + shikiConfig: { 20 + themes: { 21 + dark: "catppuccin-frappe", 22 + light: "github-light-high-contrast", 23 + }, 24 + defaultColor: false, 25 + }, 26 + }, 27 });
+12 -6
package.json
··· 12 }, 13 "dependencies": { 14 "@astrojs/check": "^0.9.4", 15 - "@astrojs/mdx": "^4.2.6", 16 - "@astrojs/rss": "^4.0.11", 17 - "@astrojs/sitemap": "^3.4.0", 18 - "astro": "5.7.13", 19 "lunarphase-js": "^2.0.3", 20 "markdown-it": "^14.1.0", 21 - "typescript": "^5.8.3" 22 }, 23 "devDependencies": { 24 "prettier": "3.5.3", 25 - "prettier-plugin-astro": "0.14.1" 26 } 27 }
··· 12 }, 13 "dependencies": { 14 "@astrojs/check": "^0.9.4", 15 + "@astrojs/mdx": "^4.3.0", 16 + "@astrojs/rss": "^4.0.12", 17 + "@astrojs/sitemap": "^3.4.1", 18 + "astro": "5.11.0", 19 "lunarphase-js": "^2.0.3", 20 "markdown-it": "^14.1.0", 21 + "rehype-accessible-emojis": "^0.3.2", 22 + "remark-toc": "^9.0.0", 23 + "typescript": "^5.8.3", 24 + "unified": "^11.0.5" 25 }, 26 "devDependencies": { 27 + "@types/hast": "^3.0.4", 28 "prettier": "3.5.3", 29 + "prettier-plugin-astro": "0.14.1", 30 + "pretty-quick": "^4.1.1", 31 + "simple-git-hooks": "^2.13.0" 32 } 33 }
+258 -48
pnpm-lock.yaml
··· 11 specifier: ^0.9.4 12 version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3) 13 "@astrojs/mdx": 14 - specifier: ^4.2.6 15 - version: 4.2.6(astro@5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0)) 16 "@astrojs/rss": 17 - specifier: ^4.0.11 18 - version: 4.0.11 19 "@astrojs/sitemap": 20 - specifier: ^3.4.0 21 - version: 3.4.0 22 astro: 23 - specifier: 5.7.13 24 - version: 5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0) 25 lunarphase-js: 26 specifier: ^2.0.3 27 version: 2.0.3 28 markdown-it: 29 specifier: ^14.1.0 30 version: 14.1.0 31 typescript: 32 specifier: ^5.8.3 33 version: 5.8.3 34 devDependencies: 35 prettier: 36 specifier: 3.5.3 37 version: 3.5.3 38 prettier-plugin-astro: 39 specifier: 0.14.1 40 version: 0.14.1 41 42 packages: 43 "@astrojs/check@0.9.4": ··· 55 integrity: sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA==, 56 } 57 58 "@astrojs/internal-helpers@0.6.1": 59 resolution: 60 { ··· 76 prettier-plugin-astro: 77 optional: true 78 79 - "@astrojs/markdown-remark@6.3.1": 80 resolution: 81 { 82 - integrity: sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg==, 83 } 84 85 - "@astrojs/mdx@4.2.6": 86 resolution: 87 { 88 - integrity: sha512-0i/GmOm6d0qq1/SCfcUgY/IjDc/bS0i42u7h85TkPFBmlFOcBZfkYhR5iyz6hZLwidvJOEq5yGfzt9B1Azku4w==, 89 } 90 - engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 } 91 peerDependencies: 92 astro: ^5.0.0 93 94 - "@astrojs/prism@3.2.0": 95 resolution: 96 { 97 - integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==, 98 } 99 - engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 } 100 101 - "@astrojs/rss@4.0.11": 102 resolution: 103 { 104 - integrity: sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==, 105 } 106 107 - "@astrojs/sitemap@3.4.0": 108 resolution: 109 { 110 - integrity: sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ==, 111 } 112 113 - "@astrojs/telemetry@3.2.1": 114 resolution: 115 { 116 - integrity: sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg==, 117 } 118 - engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 } 119 120 "@astrojs/yaml2ts@0.2.2": 121 resolution: ··· 924 integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==, 925 } 926 927 "@types/unist@2.0.11": 928 resolution: 929 { ··· 1087 } 1088 hasBin: true 1089 1090 - astro@5.7.13: 1091 resolution: 1092 { 1093 - integrity: sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w==, 1094 } 1095 engines: 1096 - { node: ^18.17.1 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" } 1097 hasBin: true 1098 1099 axobject-query@4.1.0: ··· 1557 integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, 1558 } 1559 1560 - fast-xml-parser@4.5.3: 1561 resolution: 1562 { 1563 - integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==, 1564 } 1565 hasBin: true 1566 ··· 1588 } 1589 engines: { node: ">=8" } 1590 1591 flattie@1.1.1: 1592 resolution: 1593 { ··· 1614 } 1615 engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } 1616 os: [darwin] 1617 1618 get-caller-file@2.0.5: 1619 resolution: ··· 1660 integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==, 1661 } 1662 1663 hast-util-is-element@3.0.0: 1664 resolution: 1665 { ··· 1737 { 1738 integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, 1739 } 1740 1741 import-meta-resolve@4.1.0: 1742 resolution: ··· 1889 integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==, 1890 } 1891 1892 lodash@4.17.21: 1893 resolution: 1894 { ··· 2045 resolution: 2046 { 2047 integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, 2048 } 2049 2050 mdn-data@2.12.2: ··· 2283 } 2284 engines: { node: ">=8.6" } 2285 2286 mrmime@2.0.1: 2287 resolution: 2288 { ··· 2378 integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==, 2379 } 2380 2381 p-limit@6.2.0: 2382 resolution: 2383 { 2384 integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==, 2385 } 2386 engines: { node: ">=18" } 2387 2388 p-queue@8.1.0: 2389 resolution: ··· 2434 { 2435 integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==, 2436 } 2437 2438 picocolors@1.1.1: 2439 resolution: ··· 2485 engines: { node: ">=14" } 2486 hasBin: true 2487 2488 prismjs@1.30.0: 2489 resolution: 2490 { ··· 2579 integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==, 2580 } 2581 2582 rehype-parse@9.0.1: 2583 resolution: 2584 { ··· 2646 integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==, 2647 } 2648 2649 request-light@0.5.8: 2650 resolution: 2651 { ··· 2762 integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==, 2763 } 2764 2765 simple-swizzle@0.2.2: 2766 resolution: 2767 { ··· 2849 } 2850 engines: { node: ">=12" } 2851 2852 - strnum@1.1.2: 2853 resolution: 2854 { 2855 - integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==, 2856 } 2857 2858 style-to-js@1.1.16: ··· 3021 resolution: 3022 { 3023 integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==, 3024 } 3025 3026 unist-util-is@6.0.0: ··· 3475 } 3476 engines: { node: ">=12" } 3477 3478 yocto-queue@1.2.1: 3479 resolution: 3480 { ··· 3539 3540 "@astrojs/compiler@2.12.0": {} 3541 3542 "@astrojs/internal-helpers@0.6.1": {} 3543 3544 "@astrojs/language-server@2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)": ··· 3567 transitivePeerDependencies: 3568 - typescript 3569 3570 - "@astrojs/markdown-remark@6.3.1": 3571 dependencies: 3572 "@astrojs/internal-helpers": 0.6.1 3573 - "@astrojs/prism": 3.2.0 3574 github-slugger: 2.0.0 3575 hast-util-from-html: 2.0.3 3576 hast-util-to-text: 4.0.2 ··· 3593 transitivePeerDependencies: 3594 - supports-color 3595 3596 - "@astrojs/mdx@4.2.6(astro@5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0))": 3597 dependencies: 3598 - "@astrojs/markdown-remark": 6.3.1 3599 "@mdx-js/mdx": 3.1.0(acorn@8.14.1) 3600 acorn: 8.14.1 3601 - astro: 5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0) 3602 es-module-lexer: 1.7.0 3603 estree-util-visit: 2.0.0 3604 hast-util-to-html: 9.0.5 ··· 3612 transitivePeerDependencies: 3613 - supports-color 3614 3615 - "@astrojs/prism@3.2.0": 3616 dependencies: 3617 prismjs: 1.30.0 3618 3619 - "@astrojs/rss@4.0.11": 3620 dependencies: 3621 - fast-xml-parser: 4.5.3 3622 kleur: 4.1.5 3623 3624 - "@astrojs/sitemap@3.4.0": 3625 dependencies: 3626 sitemap: 8.0.0 3627 stream-replace-string: 2.0.0 3628 zod: 3.25.7 3629 3630 - "@astrojs/telemetry@3.2.1": 3631 dependencies: 3632 ci-info: 4.2.0 3633 debug: 4.4.1 ··· 4031 4032 "@types/sax@1.2.7": 4033 dependencies: 4034 - "@types/node": 17.0.45 4035 4036 "@types/unist@2.0.11": {} 4037 ··· 4131 4132 astring@1.9.0: {} 4133 4134 - astro@5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0): 4135 dependencies: 4136 - "@astrojs/compiler": 2.12.0 4137 "@astrojs/internal-helpers": 0.6.1 4138 - "@astrojs/markdown-remark": 6.3.1 4139 - "@astrojs/telemetry": 3.2.1 4140 "@capsizecss/unpack": 2.4.0 4141 "@oslojs/encoding": 1.1.0 4142 "@rollup/pluginutils": 5.1.4(rollup@4.41.0) ··· 4163 github-slugger: 2.0.0 4164 html-escaper: 3.0.3 4165 http-cache-semantics: 4.2.0 4166 js-yaml: 4.1.0 4167 kleur: 4.1.5 4168 magic-string: 0.30.17 ··· 4483 4484 fast-uri@3.0.6: {} 4485 4486 - fast-xml-parser@4.5.3: 4487 dependencies: 4488 - strnum: 1.1.2 4489 4490 fastq@1.19.1: 4491 dependencies: ··· 4499 dependencies: 4500 to-regex-range: 5.0.1 4501 4502 flattie@1.1.1: {} 4503 4504 fontace@0.3.0: ··· 4520 4521 fsevents@2.3.3: 4522 optional: true 4523 4524 get-caller-file@2.0.5: {} 4525 ··· 4562 vfile: 6.0.3 4563 vfile-location: 5.0.3 4564 web-namespaces: 2.0.1 4565 4566 hast-util-is-element@3.0.0: 4567 dependencies: ··· 4676 html-void-elements@3.0.0: {} 4677 4678 http-cache-semantics@4.2.0: {} 4679 4680 import-meta-resolve@4.1.0: {} 4681 ··· 4737 dependencies: 4738 uc.micro: 2.1.0 4739 4740 lodash@4.17.21: {} 4741 4742 longest-streak@3.1.0: {} ··· 4936 mdast-util-to-string@4.0.0: 4937 dependencies: 4938 "@types/mdast": 4.0.4 4939 4940 mdn-data@2.12.2: {} 4941 ··· 5212 braces: 3.0.3 5213 picomatch: 2.3.1 5214 5215 mrmime@2.0.1: {} 5216 5217 ms@2.1.3: {} ··· 5252 regex: 6.0.1 5253 regex-recursion: 6.0.2 5254 5255 p-limit@6.2.0: 5256 dependencies: 5257 yocto-queue: 1.2.1 5258 5259 p-queue@8.1.0: 5260 dependencies: ··· 5292 5293 path-browserify@1.0.1: {} 5294 5295 picocolors@1.1.1: {} 5296 5297 picomatch@2.3.1: {} ··· 5315 5316 prettier@3.5.3: {} 5317 5318 prismjs@1.30.0: {} 5319 5320 prompts@2.4.2: ··· 5374 dependencies: 5375 regex-utilities: 2.3.0 5376 5377 rehype-parse@9.0.1: 5378 dependencies: 5379 "@types/hast": 3.0.4 ··· 5455 mdast-util-to-markdown: 2.1.2 5456 unified: 11.0.5 5457 5458 request-light@0.5.8: {} 5459 5460 request-light@0.7.0: {} ··· 5570 "@shikijs/vscode-textmate": 10.0.2 5571 "@types/hast": 3.0.4 5572 5573 simple-swizzle@0.2.2: 5574 dependencies: 5575 is-arrayish: 0.3.2 ··· 5619 dependencies: 5620 ansi-regex: 6.1.0 5621 5622 - strnum@1.1.2: {} 5623 5624 style-to-js@1.1.16: 5625 dependencies: ··· 5708 "@types/unist": 3.0.3 5709 unist-util-is: 6.0.0 5710 5711 unist-util-is@6.0.0: 5712 dependencies: 5713 "@types/unist": 3.0.3 ··· 5963 string-width: 4.2.3 5964 y18n: 5.0.8 5965 yargs-parser: 21.1.1 5966 5967 yocto-queue@1.2.1: {} 5968
··· 11 specifier: ^0.9.4 12 version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3) 13 "@astrojs/mdx": 14 + specifier: ^4.3.0 15 + version: 4.3.0(astro@5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0)) 16 "@astrojs/rss": 17 + specifier: ^4.0.12 18 + version: 4.0.12 19 "@astrojs/sitemap": 20 + specifier: ^3.4.1 21 + version: 3.4.1 22 astro: 23 + specifier: 5.11.0 24 + version: 5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0) 25 lunarphase-js: 26 specifier: ^2.0.3 27 version: 2.0.3 28 markdown-it: 29 specifier: ^14.1.0 30 version: 14.1.0 31 + rehype-accessible-emojis: 32 + specifier: ^0.3.2 33 + version: 0.3.2 34 + remark-toc: 35 + specifier: ^9.0.0 36 + version: 9.0.0 37 typescript: 38 specifier: ^5.8.3 39 version: 5.8.3 40 + unified: 41 + specifier: ^11.0.5 42 + version: 11.0.5 43 devDependencies: 44 + "@types/hast": 45 + specifier: ^3.0.4 46 + version: 3.0.4 47 prettier: 48 specifier: 3.5.3 49 version: 3.5.3 50 prettier-plugin-astro: 51 specifier: 0.14.1 52 version: 0.14.1 53 + pretty-quick: 54 + specifier: ^4.1.1 55 + version: 4.1.1(prettier@3.5.3) 56 + simple-git-hooks: 57 + specifier: ^2.13.0 58 + version: 2.13.0 59 60 packages: 61 "@astrojs/check@0.9.4": ··· 73 integrity: sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA==, 74 } 75 76 + "@astrojs/compiler@2.12.2": 77 + resolution: 78 + { 79 + integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==, 80 + } 81 + 82 "@astrojs/internal-helpers@0.6.1": 83 resolution: 84 { ··· 100 prettier-plugin-astro: 101 optional: true 102 103 + "@astrojs/markdown-remark@6.3.2": 104 resolution: 105 { 106 + integrity: sha512-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q==, 107 } 108 109 + "@astrojs/mdx@4.3.0": 110 resolution: 111 { 112 + integrity: sha512-OGX2KvPeBzjSSKhkCqrUoDMyzFcjKt5nTE5SFw3RdoLf0nrhyCXBQcCyclzWy1+P+XpOamn+p+hm1EhpCRyPxw==, 113 } 114 + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } 115 peerDependencies: 116 astro: ^5.0.0 117 118 + "@astrojs/prism@3.3.0": 119 resolution: 120 { 121 + integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==, 122 } 123 + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } 124 125 + "@astrojs/rss@4.0.12": 126 resolution: 127 { 128 + integrity: sha512-O5yyxHuDVb6DQ6VLOrbUVFSm+NpObulPxjs6XT9q3tC+RoKbN4HXMZLpv0LvXd1qdAjzVgJ1NFD+zKHJNDXikw==, 129 } 130 131 + "@astrojs/sitemap@3.4.1": 132 resolution: 133 { 134 + integrity: sha512-VjZvr1e4FH6NHyyHXOiQgLiw94LnCVY4v06wN/D0gZKchTMkg71GrAHJz81/huafcmavtLkIv26HnpfDq6/h/Q==, 135 } 136 137 + "@astrojs/telemetry@3.3.0": 138 resolution: 139 { 140 + integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==, 141 } 142 + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } 143 144 "@astrojs/yaml2ts@0.2.2": 145 resolution: ··· 948 integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==, 949 } 950 951 + "@types/ungap__structured-clone@1.2.0": 952 + resolution: 953 + { 954 + integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==, 955 + } 956 + 957 "@types/unist@2.0.11": 958 resolution: 959 { ··· 1117 } 1118 hasBin: true 1119 1120 + astro@5.11.0: 1121 resolution: 1122 { 1123 + integrity: sha512-MEICntERthUxJPSSDsDiZuwiCMrsaYy3fnDhp4c6ScUfldCB8RBnB/myYdpTFXpwYBy6SgVsHQ1H4MuuA7ro/Q==, 1124 } 1125 engines: 1126 + { node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" } 1127 hasBin: true 1128 1129 axobject-query@4.1.0: ··· 1587 integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, 1588 } 1589 1590 + fast-xml-parser@5.2.3: 1591 resolution: 1592 { 1593 + integrity: sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==, 1594 } 1595 hasBin: true 1596 ··· 1618 } 1619 engines: { node: ">=8" } 1620 1621 + find-up@5.0.0: 1622 + resolution: 1623 + { 1624 + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, 1625 + } 1626 + engines: { node: ">=10" } 1627 + 1628 flattie@1.1.1: 1629 resolution: 1630 { ··· 1651 } 1652 engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } 1653 os: [darwin] 1654 + 1655 + gemoji@4.2.1: 1656 + resolution: 1657 + { 1658 + integrity: sha512-V9lUpRSn+KQGavZx8Pk+6mxG3kaz21ae2kTCXuT36KaRPNgYU8eHtj/RcUCNFVvmwppsYYz3nnNS9lmcP5kTsg==, 1659 + } 1660 1661 get-caller-file@2.0.5: 1662 resolution: ··· 1703 integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==, 1704 } 1705 1706 + hast-util-is-element@1.1.0: 1707 + resolution: 1708 + { 1709 + integrity: sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==, 1710 + } 1711 + 1712 hast-util-is-element@3.0.0: 1713 resolution: 1714 { ··· 1786 { 1787 integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, 1788 } 1789 + 1790 + ignore@7.0.5: 1791 + resolution: 1792 + { 1793 + integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, 1794 + } 1795 + engines: { node: ">= 4" } 1796 1797 import-meta-resolve@4.1.0: 1798 resolution: ··· 1945 integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==, 1946 } 1947 1948 + locate-path@6.0.0: 1949 + resolution: 1950 + { 1951 + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, 1952 + } 1953 + engines: { node: ">=10" } 1954 + 1955 lodash@4.17.21: 1956 resolution: 1957 { ··· 2108 resolution: 2109 { 2110 integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, 2111 + } 2112 + 2113 + mdast-util-toc@7.1.0: 2114 + resolution: 2115 + { 2116 + integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==, 2117 } 2118 2119 mdn-data@2.12.2: ··· 2352 } 2353 engines: { node: ">=8.6" } 2354 2355 + mri@1.2.0: 2356 + resolution: 2357 + { 2358 + integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, 2359 + } 2360 + engines: { node: ">=4" } 2361 + 2362 mrmime@2.0.1: 2363 resolution: 2364 { ··· 2454 integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==, 2455 } 2456 2457 + p-limit@3.1.0: 2458 + resolution: 2459 + { 2460 + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, 2461 + } 2462 + engines: { node: ">=10" } 2463 + 2464 p-limit@6.2.0: 2465 resolution: 2466 { 2467 integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==, 2468 } 2469 engines: { node: ">=18" } 2470 + 2471 + p-locate@5.0.0: 2472 + resolution: 2473 + { 2474 + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, 2475 + } 2476 + engines: { node: ">=10" } 2477 2478 p-queue@8.1.0: 2479 resolution: ··· 2524 { 2525 integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==, 2526 } 2527 + 2528 + path-exists@4.0.0: 2529 + resolution: 2530 + { 2531 + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, 2532 + } 2533 + engines: { node: ">=8" } 2534 2535 picocolors@1.1.1: 2536 resolution: ··· 2582 engines: { node: ">=14" } 2583 hasBin: true 2584 2585 + pretty-quick@4.1.1: 2586 + resolution: 2587 + { 2588 + integrity: sha512-9Ud0l/CspNTmyIdYac9X7Inb3o8fuUsw+1zJFvCGn+at0t1UwUcUdo2RSZ41gcmfLv1fxgWQxWEfItR7CBwugg==, 2589 + } 2590 + engines: { node: ">=14" } 2591 + hasBin: true 2592 + peerDependencies: 2593 + prettier: ^3.0.0 2594 + 2595 prismjs@1.30.0: 2596 resolution: 2597 { ··· 2686 integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==, 2687 } 2688 2689 + rehype-accessible-emojis@0.3.2: 2690 + resolution: 2691 + { 2692 + integrity: sha512-kChZo+EZsuFQYHUPu6kOZFjDrG7UtQdGxkrCvHBVo9ariKPL6S68QdPVxLxwcAtZSRZIXZhDuTJHgIM8KW24Qw==, 2693 + } 2694 + 2695 rehype-parse@9.0.1: 2696 resolution: 2697 { ··· 2759 integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==, 2760 } 2761 2762 + remark-toc@9.0.0: 2763 + resolution: 2764 + { 2765 + integrity: sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA==, 2766 + } 2767 + 2768 request-light@0.5.8: 2769 resolution: 2770 { ··· 2881 integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==, 2882 } 2883 2884 + simple-git-hooks@2.13.0: 2885 + resolution: 2886 + { 2887 + integrity: sha512-N+goiLxlkHJlyaYEglFypzVNMaNplPAk5syu0+OPp/Bk6dwVoXF6FfOw2vO0Dp+JHsBaI+w6cm8TnFl2Hw6tDA==, 2888 + } 2889 + hasBin: true 2890 + 2891 simple-swizzle@0.2.2: 2892 resolution: 2893 { ··· 2975 } 2976 engines: { node: ">=12" } 2977 2978 + strnum@2.1.1: 2979 resolution: 2980 { 2981 + integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==, 2982 } 2983 2984 style-to-js@1.1.16: ··· 3147 resolution: 3148 { 3149 integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==, 3150 + } 3151 + 3152 + unist-util-flatmap@1.0.0: 3153 + resolution: 3154 + { 3155 + integrity: sha512-IG32jcKJlhARCYT2LsYPJWdoXYkzz3ESAdl1aa2hn9Auh+cgUmU6wgkII4yCc/1GgeWibRdELdCZh/p3QKQ1dQ==, 3156 } 3157 3158 unist-util-is@6.0.0: ··· 3607 } 3608 engines: { node: ">=12" } 3609 3610 + yocto-queue@0.1.0: 3611 + resolution: 3612 + { 3613 + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, 3614 + } 3615 + engines: { node: ">=10" } 3616 + 3617 yocto-queue@1.2.1: 3618 resolution: 3619 { ··· 3678 3679 "@astrojs/compiler@2.12.0": {} 3680 3681 + "@astrojs/compiler@2.12.2": {} 3682 + 3683 "@astrojs/internal-helpers@0.6.1": {} 3684 3685 "@astrojs/language-server@2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)": ··· 3708 transitivePeerDependencies: 3709 - typescript 3710 3711 + "@astrojs/markdown-remark@6.3.2": 3712 dependencies: 3713 "@astrojs/internal-helpers": 0.6.1 3714 + "@astrojs/prism": 3.3.0 3715 github-slugger: 2.0.0 3716 hast-util-from-html: 2.0.3 3717 hast-util-to-text: 4.0.2 ··· 3734 transitivePeerDependencies: 3735 - supports-color 3736 3737 + "@astrojs/mdx@4.3.0(astro@5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0))": 3738 dependencies: 3739 + "@astrojs/markdown-remark": 6.3.2 3740 "@mdx-js/mdx": 3.1.0(acorn@8.14.1) 3741 acorn: 8.14.1 3742 + astro: 5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0) 3743 es-module-lexer: 1.7.0 3744 estree-util-visit: 2.0.0 3745 hast-util-to-html: 9.0.5 ··· 3753 transitivePeerDependencies: 3754 - supports-color 3755 3756 + "@astrojs/prism@3.3.0": 3757 dependencies: 3758 prismjs: 1.30.0 3759 3760 + "@astrojs/rss@4.0.12": 3761 dependencies: 3762 + fast-xml-parser: 5.2.3 3763 kleur: 4.1.5 3764 3765 + "@astrojs/sitemap@3.4.1": 3766 dependencies: 3767 sitemap: 8.0.0 3768 stream-replace-string: 2.0.0 3769 zod: 3.25.7 3770 3771 + "@astrojs/telemetry@3.3.0": 3772 dependencies: 3773 ci-info: 4.2.0 3774 debug: 4.4.1 ··· 4172 4173 "@types/sax@1.2.7": 4174 dependencies: 4175 + "@types/node": 22.15.20 4176 + 4177 + "@types/ungap__structured-clone@1.2.0": {} 4178 4179 "@types/unist@2.0.11": {} 4180 ··· 4274 4275 astring@1.9.0: {} 4276 4277 + astro@5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0): 4278 dependencies: 4279 + "@astrojs/compiler": 2.12.2 4280 "@astrojs/internal-helpers": 0.6.1 4281 + "@astrojs/markdown-remark": 6.3.2 4282 + "@astrojs/telemetry": 3.3.0 4283 "@capsizecss/unpack": 2.4.0 4284 "@oslojs/encoding": 1.1.0 4285 "@rollup/pluginutils": 5.1.4(rollup@4.41.0) ··· 4306 github-slugger: 2.0.0 4307 html-escaper: 3.0.3 4308 http-cache-semantics: 4.2.0 4309 + import-meta-resolve: 4.1.0 4310 js-yaml: 4.1.0 4311 kleur: 4.1.5 4312 magic-string: 0.30.17 ··· 4627 4628 fast-uri@3.0.6: {} 4629 4630 + fast-xml-parser@5.2.3: 4631 dependencies: 4632 + strnum: 2.1.1 4633 4634 fastq@1.19.1: 4635 dependencies: ··· 4643 dependencies: 4644 to-regex-range: 5.0.1 4645 4646 + find-up@5.0.0: 4647 + dependencies: 4648 + locate-path: 6.0.0 4649 + path-exists: 4.0.0 4650 + 4651 flattie@1.1.1: {} 4652 4653 fontace@0.3.0: ··· 4669 4670 fsevents@2.3.3: 4671 optional: true 4672 + 4673 + gemoji@4.2.1: {} 4674 4675 get-caller-file@2.0.5: {} 4676 ··· 4713 vfile: 6.0.3 4714 vfile-location: 5.0.3 4715 web-namespaces: 2.0.1 4716 + 4717 + hast-util-is-element@1.1.0: {} 4718 4719 hast-util-is-element@3.0.0: 4720 dependencies: ··· 4829 html-void-elements@3.0.0: {} 4830 4831 http-cache-semantics@4.2.0: {} 4832 + 4833 + ignore@7.0.5: {} 4834 4835 import-meta-resolve@4.1.0: {} 4836 ··· 4892 dependencies: 4893 uc.micro: 2.1.0 4894 4895 + locate-path@6.0.0: 4896 + dependencies: 4897 + p-locate: 5.0.0 4898 + 4899 lodash@4.17.21: {} 4900 4901 longest-streak@3.1.0: {} ··· 5095 mdast-util-to-string@4.0.0: 5096 dependencies: 5097 "@types/mdast": 4.0.4 5098 + 5099 + mdast-util-toc@7.1.0: 5100 + dependencies: 5101 + "@types/mdast": 4.0.4 5102 + "@types/ungap__structured-clone": 1.2.0 5103 + "@ungap/structured-clone": 1.3.0 5104 + github-slugger: 2.0.0 5105 + mdast-util-to-string: 4.0.0 5106 + unist-util-is: 6.0.0 5107 + unist-util-visit: 5.0.0 5108 5109 mdn-data@2.12.2: {} 5110 ··· 5381 braces: 3.0.3 5382 picomatch: 2.3.1 5383 5384 + mri@1.2.0: {} 5385 + 5386 mrmime@2.0.1: {} 5387 5388 ms@2.1.3: {} ··· 5423 regex: 6.0.1 5424 regex-recursion: 6.0.2 5425 5426 + p-limit@3.1.0: 5427 + dependencies: 5428 + yocto-queue: 0.1.0 5429 + 5430 p-limit@6.2.0: 5431 dependencies: 5432 yocto-queue: 1.2.1 5433 + 5434 + p-locate@5.0.0: 5435 + dependencies: 5436 + p-limit: 3.1.0 5437 5438 p-queue@8.1.0: 5439 dependencies: ··· 5471 5472 path-browserify@1.0.1: {} 5473 5474 + path-exists@4.0.0: {} 5475 + 5476 picocolors@1.1.1: {} 5477 5478 picomatch@2.3.1: {} ··· 5496 5497 prettier@3.5.3: {} 5498 5499 + pretty-quick@4.1.1(prettier@3.5.3): 5500 + dependencies: 5501 + find-up: 5.0.0 5502 + ignore: 7.0.5 5503 + mri: 1.2.0 5504 + picocolors: 1.1.1 5505 + picomatch: 4.0.2 5506 + prettier: 3.5.3 5507 + tinyexec: 0.3.2 5508 + tslib: 2.8.1 5509 + 5510 prismjs@1.30.0: {} 5511 5512 prompts@2.4.2: ··· 5566 dependencies: 5567 regex-utilities: 2.3.0 5568 5569 + rehype-accessible-emojis@0.3.2: 5570 + dependencies: 5571 + emoji-regex: 8.0.0 5572 + gemoji: 4.2.1 5573 + hast-util-is-element: 1.1.0 5574 + unist-util-flatmap: 1.0.0 5575 + 5576 rehype-parse@9.0.1: 5577 dependencies: 5578 "@types/hast": 3.0.4 ··· 5654 mdast-util-to-markdown: 2.1.2 5655 unified: 11.0.5 5656 5657 + remark-toc@9.0.0: 5658 + dependencies: 5659 + "@types/mdast": 4.0.4 5660 + mdast-util-toc: 7.1.0 5661 + 5662 request-light@0.5.8: {} 5663 5664 request-light@0.7.0: {} ··· 5774 "@shikijs/vscode-textmate": 10.0.2 5775 "@types/hast": 3.0.4 5776 5777 + simple-git-hooks@2.13.0: {} 5778 + 5779 simple-swizzle@0.2.2: 5780 dependencies: 5781 is-arrayish: 0.3.2 ··· 5825 dependencies: 5826 ansi-regex: 6.1.0 5827 5828 + strnum@2.1.1: {} 5829 5830 style-to-js@1.1.16: 5831 dependencies: ··· 5914 "@types/unist": 3.0.3 5915 unist-util-is: 6.0.0 5916 5917 + unist-util-flatmap@1.0.0: {} 5918 + 5919 unist-util-is@6.0.0: 5920 dependencies: 5921 "@types/unist": 3.0.3 ··· 6171 string-width: 4.2.3 6172 y18n: 5.0.8 6173 yargs-parser: 21.1.1 6174 + 6175 + yocto-queue@0.1.0: {} 6176 6177 yocto-queue@1.2.1: {} 6178
+140
posts/full-test.md
···
··· 1 + --- 2 + title: Full Test 3 + date: 3000-12-31 4 + colour: "#008282" 5 + image: "mc_map_art.png" 6 + --- 7 + 8 + ## this is 9 + 10 + ### simply 11 + 12 + #### a 13 + 14 + ##### test 15 + 16 + ###### i wouldnt use absurd headings in the wild, just h2 MAYBE h3 17 + 18 + look we r testinng!! 19 + 20 + ## normie syntax 21 + 22 + ### Paragraphs 23 + 24 + here is a paragraph 25 + 26 + and here is another 27 + 28 + Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 29 + 30 + ::breakout::test:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 31 + 32 + ::full-width::bg-red::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 33 + 34 + ::full-width::bg-orange::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 35 + 36 + ::full-width::bg-yellow::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 37 + 38 + ::full-width::bg-green::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 39 + 40 + ::full-width::bg-blue::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 41 + 42 + ::full-width::bg-purple::@div::@nest:: Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 43 + 44 + ::breakout:: ![small left | ](./assets/minecraft.png) Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 45 + 46 + Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos. 47 + 48 + paragraph with **_strong emph_**, **\*strong** in emph\*, **_emph_ in strong**, **in strong _emph_**, and \*in emph **strong\*** but not ~~this text~~ bc i said so 49 + 50 + now heres a paragraph with a [link](/blog "Goes to blog") which goes to blog, [a link](https://vielle.dev/) which points to my site, [an unvisited link (DONT CLICK)](https://thissitedoesnotexist.com/fake_page), and a link to <https://deer.social> 51 + 52 + ### Code 53 + 54 + ```html 55 + <h1>Code</h1> 56 + <p>Theres more code</p> 57 + <!-- and then some more --> 58 + wow it just keeps going 59 + <style> 60 + this { 61 + size: long; 62 + } 63 + </style> 64 + ``` 65 + 66 + ``` 67 + This is code with a really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really long line 68 + ``` 69 + 70 + ``` 71 + tinycode 72 + ``` 73 + 74 + heres sopme `inline` code 75 + 76 + ### Tables 77 + 78 + | this | is | 79 + | ---- | :---: | 80 + | a | table | 81 + | a | table | 82 + | a | table | 83 + | a | table | 84 + 85 + ### Blockquotes 86 + 87 + > and this, a block quote 88 + > which is multiline 89 + 90 + > and heres another 91 + 92 + ### Lists 93 + 94 + #### Unordered 95 + 96 + - an unordered list 97 + - with nesting 98 + - and more 99 + - going back 100 + - again 101 + 102 + #### Ordered 103 + 104 + 1. an unordered list 105 + 2. which has 106 + 1. nesting 107 + 2. high numbers 108 + 109 + #### Check 110 + 111 + - [ ] make this look good 112 + - [ ] make `/blog` look good 113 + - [x] oh yeah that was an inline code ๐Ÿ’ช 114 + 115 + ## fancy syntax 116 + 117 + ### blockquote flags 118 + 119 + > $NOTE 120 + > This one is a note 121 + 122 + > $ALERT 123 + > This one is another keyword 124 + 125 + > $NOTE 126 + > this can be achived by adding `$FLAG` to the first line of a blockquote (make sure to add the double space) 127 + 128 + ### Image 129 + 130 + ![An unimportiant image](./assets/minecraft.png) 131 + 132 + ![small left | An unimportiant image](./assets/minecraft.png) heres an image which should be on the right while this text wraps around it? i hope? make sure the image goes first tho !!!! 133 + 134 + > $INFO 135 + > image flags go in alt text 136 + > if alt text has a pipe (|), there are flags 137 + > all words up to the first pipe are treated as flags in a space seperated list 138 + > they are added to the data tag as `[data-img-flag--<name>="true"]` 139 + 140 + ![small centre | An unimportiant image](./assets/minecraft.png)
+1 -7
posts/test.mdx
··· 2 title: Test Post 3 --- 4 5 - import Balloon from "@components/blog/balloon.svelte"; 6 - 7 whats this about dawg 8 9 - <div style="padding: 15rem;"></div> 10 - 11 - <div style="position: absolute"> 12 - <Balloon client:load id={0} boundingWidth={300} boundingHeight={0} /> 13 - </div>
··· 2 title: Test Post 3 --- 4 5 whats this about dawg 6 7 + (Vi a vis .MDX)
+175
rehype-custom-html.ts
···
··· 1 + import type { Plugin } from "unified"; 2 + import type { 3 + Root, 4 + Element, 5 + Node, 6 + ElementContent, 7 + RootContent, 8 + Text, 9 + } from "hast"; 10 + type Options = {}; 11 + 12 + /* 13 + blockquote flags go in the first line 14 + they are formatted as: 15 + `$FLAG `, where `FLAG` is the flag name 16 + there can only be one flag per blockquote 17 + */ 18 + 19 + function blockquote(node: Element) { 20 + for (const child of node.children) { 21 + if (child.type === "element" && child.children[0].type === "text") { 22 + const flag = child.children[0].value.match(/(?<=^\$).*/gm); 23 + if (flag?.length !== 1) continue; 24 + child.children.shift(); 25 + // finiky to get types working bc shift mutation etc 26 + if ( 27 + (child.children[0] as Node).type === "element" && 28 + (child.children[0] as Node as Element).tagName === "br" 29 + ) 30 + child.children.shift(); 31 + 32 + node.properties[`data-bq-flag--${flag[0].toLowerCase()}`] = true; 33 + } 34 + } 35 + } 36 + 37 + /* 38 + image flags go in alt text 39 + if alt text has a pipe (|), there are flags 40 + all words up to the first pipe are treated as flags in a space seperated list 41 + they are added to the data tag as [data-img-flag--<name>="true"] 42 + */ 43 + 44 + function image(node: Element) { 45 + // get alt; throw error if missing; convert to string 46 + const alt = ( 47 + node.properties.alt ?? 48 + (() => { 49 + throw new Error("NO ALT TEXT!!!"); 50 + })() 51 + ).toString(); 52 + 53 + // match section before | 54 + const prefixes = alt.match(/.*?(?= \|.*)/gm); 55 + if (!prefixes) return; 56 + 57 + node.properties.alt = alt.match(/(?<= \| ).*/gm); 58 + const flags = prefixes[0].split(" "); 59 + for (const flag of flags) { 60 + node.properties[`data-img-flag--${flag}`] = true; 61 + } 62 + } 63 + 64 + /* 65 + paragraph flags go at the start 66 + to use paragraph flags, include the following syntax at the start of a paragraph: 67 + `::FLAG[::FLAG]*::`, where FLAG is a flag which is included as [data-para-flag--FLAG] 68 + if FLAG starts with an `@`, it will be treated as a directive 69 + current directives: 70 + - @nest: replaces children with a p tag and moves children into it 71 + - @div: replaces self with div 72 + */ 73 + 74 + function para(value: Text, parent: Element) { 75 + const flags = value.value.match(/(?<=^::).*(?=::)/gm); 76 + 77 + if (!flags) return; 78 + 79 + const txt = value.value.match(/(?<=^::.*:: ).*/gm); 80 + value.value = 81 + !txt || txt.length !== 1 ? "Err: Parser Error (custom HTML)" : txt[0]; 82 + 83 + for (const flag of flags[0].split("::")) { 84 + if (flag[0] === "@") { 85 + switch (flag.slice(1)) { 86 + case "nest": { 87 + const prevChildren = parent.children; 88 + parent.children = [ 89 + { 90 + type: "element", 91 + tagName: "p", 92 + properties: {}, 93 + children: prevChildren, 94 + } satisfies Element, 95 + ]; 96 + break; 97 + } 98 + case "div": { 99 + parent.tagName = "div"; 100 + break; 101 + } 102 + default: { 103 + console.warn("Unknown paragraph directive:", flag); 104 + } 105 + } 106 + } else parent.properties[`data-para-flag--${flag}`] = true; 107 + } 108 + } 109 + 110 + const forChild = (children: ElementContent[] | RootContent[]) => { 111 + for (const node of children) { 112 + if (node.type !== "element") continue; 113 + 114 + switch (node.tagName) { 115 + case "blockquote": { 116 + blockquote(node); 117 + break; 118 + } 119 + 120 + case "img": { 121 + image(node); 122 + break; 123 + } 124 + 125 + case "p": { 126 + if (node.children[0].type === "text") para(node.children[0], node); 127 + forChild(node.children); 128 + break; 129 + } 130 + 131 + case "pre": { 132 + if (node.properties["tabindex"]) node.properties["tabindex"] = "-1"; 133 + break; 134 + } 135 + 136 + case "ul": 137 + { 138 + node.children.forEach((x) => { 139 + if (x.type === "element" && x.tagName === "li") { 140 + const contents = x.children.map((y) => { 141 + if ( 142 + y.type === "element" && 143 + y.tagName === "input" && 144 + y.properties.type === "checkbox" 145 + ) 146 + y.properties["aria-label"] = y.properties.checked 147 + ? "Checked checkbox" 148 + : "Unchecked checkbox"; 149 + return y; 150 + }); 151 + 152 + x.children = [ 153 + { 154 + type: "element", 155 + tagName: "label", 156 + properties: {}, 157 + children: contents, 158 + }, 159 + ]; 160 + } 161 + }); 162 + } 163 + 164 + break; 165 + } 166 + } 167 + }; 168 + 169 + const plugin: Plugin<[Options], Root> = function (options) { 170 + return function (root, _) { 171 + forChild(root.children); 172 + }; 173 + }; 174 + 175 + export default plugin;
+4 -8
src/Base.astro
··· 1 --- 2 interface Props { 3 - title: string; 4 dataset?: Record<string, any>; 5 [key: string]: any; 6 } ··· 27 <meta name="viewport" content="width=device-width" /> 28 <meta name="generator" content={Astro.generator} /> 29 <link rel="sitemap" href="/sitemap-index.xml" /> 30 - <title>{title} | vielle.dev</title> 31 <script> 32 // sets the timezone offset 33 - document.cookie = `timezone=${new Date().toString()}`; 34 </script> 35 - <!-- default styles (rem, *) --> 36 <style is:global> 37 @layer reset { 38 - :root { 39 - font-size: 62.5%; 40 - } 41 body { 42 - font-size: 1.6rem; 43 line-height: 1.5; 44 -webkit-font-smoothing: antialiased; 45 font-family: sans-serif;
··· 1 --- 2 interface Props { 3 + title?: string; 4 dataset?: Record<string, any>; 5 [key: string]: any; 6 } ··· 27 <meta name="viewport" content="width=device-width" /> 28 <meta name="generator" content={Astro.generator} /> 29 <link rel="sitemap" href="/sitemap-index.xml" /> 30 + <title>{title ? `${title} | vielle.dev` : "vielle.dev"}</title> 31 <script> 32 // sets the timezone offset 33 + document.cookie = `timezone=${new Date().toString()};path=/`; 34 </script> 35 + <!-- default styles --> 36 <style is:global> 37 @layer reset { 38 body { 39 line-height: 1.5; 40 -webkit-font-smoothing: antialiased; 41 font-family: sans-serif;
+17
src/assets/arrow-down.svg
···
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="10" 4 + height="10" 5 + viewBox="0 0 10 10" 6 + version="1.1" 7 + id="svg1" 8 + xmlns="http://www.w3.org/2000/svg" 9 + xmlns:svg="http://www.w3.org/2000/svg" 10 + stroke="black" 11 + stroke-width="2px" 12 + fill="none" 13 + > 14 + <path 15 + d="m 7.8145673,2.2064799 c 0,0 -2.0655083,4.998245 -2.5000003,4.998245 -0.434492,0 -2.4999997,-4.998245 -2.4999997,-4.998245" 16 + /> 17 + </svg>
+17
src/assets/arrow-right.svg
···
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="10" 4 + height="10" 5 + viewBox="0 0 10 10" 6 + version="1.1" 7 + id="svg1" 8 + xmlns="http://www.w3.org/2000/svg" 9 + xmlns:svg="http://www.w3.org/2000/svg" 10 + stroke="black" 11 + stroke-width="2px" 12 + fill="none" 13 + > 14 + <path 15 + d="m 2.8919737,2.1290735 c 0,0 4.998245,2.0655083 4.998245,2.5000003 0,0.434492 -4.998245,2.4999997 -4.998245,2.4999997" 16 + /> 17 + </svg>
-73
src/assets/arrow.svg
··· 1 - <svg 2 - width="100" 3 - height="20" 4 - viewBox="0 0 26.458333 5.2916666" 5 - class="{className}" 6 - style="{style}" 7 - > 8 - <defs id="arrow"> 9 - <marker 10 - id="DartArrow" 11 - refX="0" 12 - refY="0" 13 - orient="auto-start-reverse" 14 - markerWidth="0.75" 15 - markerHeight="0.75" 16 - viewBox="0 0 1 1" 17 - preserveAspectRatio="xMidYMid" 18 - markerUnits="strokeWidth" 19 - > 20 - <path 21 - d="M 0,0 5,-5 -12.5,0 5,5 Z" 22 - transform="scale(-0.5)" 23 - id="path6" 24 - ></path> 25 - </marker> 26 - </defs> 27 - <g 28 - id="layer1" 29 - transform="matrix(0.8611475,0.06332518,-0.05355696,1.0182114,1.9248292,-1.3174538)" 30 - > 31 - <path 32 - d="m 0.24644479,2.3103471 c 0,0 4.07342911,2.4441516 11.16257621,2.4441516 7.089149,0 11.162682,-2.4441342 11.162682,-2.4441342" 33 - id="path1" 34 - ></path> 35 - </g> 36 - </svg> 37 - 38 - <style> 39 - .line { 40 - position: absolute; 41 - display: block; 42 - 43 - width: var(--width); 44 - height: calc(var(--width) / 5); 45 - 46 - transform: rotate(var(--angle)) scaleY(var(--scaleY, 1)); 47 - transform-origin: top left; 48 - 49 - top: var(--y); 50 - left: var(--x); 51 - 52 - stroke-width: 0.957978; 53 - stroke-dasharray: none; 54 - marker-end: url(#DartArrow); 55 - 56 - stroke: var(--colour); 57 - filter: drop-shadow(0 0 0.25rem black); 58 - fill: none; 59 - 60 - .location:hover & { 61 - filter: drop-shadow(0 0 0.5rem var(--colour)); 62 - } 63 - } 64 - 65 - #arrow marker { 66 - overflow: visible; 67 - } 68 - #arrow path { 69 - fill: context-stroke; 70 - fill-rule: evenodd; 71 - stroke: none; 72 - } 73 - </style>
···
-13
src/assets/balloon-glint.svg
··· 1 - <svg 2 - xmlns="http://www.w3.org/2000/svg" 3 - width="210mm" 4 - height="297mm" 5 - viewBox="0 0 210 297" 6 - > 7 - <g> 8 - <path 9 - style="fill: #ffffff" 10 - d="M 9.2929728,1.5456421 C 5.8272482,2.0424561 2.9819023,4.5085073 1.7466634,7.8119263 l 2.361613,1.0051066 C 5.0089649,6.2523257 7.1627996,4.4036314 9.7544434,4.0757202 9.7129319,3.7094167 9.64465,3.2547364 9.5239665,2.6814901 9.4170573,2.1736713 9.3470099,1.8242883 9.2929728,1.5456421 Z" 11 - /> 12 - </g> 13 - </svg>
···
+16
src/assets/check.svg
···
··· 1 + <svg 2 + xmlns="http://www.w3.org/2000/svg" 3 + width="24" 4 + height="24" 5 + viewBox="0 0 24 24" 6 + fill="none" 7 + stroke="white" 8 + stroke-width="2" 9 + stroke-linecap="round" 10 + stroke-linejoin="round" 11 + class="lucide lucide-check-icon lucide-check" 12 + > 13 + <desc><!-- no alt text as descriptive --></desc> 14 + 15 + <path d="M20 6 9 17l-5-5" /> 16 + </svg>
+18
src/assets/copy.svg
···
··· 1 + <svg 2 + xmlns="http://www.w3.org/2000/svg" 3 + width="18" 4 + height="18" 5 + viewBox="0 0 18 18" 6 + fill="none" 7 + stroke="currentColor" 8 + stroke-width="2" 9 + stroke-linecap="round" 10 + stroke-linejoin="round" 11 + class="lucide lucide-copy-icon lucide-copy" 12 + > 13 + <title>Copy text</title> 14 + <rect width="10" height="10" x="6" y="6" rx="2" ry="2" /> 15 + <path 16 + d="m 3,12 c -1,0 -1.5,-0.5 -1.5,-1.5 V 3 c 0,-1 0.5,-1.5 1.5,-1.5 h 7 c 0.8,0 1.5,0.5 1.5,1.5" 17 + /> 18 + </svg>
+1 -2
src/assets/hamburger.svg
··· 9 stroke-linecap="round" 10 stroke-linejoin="round" 11 class="lucide lucide-menu-icon lucide-menu" 12 - title="" 13 > 14 - <title><!-- no alt text as used for buttons --></title> 15 <path d="M4 12h16" /> 16 <path d="M4 18h16" /> 17 <path d="M4 6h16" />
··· 9 stroke-linecap="round" 10 stroke-linejoin="round" 11 class="lucide lucide-menu-icon lucide-menu" 12 > 13 + <title>Menu</title> 14 <path d="M4 12h16" /> 15 <path d="M4 18h16" /> 16 <path d="M4 6h16" />
src/assets/mc_blue_banner.png

This is a binary file and will not be displayed.

src/assets/mc_cyan_banner.png

This is a binary file and will not be displayed.

src/assets/mc_magenta_banner.png

This is a binary file and will not be displayed.

src/assets/mc_map.png

This is a binary file and will not be displayed.

src/assets/mc_map_contents.png

This is a binary file and will not be displayed.

src/assets/mc_red_banner.png

This is a binary file and will not be displayed.

+15
src/assets/moon.svg
···
··· 1 + <svg 2 + xmlns="http://www.w3.org/2000/svg" 3 + width="24" 4 + height="24" 5 + viewBox="0 0 24 24" 6 + fill="none" 7 + stroke="currentColor" 8 + stroke-width="2" 9 + stroke-linecap="round" 10 + stroke-linejoin="round" 11 + class="lucide lucide-moon-icon lucide-moon" 12 + > 13 + <desc><!-- no alt text as descriptive --></desc> 14 + <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" /> 15 + </svg>
+1
src/assets/rss.svg
··· 4 viewBox="0 0 256 256" 5 xmlns="http://www.w3.org/2000/svg" 6 > 7 <circle 8 cx="35.10857" 9 cy="220.89143"
··· 4 viewBox="0 0 256 256" 5 xmlns="http://www.w3.org/2000/svg" 6 > 7 + <desc><!-- no alt text as descriptive --></desc> 8 <circle 9 cx="35.10857" 10 cy="220.89143"
+23
src/assets/sun.svg
···
··· 1 + <svg 2 + xmlns="http://www.w3.org/2000/svg" 3 + width="24" 4 + height="24" 5 + viewBox="0 0 24 24" 6 + fill="none" 7 + stroke="currentColor" 8 + stroke-width="2" 9 + stroke-linecap="round" 10 + stroke-linejoin="round" 11 + class="lucide lucide-sun-icon lucide-sun" 12 + > 13 + <desc><!-- no alt text as descriptive --></desc> 14 + <circle cx="12" cy="12" r="4" /> 15 + <path d="M12 2v2" /> 16 + <path d="M12 20v2" /> 17 + <path d="m4.93 4.93 1.41 1.41" /> 18 + <path d="m17.66 17.66 1.41 1.41" /> 19 + <path d="M2 12h2" /> 20 + <path d="M20 12h2" /> 21 + <path d="m6.34 17.66-1.41 1.41" /> 22 + <path d="m19.07 4.93-1.41 1.41" /> 23 + </svg>
-17
src/assets/x.svg
··· 1 - <svg 2 - xmlns="http://www.w3.org/2000/svg" 3 - width="24" 4 - height="24" 5 - viewBox="0 0 24 24" 6 - fill="none" 7 - stroke="currentColor" 8 - stroke-width="2" 9 - stroke-linecap="round" 10 - stroke-linejoin="round" 11 - class="lucide lucide-x-icon lucide-x" 12 - title="" 13 - > 14 - <title><!-- no alt text as used for buttons --></title> 15 - <path d="M18 6 6 18" /> 16 - <path d="m6 6 12 12" /> 17 - </svg>
···
+7 -7
src/components/blog/Background.astro
··· 12 Astro.cookies.get("timezone")?.value ?? 13 Astro.request.headers.get("Date") ?? 14 Astro.request.headers.get("date") ?? // idk if it cares about capitals so Both 15 - Date.now() 16 ); 17 18 const accurateHours = ··· 65 <div 66 id="background" 67 data-time={daytime ? "day" : "night"} 68 - style={`--palette-sky-day: ${blog.palette.sky.day}; 69 - --palette-sky-night: ${blog.palette.sky.night}; 70 - --palette-sun: ${blog.palette.sun}; 71 - --palette-moon: ${blog.palette.moon}; 72 - --palette-cloud: ${blog.palette.clouds}; 73 - --palette-star: ${blog.palette.stars}`} 74 aria-hidden="true" 75 > 76 {
··· 12 Astro.cookies.get("timezone")?.value ?? 13 Astro.request.headers.get("Date") ?? 14 Astro.request.headers.get("date") ?? // idk if it cares about capitals so Both 15 + Date.now(), 16 ); 17 18 const accurateHours = ··· 65 <div 66 id="background" 67 data-time={daytime ? "day" : "night"} 68 + style={`--palette-sky-day: ${blog.palette.environment.sky.day}; 69 + --palette-sky-night: ${blog.palette.environment.sky.night}; 70 + --palette-sun: ${blog.palette.environment.sun}; 71 + --palette-moon: ${blog.palette.environment.moon}; 72 + --palette-cloud: ${blog.palette.environment.clouds}; 73 + --palette-star: ${blog.palette.environment.stars}`} 74 aria-hidden="true" 75 > 76 {
+21 -24
src/components/blog/Balloon.astro
··· 17 18 <div 19 class="cable" 20 - style={`--length: ${length}rem; 21 --id: ${id}; 22 --of: ${of}; 23 - --offset: ${offset}rem; 24 ${rotation.map((x, i) => `--rot-${i}: ${x}deg;`).join(" ")} 25 --timing: ${utils.getRandom(blog.balloons.timing)}s; 26 `} 27 > 28 <div 29 class="balloon" 30 - style={`--width: ${utils.getRandom(blog.balloons.size[0])}rem; 31 - --height: ${utils.getRandom(blog.balloons.size[1])}rem;`} 32 tabindex="-1" 33 data-min-time={blog.balloons.time[0]} 34 data-max-time={blog.balloons.time[1]} ··· 41 42 <script> 43 const balloons = document.querySelectorAll(".balloon"); 44 - console.log(balloons); 45 balloons.forEach((el) => { 46 if (!(el instanceof HTMLElement)) return; 47 ··· 53 const postParent = el.parentElement?.parentElement; 54 if (!cableParent) throw new Error("No parent 1 level up!!!"); 55 if (!postParent) throw new Error("No parent 2 levels up!!!"); 56 - console.log("clicked! popping", el, "with post", postParent); 57 58 el.blur(); 59 ··· 63 { 64 duration: 100, 65 fill: "forwards", 66 - } 67 ).finished, 68 69 cableParent.animate( ··· 77 { 78 duration: 500, 79 fill: "forwards", 80 - } 81 ), 82 83 postParent.animate( 84 [ 85 {}, 86 { 87 - top: "calc(var(--x-offset-0) + 50rem)", 88 }, 89 ], 90 { 91 duration: 1000, 92 easing: "ease-in-out", 93 - } 94 ).finished, 95 ]).then(() => { 96 const duration = (mintime + Math.random() * (maxtime - mintime)) * 1000; ··· 105 duration, 106 fill: "forwards", 107 // easing: "ease-in", 108 - } 109 ); 110 111 cableParent.animate( ··· 122 { 123 duration, 124 fill: "forwards", 125 - } 126 ); 127 128 postParent.animate( 129 [ 130 { 131 - top: "calc(var(--x-offset-0) + 50rem)", 132 }, 133 {}, 134 ], ··· 136 duration, 137 fill: "forwards", 138 easing: "ease-in", 139 - } 140 ); 141 }); 142 }); ··· 233 .cable { 234 position: absolute; 235 236 - width: 0.5rem; 237 height: var(--length); 238 - border-radius: 0.25rem; 239 background: black; 240 241 [data-time="night"] + * & { 242 background: #404040; 243 } 244 245 - /* .5rem accounts for border (z-index doesn't work) */ 246 z-index: -99; 247 top: calc(-1 * var(--length)); 248 left: calc( ··· 277 } 278 279 .cable-tie { 280 - width: 1.75rem; 281 - height: 0.5rem; 282 283 position: absolute; 284 - bottom: -0.25rem; 285 left: 50%; 286 translate: -50%; 287 z-index: 1; 288 289 - border-radius: 0.25rem; 290 background-color: black; 291 292 [data-time="night"] + * & { ··· 295 } 296 297 .tie { 298 - width: 2rem; 299 - height: 2rem; 300 background-color: var(--colour); 301 clip-path: polygon(50% 0, 0 100%, 100% 100%); 302 position: absolute; 303 - bottom: -1rem; 304 left: 50%; 305 translate: -50%; 306 }
··· 17 18 <div 19 class="cable" 20 + style={`--length: ${length}px; 21 --id: ${id}; 22 --of: ${of}; 23 + --offset: ${offset}px; 24 ${rotation.map((x, i) => `--rot-${i}: ${x}deg;`).join(" ")} 25 --timing: ${utils.getRandom(blog.balloons.timing)}s; 26 `} 27 > 28 <div 29 class="balloon" 30 + style={`--width: ${utils.getRandom(blog.balloons.size[0])}px; 31 + --height: ${utils.getRandom(blog.balloons.size[1])}px;`} 32 tabindex="-1" 33 data-min-time={blog.balloons.time[0]} 34 data-max-time={blog.balloons.time[1]} ··· 41 42 <script> 43 const balloons = document.querySelectorAll(".balloon"); 44 balloons.forEach((el) => { 45 if (!(el instanceof HTMLElement)) return; 46 ··· 52 const postParent = el.parentElement?.parentElement; 53 if (!cableParent) throw new Error("No parent 1 level up!!!"); 54 if (!postParent) throw new Error("No parent 2 levels up!!!"); 55 56 el.blur(); 57 ··· 61 { 62 duration: 100, 63 fill: "forwards", 64 + }, 65 ).finished, 66 67 cableParent.animate( ··· 75 { 76 duration: 500, 77 fill: "forwards", 78 + }, 79 ), 80 81 postParent.animate( 82 [ 83 {}, 84 { 85 + top: "calc(var(--x-offset-0) + 500px)", 86 }, 87 ], 88 { 89 duration: 1000, 90 easing: "ease-in-out", 91 + }, 92 ).finished, 93 ]).then(() => { 94 const duration = (mintime + Math.random() * (maxtime - mintime)) * 1000; ··· 103 duration, 104 fill: "forwards", 105 // easing: "ease-in", 106 + }, 107 ); 108 109 cableParent.animate( ··· 120 { 121 duration, 122 fill: "forwards", 123 + }, 124 ); 125 126 postParent.animate( 127 [ 128 { 129 + top: "calc(var(--x-offset-0) + 500px)", 130 }, 131 {}, 132 ], ··· 134 duration, 135 fill: "forwards", 136 easing: "ease-in", 137 + }, 138 ); 139 }); 140 }); ··· 231 .cable { 232 position: absolute; 233 234 + width: 5px; 235 height: var(--length); 236 + border-radius: 2.5px; 237 background: black; 238 239 [data-time="night"] + * & { 240 background: #404040; 241 } 242 243 z-index: -99; 244 top: calc(-1 * var(--length)); 245 left: calc( ··· 274 } 275 276 .cable-tie { 277 + width: 17.5px; 278 + height: 5px; 279 280 position: absolute; 281 + bottom: -2.5px; 282 left: 50%; 283 translate: -50%; 284 z-index: 1; 285 286 + border-radius: 2.5px; 287 background-color: black; 288 289 [data-time="night"] + * & { ··· 292 } 293 294 .tie { 295 + width: 20px; 296 + height: 20px; 297 background-color: var(--colour); 298 clip-path: polygon(50% 0, 0 100%, 100% 100%); 299 position: absolute; 300 + bottom: -10px; 301 left: 50%; 302 translate: -50%; 303 }
+148
src/components/blog/CodeHeading.astro
···
··· 1 + --- 2 + import Copy from "@/assets/copy.svg"; 3 + 4 + interface Props { 5 + colours: { text: string; border: string }; 6 + } 7 + 8 + const { colours } = Astro.props; 9 + --- 10 + 11 + <template id="code-heading"> 12 + <span class="lang"><slot is:inline>.txt</slot></span> 13 + <span id="copied" style="visibility:hidden" role="alert">Copied!</span> 14 + <button id="copy"><Copy /></button> 15 + 16 + <!-- define:vars didnt work :( --> 17 + <style 18 + set:html={` 19 + :host { 20 + --text: ${colours.text}; 21 + --border: ${colours.border}; 22 + } 23 + `} 24 + ></style> 25 + 26 + <style> 27 + @keyframes teeter { 28 + from, 29 + to { 30 + rotate: 0deg; 31 + } 32 + 25% { 33 + rotate: 15deg; 34 + } 35 + 75% { 36 + rotate: -15deg; 37 + } 38 + } 39 + 40 + .lang { 41 + color: var(--text); 42 + } 43 + 44 + button { 45 + border: none; 46 + background: none; 47 + aspect-ratio: 1; 48 + border-radius: 100%; 49 + 50 + display: flex; 51 + align-items: center; 52 + justify-content: center; 53 + 54 + &:hover, 55 + &:focus { 56 + scale: 1.2; 57 + outline: none; 58 + background-color: #ffffff20; 59 + } 60 + 61 + &:active { 62 + scale: 1.4; 63 + animation: teeter 0.2s; 64 + } 65 + 66 + & svg { 67 + stroke: var(--text); 68 + margin: 2px; 69 + } 70 + } 71 + 72 + :host { 73 + display: flex block; 74 + justify-content: space-between; 75 + align-items: center; 76 + /* gets overridden by * because why not ig */ 77 + padding: 5px 15px !important; 78 + position: sticky; 79 + top: 0; 80 + left: 0; 81 + border-bottom: 4px solid var(--border); 82 + user-select: none; 83 + } 84 + </style> 85 + </template> 86 + 87 + <script> 88 + class CodeHeading extends HTMLElement { 89 + contents = ""; 90 + static observedAttributes = ["contents"]; 91 + 92 + template: HTMLTemplateElement; 93 + content: DocumentFragment; 94 + shadowRoot: ShadowRoot; 95 + 96 + constructor() { 97 + super(); 98 + const template = document.getElementById("code-heading"); 99 + if (!template || !(template instanceof HTMLTemplateElement)) 100 + throw new Error("Could not get #code-heading"); 101 + this.template = template; 102 + this.content = template.content; 103 + 104 + this.shadowRoot = this.attachShadow({ mode: "open" }); 105 + this.shadowRoot.appendChild(this.content.cloneNode(true)); 106 + 107 + const copy = this.shadowRoot.getElementById("copy"); 108 + if (!copy) throw new Error("No #copy in #code-heading"); 109 + 110 + const copied = this.shadowRoot.getElementById("copied"); 111 + if (!copied) throw new Error("No #copied in #code-heading"); 112 + 113 + const copied_animation = { 114 + opacity: [0, 1], 115 + visibility: ["hidden", "visible"], 116 + }; 117 + 118 + copy.addEventListener("click", () => { 119 + navigator.clipboard 120 + .writeText(this.contents) 121 + .catch((e) => { 122 + console.error("Encountered error copying to clipboard;", e); 123 + }) 124 + .then(async () => { 125 + await copied.animate(copied_animation, { 126 + duration: 200, 127 + fill: "forwards", 128 + }).finished; 129 + 130 + copied.animate(copied_animation, { 131 + duration: 200, 132 + delay: 2000, 133 + fill: "forwards", 134 + direction: "reverse", 135 + }); 136 + }); 137 + }); 138 + } 139 + 140 + attributeChangedCallback(name: string, _: any, newV?: string) { 141 + if (name == "contents") { 142 + this.contents = newV ?? ""; 143 + } 144 + } 145 + } 146 + 147 + customElements.define("code-heading", CodeHeading); 148 + </script>
+17 -17
src/components/blog/Post.astro
··· 17 if (!data.image) return; 18 const img = data.image.match(/.*(?=\.png)/gm); 19 if (img === null) return; 20 - return await import(`../../posts/assets/${img[0]}.png`).then( 21 - (x) => x.default 22 ); 23 })(); 24 ··· 61 ${offsets 62 .map( 63 (x, i) => 64 - `--x-offset-${i}: calc((100svw - ${blog.post.width + 2 * blog.post.xPadding}rem) * ${positions[0] + x[0]} + ${blog.post.xPadding}rem); 65 - --y-offset-${i}: ${blog.post.yLeeway * 2 * (positions[1] + x[1]) - blog.post.yLeeway}rem;` 66 ) 67 .join("\n")} 68 ··· 73 74 /* config */ 75 76 - --width: ${blog.post.width}rem; 77 - --y-gap: ${blog.post.yGap}rem; 78 `} 79 > 80 { ··· 172 173 section { 174 width: var(--width); 175 - padding: 1rem; 176 margin-bottom: var(--y-gap); 177 178 position: relative; ··· 185 content: "" / ""; 186 display: block; 187 position: absolute; 188 - top: -0.5rem; 189 - left: -0.5rem; 190 z-index: -2; 191 192 - width: calc(var(--width) + 1rem); 193 - height: calc(100% + 1rem); 194 195 background-color: white; 196 - border: 0.5rem solid var(--colour, dodgerblue); 197 - border-radius: 2.5rem; 198 199 - box-shadow: 0 0 7.5rem var(--box-shadow-colour, #00000080); 200 } 201 202 /* default, overridden by reduced motion */ ··· 217 } 218 219 & > img { 220 - border-radius: 1.5rem; 221 222 - width: 30rem; 223 - height: 20rem; 224 object-fit: cover; 225 } 226 }
··· 17 if (!data.image) return; 18 const img = data.image.match(/.*(?=\.png)/gm); 19 if (img === null) return; 20 + return await import(`../../content/posts/assets/${img[0]}.png`).then( 21 + (x) => x.default, 22 ); 23 })(); 24 ··· 61 ${offsets 62 .map( 63 (x, i) => 64 + `--x-offset-${i}: calc((100svw - ${blog.post.width + 2 * blog.post.xPadding}px) * ${positions[0] + x[0]} + ${blog.post.xPadding}px); 65 + --y-offset-${i}: ${blog.post.yLeeway * 2 * (positions[1] + x[1]) - blog.post.yLeeway}px;`, 66 ) 67 .join("\n")} 68 ··· 73 74 /* config */ 75 76 + --width: ${blog.post.width}px; 77 + --y-gap: ${blog.post.yGap}px; 78 `} 79 > 80 { ··· 172 173 section { 174 width: var(--width); 175 + padding: 10px; 176 margin-bottom: var(--y-gap); 177 178 position: relative; ··· 185 content: "" / ""; 186 display: block; 187 position: absolute; 188 + top: -5px; 189 + left: -5px; 190 z-index: -2; 191 192 + width: calc(var(--width) + 10px); 193 + height: calc(100% + 10px); 194 195 background-color: white; 196 + border: 5px solid var(--colour, dodgerblue); 197 + border-radius: 25px; 198 199 + box-shadow: 0 0 75px var(--box-shadow-colour, #00000080); 200 } 201 202 /* default, overridden by reduced motion */ ··· 217 } 218 219 & > img { 220 + border-radius: 15px; 221 222 + width: 300px; 223 + height: 200px; 224 object-fit: cover; 225 } 226 }
+11 -7
src/components/blog/background/Cloud.astro
··· 36 37 const vectorOffset = ( 38 v: [number, number], 39 - o: [number, number] 40 ): [number, number] => { 41 return [o[0] - v[0], o[1] - v[1]]; 42 }; ··· 89 ]; 90 const newDistance = Math.sqrt( 91 (newCenter[0] - p.origin[0]) ** 2 + 92 - (newCenter[1] - p.origin[1]) ** 2 93 ); 94 return { 95 origin: vectorOffset(vector(ang, c), p.origin), ··· 120 prev: 0, 121 output: [] as any[], 122 complete: false, 123 - } 124 ).output 125 } 126 <circle cx={r} cy={r} r={r}></circle> ··· 133 y1="0" 134 y2="1" 135 > 136 - <stop offset="0%" stop-color={blog.palette.clouds}></stop> 137 <stop 138 offset={`${blog.background.clouds.gradientStops[0]}%`} 139 - stop-color={blog.palette.clouds}></stop> 140 <stop 141 offset={`${blog.background.clouds.gradientStops[1]}%`} 142 - stop-color={`rgb(from ${blog.palette.clouds} r g b / 0)`}></stop> 143 - <stop offset="100%" stop-color={`rgb(from ${blog.palette.clouds} r g b / 0)`}></stop> 144 </linearGradient> 145 </defs> 146
··· 36 37 const vectorOffset = ( 38 v: [number, number], 39 + o: [number, number], 40 ): [number, number] => { 41 return [o[0] - v[0], o[1] - v[1]]; 42 }; ··· 89 ]; 90 const newDistance = Math.sqrt( 91 (newCenter[0] - p.origin[0]) ** 2 + 92 + (newCenter[1] - p.origin[1]) ** 2, 93 ); 94 return { 95 origin: vectorOffset(vector(ang, c), p.origin), ··· 120 prev: 0, 121 output: [] as any[], 122 complete: false, 123 + }, 124 ).output 125 } 126 <circle cx={r} cy={r} r={r}></circle> ··· 133 y1="0" 134 y2="1" 135 > 136 + <stop offset="0%" stop-color={blog.palette.environment.clouds}></stop> 137 <stop 138 offset={`${blog.background.clouds.gradientStops[0]}%`} 139 + stop-color={blog.palette.environment.clouds}></stop> 140 <stop 141 offset={`${blog.background.clouds.gradientStops[1]}%`} 142 + stop-color={`rgb(from ${blog.palette.environment.clouds} r g b / 0)`} 143 + ></stop> 144 + <stop 145 + offset="100%" 146 + stop-color={`rgb(from ${blog.palette.environment.clouds} r g b / 0)`} 147 + ></stop> 148 </linearGradient> 149 </defs> 150
+3 -3
src/components/blog/background/Clouds.astro
··· 30 ...prev.output, 31 <Cloud 32 style={`--parallax-speed: ${blog.background.parallax.clouds}; 33 - width: ${width}rem; 34 - height: ${height}rem; 35 - top: ${y}rem; 36 left: calc(${x} * 200lvw - 100lvw); 37 position: absolute;`} 38 id={"cloud-" + i}
··· 30 ...prev.output, 31 <Cloud 32 style={`--parallax-speed: ${blog.background.parallax.clouds}; 33 + width: ${width}px; 34 + height: ${height}px; 35 + top: ${y}px; 36 left: calc(${x} * 200lvw - 100lvw); 37 position: absolute;`} 38 id={"cloud-" + i}
+10 -9
src/components/blog/background/Moon.astro
··· 8 9 <style> 10 svg { 11 - width: 20rem; 12 - height: 20rem; 13 - font-size: 20rem; 14 15 position: absolute; 16 - top: 30rem; 17 - right: 1rem; 18 } 19 </style> 20 ··· 32 </defs> 33 34 <!-- base --> 35 - <circle fill={blog.palette.moon} cx="100" cy="100" r="100"></circle> 36 <!-- half shadow --> 37 <circle 38 - fill={blog.palette.sky.night} 39 cx="100" 40 cy="100" 41 r="100" ··· 43 <!-- rotation shadow bulge thing --> 44 <ellipse 45 fill={phase < 0.25 || phase > 0.75 46 - ? blog.palette.moon 47 - : blog.palette.sky.night} 48 cx="100" 49 cy="100" 50 rx={50 * Math.cos(4 * Math.PI * phase) + 50}
··· 8 9 <style> 10 svg { 11 + width: 200px; 12 + height: 200px; 13 + font-size: 200px; 14 15 position: absolute; 16 + top: 300px; 17 + right: 10px; 18 } 19 </style> 20 ··· 32 </defs> 33 34 <!-- base --> 35 + <circle fill={blog.palette.environment.moon} cx="100" cy="100" r="100" 36 + ></circle> 37 <!-- half shadow --> 38 <circle 39 + fill={blog.palette.environment.sky.night} 40 cx="100" 41 cy="100" 42 r="100" ··· 44 <!-- rotation shadow bulge thing --> 45 <ellipse 46 fill={phase < 0.25 || phase > 0.75 47 + ? blog.palette.environment.moon 48 + : blog.palette.environment.sky.night} 49 cx="100" 50 cy="100" 51 rx={50 * Math.cos(4 * Math.PI * phase) + 50}
+3 -3
src/components/blog/background/Stars.astro
··· 39 const prongs = Math.round( 40 blog.background.stars.prongs[0] + 41 Math.random() * 42 - (blog.background.stars.prongs[1] - blog.background.stars.prongs[0]) 43 ); 44 45 return ( 46 <svg 47 style={`--parallax-speed: ${utils.getRandom(blog.background.parallax.star, sizeSeed)}; 48 - --size: ${blog.background.stars.size[0] + sizeSeed * (blog.background.stars.size[1] - blog.background.stars.size[0])}rem; 49 --x: ${Math.random()}; 50 --y: ${Math.random()}; 51 --rotate-speed: ${blog.background.stars.rotateSpeed[0] + Math.random() * (blog.background.stars.rotateSpeed[1] - blog.background.stars.rotateSpeed[0])}s; ··· 57 > 58 {new Array(prongs).fill(0).map((_, i) => ( 59 <polygon 60 - fill={blog.palette.stars} 61 points="50 0, 75 50, 25 50" 62 transform={`rotate(${(i / prongs) * 360})`} 63 transform-origin="center"
··· 39 const prongs = Math.round( 40 blog.background.stars.prongs[0] + 41 Math.random() * 42 + (blog.background.stars.prongs[1] - blog.background.stars.prongs[0]), 43 ); 44 45 return ( 46 <svg 47 style={`--parallax-speed: ${utils.getRandom(blog.background.parallax.star, sizeSeed)}; 48 + --size: ${blog.background.stars.size[0] + sizeSeed * (blog.background.stars.size[1] - blog.background.stars.size[0])}px; 49 --x: ${Math.random()}; 50 --y: ${Math.random()}; 51 --rotate-speed: ${blog.background.stars.rotateSpeed[0] + Math.random() * (blog.background.stars.rotateSpeed[1] - blog.background.stars.rotateSpeed[0])}s; ··· 57 > 58 {new Array(prongs).fill(0).map((_, i) => ( 59 <polygon 60 + fill={blog.palette.environment.stars} 61 points="50 0, 75 50, 25 50" 62 transform={`rotate(${(i / prongs) * 360})`} 63 transform-origin="center"
+4 -4
src/components/blog/background/Sun.astro
··· 13 svg { 14 position: absolute; 15 border-radius: 100%; 16 - top: 15rem; 17 - left: calc(100lvw * var(--sun-progress-percent) - 7.5rem); 18 z-index: -1; 19 20 animation: ··· 33 --sun-progress-percent: ${percent}`} 34 data-parallax 35 > 36 - <circle fill={blog.palette.sun} cx="50" cy="50" r="35"></circle> 37 38 { 39 new Array(prongs) 40 .fill(0) 41 .map((_, i) => ( 42 <polygon 43 - fill={blog.palette.sun} 44 points="50 0, 55 10, 45 10" 45 transform={`rotate(${(i / prongs) * 360})`} 46 transform-origin="center"
··· 13 svg { 14 position: absolute; 15 border-radius: 100%; 16 + top: 150px; 17 + left: calc(100lvw * var(--sun-progress-percent) - 75px); 18 z-index: -1; 19 20 animation: ··· 33 --sun-progress-percent: ${percent}`} 34 data-parallax 35 > 36 + <circle fill={blog.palette.environment.sun} cx="50" cy="50" r="35"></circle> 37 38 { 39 new Array(prongs) 40 .fill(0) 41 .map((_, i) => ( 42 <polygon 43 + fill={blog.palette.environment.sun} 44 points="50 0, 55 10, 45 10" 45 transform={`rotate(${(i / prongs) * 360})`} 46 transform-origin="center"
+259
src/components/blog/post.css
···
··· 1 + .content { 2 + /* Custom Flags */ 3 + 4 + & blockquote { 5 + &[data-bq-flag--note], 6 + &[data-bq-flag--alert], 7 + &[data-bq-flag--info] { 8 + color: black; 9 + } 10 + 11 + &[data-bq-flag--note] { 12 + --accent: var(--rainbow-4); 13 + --icon: "๐Ÿ“"; 14 + --name: "Note"; 15 + } 16 + 17 + &[data-bq-flag--alert] { 18 + --accent: var(--rainbow-0); 19 + --icon: "๐Ÿšจ"; 20 + --name: "Alert"; 21 + } 22 + 23 + &[data-bq-flag--info] { 24 + --accent: var(--rainbow-5); 25 + --icon: "๐Ÿ“š"; 26 + --name: "Info"; 27 + } 28 + } 29 + 30 + & p, 31 + & div:has(> p) { 32 + &[data-para-flag--bg-red], 33 + &[data-para-flag--bg-orange], 34 + &[data-para-flag--bg-yellow], 35 + &[data-para-flag--bg-green], 36 + &[data-para-flag--bg-blue], 37 + &[data-para-flag--bg-purple] { 38 + /* contrasting colour */ 39 + color: black; 40 + } 41 + 42 + &[data-para-flag--bg-red] { 43 + background-color: var(--rainbow-0); 44 + } 45 + 46 + &[data-para-flag--bg-orange] { 47 + background-color: var(--rainbow-1); 48 + } 49 + 50 + &[data-para-flag--bg-yellow] { 51 + background-color: var(--rainbow-2); 52 + } 53 + 54 + &[data-para-flag--bg-green] { 55 + background-color: var(--rainbow-3); 56 + } 57 + 58 + &[data-para-flag--bg-blue] { 59 + background-color: var(--rainbow-4); 60 + } 61 + 62 + &[data-para-flag--bg-purple] { 63 + background-color: var(--rainbow-5); 64 + } 65 + } 66 + 67 + & img { 68 + &[data-img-flag--small="true"] { 69 + width: 50%; 70 + } 71 + 72 + &[data-img-flag--left="true"] { 73 + float: left; 74 + } 75 + 76 + &[data-img-flag--right="true"] { 77 + float: right; 78 + } 79 + 80 + &[data-img-flag--centre="true"] { 81 + margin-inline: auto; 82 + } 83 + } 84 + 85 + /* Headings */ 86 + 87 + & h2, 88 + & h3, 89 + & h4 { 90 + margin-block-start: 20px; 91 + margin-block-end: 20px; 92 + 93 + color: var(--typo-subheading); 94 + 95 + & + & { 96 + margin-block-start: 0; 97 + } 98 + 99 + :has(+ &) { 100 + margin-block-end: 0; 101 + } 102 + } 103 + 104 + & h2 { 105 + font-size: 2.2rem; 106 + } 107 + 108 + & h3 { 109 + font-size: 1.8rem; 110 + } 111 + 112 + & h4 { 113 + font-size: 1.5rem; 114 + } 115 + 116 + /* Paragraphs */ 117 + & p, 118 + & blockquote { 119 + clear: both; 120 + margin-block: 20px; 121 + } 122 + 123 + & div:has(> p) { 124 + margin-block: 10px; 125 + } 126 + 127 + /* Images */ 128 + & img { 129 + height: auto; /* fix height issues ?? */ 130 + margin: 10px; 131 + } 132 + 133 + & a { 134 + text-decoration: 2px underline; 135 + 136 + &:link { 137 + color: var(--typo-url); 138 + } 139 + &:visited { 140 + color: var(--typo-visited); 141 + } 142 + &:hover { 143 + text-decoration: 1px wavy underline; 144 + } 145 + &:active { 146 + color: var(--rainbow-3); 147 + } 148 + } 149 + 150 + /* Standard Lists */ 151 + & ul, 152 + & ol { 153 + margin-inline-start: 40px; 154 + & & { 155 + margin-inline-start: 20px; 156 + } 157 + } 158 + 159 + /* Blockquotes */ 160 + & blockquote { 161 + --accent: var(--bg-secondary); 162 + border-left: 2px solid hsl(from var(--accent) h s calc(l * 0.9)); 163 + padding: 10px 40px 10px 10px; 164 + margin: 10px; 165 + border-radius: 5px; 166 + background-color: var(--accent); 167 + width: fit-content; 168 + min-width: 200px; 169 + 170 + &::before { 171 + content: var(--icon) " " var(--name) / var(--name); 172 + } 173 + } 174 + 175 + /* Inline code */ 176 + :not(pre) > code { 177 + color: var(--typo-code); 178 + background-color: var(--bg-code); 179 + padding: 2px; 180 + border-radius: 5px; 181 + 182 + /* make blockquote code use a lighter version of the accent with a darker background */ 183 + :is(blockquote) & { 184 + color: hsl(from var(--accent) h calc(s * 0.8) calc(l * 1.4)); 185 + background-color: #00000080; 186 + } 187 + } 188 + 189 + /* Outline Code */ 190 + & pre:has(> code) { 191 + padding: 5px; 192 + border-radius: 10px; 193 + } 194 + 195 + .astro-code { 196 + background-color: var(--bg-code) !important; 197 + margin-block: 10px; 198 + padding: 0; 199 + position: relative; 200 + 201 + & code { 202 + display: block; 203 + padding: 10px; 204 + 205 + & span { 206 + color: light-dark(var(--shiki-light), var(--shiki-dark)) !important; 207 + } 208 + } 209 + } 210 + 211 + /* Check lists */ 212 + .task-list-item { 213 + list-style: none; 214 + } 215 + 216 + .task-list-item label { 217 + display: flex; 218 + margin-block-start: 5px; 219 + margin-block-end: 7.5px; 220 + 221 + gap: 5px; 222 + 223 + & input[type="checkbox"] { 224 + width: 25px; 225 + height: 25px; 226 + margin-inline-end: 5px; 227 + 228 + background: light-dark(rgb(0, 0, 0, 0.2), rgb(255, 255, 255, 0.4)); 229 + border-radius: 5px; 230 + border: 1px solid var(--typo-body); 231 + 232 + &:checked { 233 + --checkmark: url("../../assets/check.svg"); 234 + background: var(--checkmark) center/20px padding-box no-repeat 235 + var(--rainbow-2); 236 + } 237 + } 238 + } 239 + 240 + /* Table */ 241 + & table { 242 + border-collapse: collapse; 243 + border-spacing: 0; 244 + 245 + & th, 246 + & td { 247 + border: 1px solid white; 248 + padding: 5px; 249 + } 250 + 251 + & thead th { 252 + background-color: var(--bg-secondary); 253 + } 254 + 255 + & tbody tr:nth-child(2n) { 256 + background-color: #ffffff10; 257 + } 258 + } 259 + }
+90
src/components/generic/LightDarkToggle.astro
···
··· 1 + --- 2 + import Sun from "@/assets/sun.svg"; 3 + import Moon from "@/assets/moon.svg"; 4 + 5 + interface Props { 6 + colours: { 7 + bg: string; 8 + fg: string; 9 + }; 10 + } 11 + 12 + const { colours } = Astro.props; 13 + --- 14 + 15 + <button 16 + aria-label="toggle colour scheme" 17 + id="colour-toggle" 18 + style="visibility: hidden" 19 + > 20 + <Sun data-mode-light /> 21 + <Moon data-mode-dark /> 22 + </button> 23 + 24 + <style define:vars={colours}> 25 + #colour-toggle { 26 + background-color: var(--bg); 27 + 28 + border: none; 29 + border-radius: 50%; 30 + padding: 5px; 31 + 32 + width: 34px; 33 + height: 34px; 34 + 35 + & svg { 36 + fill: var(--fg); 37 + stroke: var(--fg); 38 + } 39 + } 40 + </style> 41 + 42 + <script> 43 + const root = document.querySelector(":root"); 44 + if (!(root instanceof HTMLElement)) throw new Error(":root is not html"); 45 + 46 + const button = document.getElementById("colour-toggle"); 47 + if (!button) throw new Error("No #colour-toggle element"); 48 + 49 + const modeToggled = { 50 + light: document.querySelectorAll("[data-mode-light]"), 51 + dark: document.querySelectorAll("[data-mode-dark]"), 52 + }; 53 + 54 + const cookies = document.cookie 55 + .split("; ") 56 + .reduce< 57 + Record<string, string> 58 + >((prev, cur) => ({ ...prev, [cur.split("=")[0]]: cur.split("=")[1] }), {}); 59 + 60 + const mediaMode = matchMedia("(prefers-color-scheme: light)").matches; 61 + const cookieMode = 62 + cookies["colour-mode"] === "light" 63 + ? true 64 + : cookies["colour-mode"] === "dark" 65 + ? false 66 + : undefined; 67 + let lightMode = cookieMode ?? mediaMode; 68 + 69 + const updateColourScheme = () => { 70 + root.style.colorScheme = lightMode ? "light" : "dark"; 71 + document.cookie = `colour-mode=${root.style.colorScheme};path=/`; 72 + 73 + modeToggled[lightMode ? "light" : "dark"].forEach((el) => { 74 + if (!(el instanceof SVGElement || el instanceof HTMLElement)) return; 75 + el.style.display = "block"; 76 + }); 77 + 78 + modeToggled[!lightMode ? "light" : "dark"].forEach((el) => { 79 + if (!(el instanceof SVGElement || el instanceof HTMLElement)) return; 80 + el.style.display = "none"; 81 + }); 82 + }; 83 + 84 + updateColourScheme(); 85 + button.addEventListener("click", () => { 86 + lightMode = !lightMode; 87 + updateColourScheme(); 88 + }); 89 + button.style.visibility = "visible"; 90 + </script>
-92
src/components/generic/Nav.astro
··· 1 - --- 2 - import type { nav } from "@/content.config"; 3 - import NavEntry from "./NavEntry.astro"; 4 - import Hamburger from "@/assets/hamburger.svg"; 5 - import X from "@/assets/x.svg"; 6 - 7 - interface Props { 8 - startOpen?: boolean; 9 - current: string; 10 - data: nav[]; 11 - } 12 - 13 - const { data, startOpen = false, current } = Astro.props; 14 - --- 15 - 16 - <button 17 - popovertarget="nav" 18 - popovertargetaction="show" 19 - aria-label="Nav Menu" 20 - id="nav-menu" 21 - > 22 - <Hamburger /> 23 - </button> 24 - <dialog closedby="any" open={startOpen} id="nav" popover> 25 - <div class="top"> 26 - <h1>{current}</h1> 27 - <button popovertarget="nav" popovertargetaction="hide" aria-label="close"> 28 - <X width={32} height={32} /> 29 - </button> 30 - </div> 31 - <NavEntry {data} /> 32 - </dialog> 33 - 34 - <style> 35 - button { 36 - background-color: transparent; 37 - border: none; 38 - & svg { 39 - stroke: white; 40 - } 41 - } 42 - 43 - #nav-menu { 44 - background-color: black; 45 - padding: 1rem; 46 - border-radius: 0 0 50% 0; 47 - } 48 - 49 - .top { 50 - display: flex; 51 - flex-direction: row; 52 - justify-content: space-between; 53 - } 54 - 55 - dialog { 56 - color: white; 57 - 58 - width: min(50vw, 20rem); 59 - height: 100vh; 60 - padding: 1rem; 61 - 62 - background: black; 63 - border: none; 64 - 65 - position: fixed; 66 - top: 0; 67 - transition: 68 - left 0.2s, 69 - display 0.2s allow-discrete; 70 - 71 - &:popover-open { 72 - /* Post-Entry (Normal) State */ 73 - left: 0; 74 - 75 - /* Pre-Entry State */ 76 - @starting-style { 77 - left: -100%; 78 - } 79 - } 80 - 81 - /* Exiting State */ 82 - &:not(:popover-open) { 83 - left: -100%; 84 - } 85 - } 86 - 87 - /* STUPID ISSUE (astro tries to add a tag to the backdrop) */ 88 - :global(::backdrop) { 89 - background: #00000080; 90 - backdrop-filter: blur(0.5rem); 91 - } 92 - </style>
···
-63
src/components/generic/NavEntry.astro
··· 1 - --- 2 - import type { nav } from "@/content.config"; 3 - 4 - interface Props { 5 - data: nav[]; 6 - root?: string; 7 - } 8 - 9 - const { data, root = "" } = Astro.props; 10 - --- 11 - 12 - <ul> 13 - { 14 - data.map((x) => ( 15 - <li> 16 - <a href={`${root}${x.slug}`}>{x.name}</a> 17 - {x.children && x.children.length > 0 ? ( 18 - <Astro.self root={`${root}${x.slug}`} data={x.children} /> 19 - ) : null} 20 - </li> 21 - )) 22 - } 23 - </ul> 24 - 25 - <style> 26 - li { 27 - list-style-type: "โ•บ "; 28 - margin-inline-start: 4rem; 29 - } 30 - 31 - a:link { 32 - color: #62A0EA; 33 - } 34 - 35 - a:visited { 36 - color: #DC8ADD; 37 - } 38 - 39 - a:focus, 40 - a:hover { 41 - text-decoration: none; 42 - color: #4040ff 43 - 44 - &:visited { 45 - color: #ff40ff; 46 - } 47 - } 48 - 49 - a:focus { 50 - outline: 0.2rem solid #62A0EA; 51 - outline-offset: 0; 52 - border-radius: 0.4rem; 53 - 54 - &:visited { 55 - outline-color: #DC8ADD; 56 - } 57 - } 58 - 59 - a:active { 60 - text-decoration: none; 61 - scale: 1.05; 62 - } 63 - </style>
···
-210
src/components/index/Map.astro
··· 1 - --- 2 - import mc_map_contents from "@/assets/mc_map_contents.png"; 3 - import mc_red from "@/assets/mc_red_banner.png"; 4 - import mc_cyan from "@/assets/mc_cyan_banner.png"; 5 - import mc_magenta from "@/assets/mc_magenta_banner.png"; 6 - import mc_blue from "@/assets/mc_blue_banner.png"; 7 - import Arrow from "@/assets/arrow.svg"; 8 - 9 - type colour = "red" | "cyan" | "magenta" | "blue"; 10 - type position = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; 11 - 12 - interface Location { 13 - colour: colour; 14 - name: string; 15 - href?: string; 16 - x: position; 17 - y: position; 18 - } 19 - 20 - interface Props { 21 - locations: Location[]; 22 - } 23 - 24 - const { locations } = Astro.props; 25 - 26 - const getSrc = (colour: colour) => { 27 - switch (colour) { 28 - case "red": 29 - return mc_red.src; 30 - case "cyan": 31 - return mc_cyan.src; 32 - case "magenta": 33 - return mc_magenta.src; 34 - case "blue": 35 - return mc_blue.src; 36 - } 37 - }; 38 - 39 - const getCssColour = (colour: colour) => { 40 - switch (colour) { 41 - case "red": 42 - return "#af2d25"; 43 - case "cyan": 44 - return "#159b9b"; 45 - case "magenta": 46 - return "#c64ebc"; 47 - case "blue": 48 - return "#3c43a9"; 49 - } 50 - }; 51 - 52 - const scale = 4; 53 - --- 54 - 55 - <div style=`--scale: ${scale}px;` class="map"> 56 - <img 57 - src={mc_map_contents.src} 58 - alt="" 59 - width={58 * scale} 60 - height={58 * scale} 61 - class="map-img" 62 - /> 63 - 64 - { 65 - locations.map((l) => { 66 - // calculate size of map region 67 - const mapSize = 64 * scale; 68 - 69 - interface XY { 70 - y: number; 71 - x: number; 72 - } 73 - 74 - // calculate position of banner 75 - const bannerPos: XY = { 76 - x: l.x * 8 * scale, 77 - y: l.y * 8 * scale, 78 - }; 79 - 80 - // calculate position of text 81 - // coords are inverted so that it doesnt overlap the map 82 - // and so that the line is based properly 83 - // const textPos: XY = { 84 - // x: mapSize + 16 + Math.floor(Math.random() * 30), 85 - // y: mapSize - 32 + Math.floor(Math.random() * 30) - 15, 86 - // }; 87 - 88 - const textPos: XY = { 89 - ...(l.x < 4 90 - ? { x: -132 - Math.floor(Math.random() * 50) } 91 - : { x: mapSize + 32 + Math.floor(Math.random() * 50) }), 92 - ...(l.y < 4 93 - ? { y: 16 + Math.floor(Math.random() * 50) - 25 } 94 - : { y: (mapSize / 4) * 3 + Math.floor(Math.random() * 50) - 25 }), 95 - }; 96 - 97 - // calculate coordinates of corners 98 - const bannerCorner: XY = { 99 - x: bannerPos.x < 128 ? bannerPos.x : bannerPos.x + 8 * scale, 100 - y: bannerPos.y < 128 ? bannerPos.y : bannerPos.y + 8 * scale, 101 - }; 102 - 103 - const textCorner: XY = { 104 - ...textPos, 105 - ...(l.x < 4 ? { x: textPos.x + 100 } : {}), 106 - ...{ y: textPos.y + 10 }, 107 - }; 108 - 109 - // calculate length and angle of line 110 - 111 - const lineLength: number = Math.sqrt( 112 - (bannerCorner.x - textCorner.x) ** 2 + 113 - (bannerCorner.y - textCorner.y) ** 2, 114 - ); 115 - 116 - const lineAngle: number = Math.atan2( 117 - bannerCorner.y - textCorner.y, 118 - bannerCorner.x - textCorner.x, 119 - ); 120 - 121 - return ( 122 - <a class="location" href={l.href ?? ""}> 123 - <img 124 - src={getSrc(l.colour)} 125 - alt="" 126 - width={8 * scale} 127 - height={8 * scale} 128 - class="marker" 129 - style={`--y: ${bannerPos.y}px; 130 - --x: ${bannerPos.x}px; 131 - --colour: ${getCssColour(l.colour)};`} 132 - /> 133 - <div 134 - style={`--y: ${textPos.y}px; 135 - --x: ${textPos.x}px; 136 - --colour: ${getCssColour(l.colour)}; 137 - text-align: ${l.x < 4 ? "right" : "left"};`} 138 - class="text" 139 - > 140 - {l.name} 141 - </div> 142 - <Arrow 143 - class="line" 144 - style={`--width: ${lineLength}px; 145 - --y: ${textCorner.y}px; 146 - --x: ${textCorner.x}px; 147 - --angle: ${lineAngle}rad; 148 - --colour: ${getCssColour(l.colour)}; 149 - --scaleY: ${!(l.x < 4 != l.y < 4) ? -1 : 1};`} 150 - /> 151 - </a> 152 - ); 153 - }) 154 - } 155 - </div> 156 - 157 - <style> 158 - img { 159 - display: block; 160 - position: absolute; 161 - &.map-img { 162 - top: calc(3 * var(--scale)); 163 - left: calc(3 * var(--scale)); 164 - } 165 - &.marker { 166 - top: var(--y); 167 - left: var(--x); 168 - .location:hover & { 169 - filter: drop-shadow(0 0 0.5rem var(--colour)); 170 - scale: 1.1; 171 - } 172 - } 173 - } 174 - 175 - .text { 176 - position: absolute; 177 - 178 - width: 10rem; 179 - height: 2rem; 180 - 181 - top: var(--y); 182 - left: var(--x); 183 - 184 - color: var(--colour); 185 - .location:hover & { 186 - filter: drop-shadow(0 0 0.5rem var(--colour)); 187 - } 188 - } 189 - 190 - .location { 191 - display: block; 192 - --speed: 100ms; 193 - transition: 194 - scale var(--speed), 195 - filter var(--speed); 196 - & * { 197 - transition: inherit; 198 - } 199 - } 200 - 201 - .map { 202 - box-sizing: border-box; 203 - width: calc(64 * var(--scale)); 204 - height: calc(64 * var(--scale)); 205 - background-image: url("../../assets/mc_map.png"); 206 - background-size: 100%; 207 - image-rendering: pixelated; 208 - position: relative; 209 - } 210 - </style>
···
+186
src/components/navigation/Nav.astro
···
··· 1 + --- 2 + import type { nav } from "@/content/config"; 3 + import { getEntry } from "astro:content"; 4 + 5 + import Sidebar from "./Sidebar.astro"; 6 + import Hamburger from "@/assets/hamburger.svg"; 7 + 8 + const data = (await getEntry("nav", "urls")?.then((x) => x.data)) ?? []; 9 + --- 10 + 11 + <nav> 12 + <h1>๐Ÿชค | vielle.dev</h1> 13 + <ul class="desktop"> 14 + { 15 + (() => { 16 + const a = (name: string, href: string) => <a {href}>{name}</a>; 17 + const render = ( 18 + name: string, 19 + children: nav[], 20 + popout: boolean = true, 21 + ) => { 22 + const list = ( 23 + <ul> 24 + {children.map((x) => ( 25 + <li> 26 + {x.children 27 + ? render(x.name, x.children, false) 28 + : a(x.name, x.url || "")} 29 + </li> 30 + ))} 31 + </ul> 32 + ); 33 + return popout ? ( 34 + <details name="nav"> 35 + <summary> 36 + <span>{name}</span> 37 + </summary> 38 + {list} 39 + </details> 40 + ) : ( 41 + <> 42 + <span>{name}</span> 43 + {list} 44 + </> 45 + ); 46 + }; 47 + return data.map((entry) => ( 48 + <li> 49 + {entry.children 50 + ? render(entry.name, entry.children) 51 + : a(entry.name, entry.url || "")} 52 + </li> 53 + )); 54 + })() 55 + } 56 + </ul> 57 + 58 + <button class="mobile" popovertarget="sidebar"><Hamburger /></button> 59 + 60 + <Sidebar /> 61 + </nav> 62 + 63 + <style> 64 + nav { 65 + background-color: white; 66 + color: black; 67 + border: 5px solid black; 68 + border-radius: 0 0 20px 20px; 69 + box-shadow: 0 10px; 70 + display: flex; 71 + flex-direction: row; 72 + align-items: center; 73 + justify-content: center; 74 + padding: 10px 40px; 75 + } 76 + 77 + nav > ul { 78 + display: flex; 79 + flex-direction: row; 80 + align-items: center; 81 + justify-content: center; 82 + gap: 10px; 83 + 84 + & > li { 85 + list-style-type: none; 86 + display: flex; 87 + flex-direction: row; 88 + align-items: center; 89 + justify-content: center; 90 + gap: 10px; 91 + &:not(:first-child)::before { 92 + content: ""; 93 + display: block; 94 + width: 5px; 95 + height: 5px; 96 + border-radius: 2.5px; 97 + background-color: currentColor; 98 + } 99 + } 100 + } 101 + 102 + details { 103 + position: relative; 104 + 105 + summary::marker { 106 + content: url(../../assets/arrow-right.svg); 107 + + { 108 + margin-left: 5px; 109 + } 110 + } 111 + &[open] > summary::marker { 112 + content: url(../../assets/arrow-down.svg); 113 + } 114 + } 115 + 116 + details > ul { 117 + background-color: white; 118 + border: 5px solid black; 119 + border-radius: 20px; 120 + box-shadow: 0 10px; 121 + 122 + padding: 10px 20px; 123 + width: max-content; 124 + 125 + ul { 126 + margin-left: 1em; 127 + } 128 + } 129 + 130 + /* positioning */ 131 + details[open] { 132 + anchor-name: --detail-anchor; 133 + > ul { 134 + position: absolute; 135 + 136 + /* fallback for no anchor support */ 137 + right: -20px; 138 + 139 + /* remove fallback when supported */ 140 + @supports (anchor-name: --supports-anchor) { 141 + position: fixed; 142 + right: unset; 143 + } 144 + 145 + /* anchor positioning. all properties should progressive enhance */ 146 + position-anchor: --detail-anchor; 147 + position-area: bottom span-right; 148 + position-try-fallbacks: flip-inline; 149 + position-try: flip-inline; 150 + } 151 + } 152 + 153 + h1 { 154 + margin-right: auto; 155 + font-size: 1.5rem; 156 + white-space: nowrap; 157 + } 158 + 159 + button:has(svg) { 160 + padding: 0; 161 + border: none; 162 + background-color: transparent; 163 + 164 + width: 2em; 165 + height: 2em; 166 + 167 + & svg { 168 + width: 100%; 169 + height: 100%; 170 + } 171 + } 172 + 173 + .mobile { 174 + display: none; 175 + } 176 + 177 + @media screen and (max-width: 650px) { 178 + .mobile { 179 + display: var(--display, block) !important; 180 + } 181 + 182 + .desktop { 183 + display: none !important; 184 + } 185 + } 186 + </style>
+100
src/components/navigation/Sidebar.astro
···
··· 1 + --- 2 + import type { nav } from "@/content/config"; 3 + import { getEntry } from "astro:content"; 4 + 5 + const data = (await getEntry("nav", "urls")?.then((x) => x.data)) ?? []; 6 + --- 7 + 8 + <aside id="sidebar" popover> 9 + <h2>๐Ÿชค | vielle.dev</h2> 10 + 11 + <nav> 12 + { 13 + (() => { 14 + const step = (entry: nav[]) => ( 15 + <ul> 16 + {entry.map((x) => ( 17 + <li> 18 + {x.url ? <a href={x.url}>{x.name}</a> : <span>{x.name}</span>} 19 + {x.children && step(x.children)} 20 + </li> 21 + ))} 22 + </ul> 23 + ); 24 + return step(data); 25 + })() 26 + } 27 + </nav> 28 + </aside> 29 + 30 + <style> 31 + aside { 32 + inset: auto; 33 + top: 0; 34 + right: 0; 35 + height: 100%; 36 + 37 + background-color: white; 38 + color: black; 39 + border: 5px solid black; 40 + border-radius: 20px 0 0 20px; 41 + box-shadow: 0 10px; 42 + padding: 10px 20px; 43 + 44 + & ul { 45 + padding-inline: 1em; 46 + } 47 + 48 + &::backdrop { 49 + background-color: #00000080; 50 + backdrop-filter: blur(15px); 51 + } 52 + 53 + /* animations */ 54 + --popover-animation-timing: 0.2s; 55 + @media (prefers-reduced-motion: reduce) { 56 + --popover-animation-timing: 0; 57 + } 58 + --popover-animation-easing: ease-in-out; 59 + 60 + transition: 61 + translate var(--popover-animation-timing, 0.2s) 62 + var(--popover-animation-easing, linear) allow-discrete, 63 + overlay var(--popover-animation-timing, 0.2s) 64 + var(--popover-animation-easing, linear) allow-discrete, 65 + display var(--popover-animation-timing, 0.2s) 66 + var(--popover-animation-easing, linear) allow-discrete; 67 + 68 + /* exit */ 69 + translate: 100% 0; 70 + /* base */ 71 + &:popover-open { 72 + translate: 0 0; 73 + /* enter */ 74 + @starting-style { 75 + translate: 100% 0; 76 + } 77 + } 78 + 79 + &::backdrop { 80 + transition: 81 + display var(--popover-animation-timing) 82 + var(--popover-animation-easing, linear) allow-discrete, 83 + overlay var(--popover-animation-timing, 0.2s) 84 + var(--popover-animation-easing, linear) allow-discrete, 85 + opacity var(--popover-animation-timing) 86 + var(--popover-animation-easing, linear) allow-discrete; 87 + 88 + /* exit */ 89 + opacity: 0; 90 + } 91 + /* base */ 92 + &:popover-open::backdrop { 93 + opacity: 1; 94 + /* enter */ 95 + @starting-style { 96 + opacity: 0; 97 + } 98 + } 99 + } 100 + </style>
+70 -25
src/config.ts
··· 1 export const blog = { 2 // overrideHour: 0, 3 post: { 4 - width: 30, 5 - xPadding: 2, 6 - yLeeway: 5, 7 - yGap: 20, 8 - topYGap: 35, 9 drift: [0.1, 1], 10 timing: [10, 20], 11 }, ··· 19 20 clouds: { 21 count: 8, 22 - width: [40, 80], 23 - height: [15, 30], 24 - yGap: [15, 25], 25 26 bumpRadius: [20, 60], 27 gradientStops: [35, 80], ··· 29 30 stars: { 31 count: 40, 32 - size: [2, 5], 33 prongs: [4, 8], 34 rotateSpeed: [20, 40], 35 }, ··· 40 }, 41 balloons: { 42 numBalloons: [1, 3], 43 - length: [5, 15], 44 - offset: [-2.5, 2.5], 45 rotation: [-10, 10], 46 timing: [30, 45], 47 size: [ 48 - [5, 10], 49 - [10, 20], 50 ], 51 opacity: [0.6, 0.9], 52 time: [2, 5], 53 }, 54 palette: { 55 - sky: { 56 - // blue 57 - day: "#1E90FF", 58 - // black 59 - night: "#39375B" 60 }, 61 - // yellow 62 - sun: "#FFEC51", 63 - // whites 64 - moon: "#E5D4ED", 65 - clouds: "#E5D4ED", 66 - stars: "#ffffff", 67 - } 68 } as const; 69 70 export const utils = {
··· 1 export const blog = { 2 // overrideHour: 0, 3 post: { 4 + width: 300, 5 + xPadding: 20, 6 + yLeeway: 50, 7 + yGap: 200, 8 + topYGap: 350, 9 drift: [0.1, 1], 10 timing: [10, 20], 11 }, ··· 19 20 clouds: { 21 count: 8, 22 + width: [400, 800], 23 + height: [150, 300], 24 + yGap: [150, 250], 25 26 bumpRadius: [20, 60], 27 gradientStops: [35, 80], ··· 29 30 stars: { 31 count: 40, 32 + size: [20, 50], 33 prongs: [4, 8], 34 rotateSpeed: [20, 40], 35 }, ··· 40 }, 41 balloons: { 42 numBalloons: [1, 3], 43 + length: [50, 150], 44 + offset: [-25, 25], 45 rotation: [-10, 10], 46 timing: [30, 45], 47 size: [ 48 + [50, 100], 49 + [100, 200], 50 ], 51 opacity: [0.6, 0.9], 52 time: [2, 5], 53 }, 54 palette: { 55 + environment: { 56 + sky: { 57 + // blue 58 + day: "#1E90FF", 59 + // black 60 + night: "#39375B", 61 + }, 62 + // yellow 63 + sun: "#FFEC51", 64 + // whites 65 + moon: "#E5D4ED", 66 + clouds: "#E5D4ED", 67 + stars: "#ffffff", 68 + }, 69 + 70 + post: { 71 + light: { 72 + background: { 73 + main: "#f2f6fc", 74 + secondary: "#e7e8ea", 75 + code: "#ffffff", 76 + }, 77 + typography: { 78 + body: "#070e21", 79 + heading: "#070e21", 80 + subheading: "#040710", 81 + url: "#1f3e98", 82 + visited: "#931f82", 83 + code: "#137B81", 84 + }, 85 + }, 86 + 87 + dark: { 88 + background: { 89 + main: "#262428", 90 + secondary: "#161418", 91 + code: "#303446", 92 + }, 93 + typography: { 94 + body: "#ffebff", 95 + heading: "#ffe8ff", 96 + subheading: "#ffe0ff", 97 + url: "#a8a8ff", 98 + visited: "#ff80ff", 99 + code: "#81c8be", 100 + }, 101 + }, 102 + 103 + rainbow: [ 104 + "#F09094", 105 + "#F6B379", 106 + "#F6E8A2", 107 + "#97BB77", 108 + "#C2D7FF", 109 + "#D784C9", 110 + ], 111 }, 112 + }, 113 } as const; 114 115 export const utils = {
+50
src/content/config.ts
···
··· 1 + import { defineCollection, z } from "astro:content"; 2 + import { file, glob } from "astro/loaders"; 3 + 4 + const blog = defineCollection({ 5 + loader: glob({ pattern: "**/*.md", base: "./src/content/posts" }), 6 + schema: z.object({ 7 + title: z.string(), 8 + date: z.date(), 9 + colour: z.string(), 10 + // no alt (empty as decorative) 11 + image: z 12 + .string() 13 + .refine( 14 + (value) => value.endsWith(".png"), 15 + (val) => ({ 16 + message: `${val} must end with .png`, 17 + }), 18 + ) 19 + .optional(), 20 + hasMdx: z.boolean().default(false), 21 + }), 22 + }); 23 + 24 + const blogMdx = defineCollection({ 25 + loader: glob({ pattern: "**/*.mdx", base: "./src/content/posts" }), 26 + schema: z.object({ 27 + title: z.string(), 28 + }), 29 + }); 30 + 31 + export type nav = { 32 + name: string; 33 + url: string | false; 34 + children?: nav[]; 35 + }; 36 + 37 + const navSchema: z.ZodType<nav> = z.lazy(() => 38 + z.object({ 39 + name: z.string(), 40 + url: z.string().or(z.literal(false)), 41 + children: z.optional(z.array(navSchema)), 42 + }), 43 + ); 44 + 45 + const nav = defineCollection({ 46 + loader: file("src/content/navList.json"), 47 + schema: z.array(navSchema), 48 + }); 49 + 50 + export const collections = { blog, blogMdx, nav };
+76
src/content/navList.json
···
··· 1 + { 2 + "urls": [ 3 + { 4 + "url": "/", 5 + "name": "Home" 6 + }, 7 + { 8 + "url": "/blog", 9 + "name": "Blog" 10 + }, 11 + { 12 + "url": false, 13 + "name": "More", 14 + "children": [ 15 + { 16 + "url": "/rss.xml", 17 + "name": "RSS" 18 + }, 19 + { 20 + "url": "/ai", 21 + "name": "AI Usage" 22 + }, 23 + { 24 + "url": "/use", 25 + "name": "Things I Use" 26 + } 27 + ] 28 + }, 29 + { 30 + "url": false, 31 + "name": "Socials", 32 + "children": [ 33 + { 34 + "url": "https://pdsls.dev/at://did:plc:4zht3z4caxwrw3dlsybodywc", 35 + "name": "atproto (pdsls)", 36 + "children": [ 37 + { 38 + "url": "https://deer.social/profile/did:plc:4zht3z4caxwrw3dlsybodywc", 39 + "name": "Bluesky" 40 + }, 41 + { 42 + "url": "https://tangled.sh/@vielle.dev", 43 + "name": "Tangled.sh" 44 + } 45 + ] 46 + }, 47 + { 48 + "url": "https://what-if-doctor-who-was-yuri-yaoi.tumblr.com/", 49 + "name": "Tumblr" 50 + }, 51 + { 52 + "url": "https://github.com/afterlifepro/", 53 + "name": "Github" 54 + } 55 + ] 56 + }, 57 + { 58 + "url": false, 59 + "name": "Projects", 60 + "children": [ 61 + { 62 + "url": "https://dong.vielle.dev", 63 + "name": "Dong (web)" 64 + }, 65 + { 66 + "url": "https://saltire-the-gays.vielle.dev", 67 + "name": "Saltire the Gays" 68 + }, 69 + { 70 + "url": "https://afterlifepro.neocities.org", 71 + "name": "Neocities (old site)" 72 + } 73 + ] 74 + } 75 + ] 76 + }
+1
src/content/posts
···
··· 1 + ../../posts
-49
src/content.config.ts
··· 1 - import { defineCollection, z } from "astro:content"; 2 - import { file, glob } from "astro/loaders"; 3 - 4 - const blog = defineCollection({ 5 - loader: glob({ pattern: "**/*.md", base: "./src/posts" }), 6 - schema: z.object({ 7 - title: z.string(), 8 - date: z.date(), 9 - colour: z.string(), 10 - // no alt (empty as decorative) 11 - image: z 12 - .string() 13 - .refine( 14 - (value) => value.endsWith(".png"), 15 - (val) => ({ 16 - message: `${val} must end with .png`, 17 - }), 18 - ) 19 - .optional(), 20 - hasMdx: z.boolean().default(false), 21 - }), 22 - }); 23 - 24 - const blogMdx = defineCollection({ 25 - loader: glob({ pattern: "**/*.mdx", base: "./src/posts" }), 26 - schema: z.object({ 27 - title: z.string(), 28 - }), 29 - }); 30 - 31 - const baseNav = z.object({ 32 - slug: z.string(), 33 - name: z.string(), 34 - }); 35 - 36 - export type nav = z.infer<typeof baseNav> & { 37 - children?: nav[]; 38 - }; 39 - 40 - const navSchema: z.ZodType<nav> = baseNav.extend({ 41 - children: z.lazy(() => navSchema.array()), 42 - }); 43 - 44 - const nav = defineCollection({ 45 - loader: file("src/navList.json"), 46 - schema: navSchema, 47 - }); 48 - 49 - export const collections = { blog, blogMdx, nav };
···
-28
src/navList.json
··· 1 - [ 2 - { 3 - "slug": "/", 4 - "name": "Home", 5 - "children": [] 6 - }, 7 - { 8 - "slug": "/blog", 9 - "name": "Blog", 10 - "children": [] 11 - }, 12 - { 13 - "slug": "/testing", 14 - "name": "Testing", 15 - "children": [ 16 - { 17 - "slug": "/123", 18 - "name": "123", 19 - "children": [] 20 - }, 21 - { 22 - "slug": "/maoii", 23 - "name": "Me!", 24 - "children": [] 25 - } 26 - ] 27 - } 28 - ]
···
+178 -6
src/pages/blog/[id].astro
··· 1 --- 2 import Base from "@/Base.astro"; 3 import { getEntry } from "astro:content"; 4 const { id } = Astro.params; 5 - const r404 = Astro.redirect("/404"); 6 7 - if (!id) return r404; 8 const post = await getEntry("blog", id); 9 - if (!post) return r404; 10 --- 11 12 - <Base title={post.data.title}> 13 - <h1>{post.data.title}</h1> 14 - <p>{JSON.stringify(post)}</p> 15 </Base>
··· 1 --- 2 import Base from "@/Base.astro"; 3 + import Nav from "@/components/navigation/Nav.astro"; 4 + import LightDarkToggle from "@/components/generic/LightDarkToggle.astro"; 5 + import CodeHeading from "@/components/blog/CodeHeading.astro"; 6 + 7 + import { render } from "astro:content"; 8 import { getEntry } from "astro:content"; 9 + import { parse } from "node:path"; 10 + 11 + import { blog } from "@/config"; 12 + import "@/components/blog/post.css"; 13 + 14 + const { 15 + post: { light, dark, rainbow }, 16 + } = blog.palette; 17 + 18 const { id } = Astro.params; 19 + if (!id) return Astro.redirect("/404"); 20 21 const post = await getEntry("blog", id); 22 + if (!post) return Astro.redirect("/404"); 23 + 24 + const { 25 + data: { title, hasMdx, colour }, 26 + } = post; 27 + 28 + const Content = await (async () => { 29 + if (!hasMdx) return render(post).then((x) => x.Content); 30 + 31 + if (!post.filePath) throw new Error("Post does not have a filepath"); 32 + return import(`../../content/posts/${parse(post.filePath).name}.mdx`).then( 33 + (x) => x.Content, 34 + ); 35 + })(); 36 --- 37 38 + <Base {title}> 39 + <Nav /> 40 + <header> 41 + <h1>{title}</h1> 42 + 43 + <LightDarkToggle 44 + colours={{ fg: "var(--bg-main)", bg: "var(--typo-body)" }} 45 + /> 46 + </header> 47 + 48 + <main style={`--accent: ${colour};`}> 49 + <div class="content"> 50 + <Content /> 51 + </div> 52 + </main> 53 </Base> 54 + 55 + <CodeHeading colours={{ text: "var(--typo-body)", border: "var(--bg-main)" }} /> 56 + 57 + <script> 58 + document.querySelectorAll(".astro-code").forEach((code) => { 59 + if (!(code instanceof HTMLElement)) return; 60 + 61 + const heading = document.createElement("code-heading"); 62 + heading.setAttribute("contents", code.innerText); 63 + 64 + const lang = code.dataset["language"]; 65 + if (lang && lang !== "plaintext") { 66 + const langEl = document.createElement("span"); 67 + langEl.innerText = "." + lang; 68 + heading.append(langEl); 69 + } 70 + 71 + code.prepend(heading); 72 + }); 73 + </script> 74 + 75 + <!-- page styles --> 76 + <style> 77 + header { 78 + position: fixed; 79 + top: 0; 80 + width: 100%; 81 + z-index: 999; 82 + display: flex; 83 + align-items: center; 84 + justify-content: space-between; 85 + 86 + background-color: var(--bg-secondary); 87 + color: var(--typo-heading); 88 + padding-bottom: 5px; 89 + 90 + & > :global(:not(style, script):last-of-type) { 91 + margin-right: 10px; 92 + margin-top: 5px; 93 + } 94 + } 95 + 96 + body { 97 + background-color: var(--bg-main); 98 + color: var(--typo-body); 99 + } 100 + 101 + .content { 102 + padding-block: 4em; 103 + } 104 + 105 + .content, 106 + :global(.full-width), 107 + :global([data-para-flag--full-width]) { 108 + --padding-inline: 20px; 109 + --content-max-width: 60ch; 110 + --breakout-max-width: 80ch; 111 + 112 + --content-size: min( 113 + 100% - var(--padding-inline) * 2, 114 + var(--content-max-width) 115 + ); 116 + --breakout-size: calc( 117 + (var(--breakout-max-width) - var(--content-max-width)) / 2 118 + ); 119 + 120 + display: grid; 121 + grid-template-columns: 122 + [full-width-start] minmax(var(--padding-inline), 1fr) 123 + [breakout-start] minmax(0, var(--breakout-size)) 124 + [content-start] var(--content-size) [content-end] 125 + minmax(0, var(--breakout-size)) [breakout-end] 126 + minmax(var(--padding-inline), 1fr) [full-width-end]; 127 + 128 + & > :global(*) { 129 + grid-column: content; 130 + } 131 + 132 + & > :global(.breakout), 133 + & > :global([data-para-flag--breakout]) { 134 + grid-column: breakout; 135 + } 136 + 137 + & > :global(.full-width), 138 + & > :global([data-para-flag--full-width]) { 139 + grid-column: full-width; 140 + } 141 + } 142 + 143 + :global(#nav-menu) { 144 + height: 3em; 145 + aspect-ratio: 1; 146 + display: flex; 147 + justify-content: center; 148 + align-items: center; 149 + 150 + & :global(svg) { 151 + stroke: var(--typo-body); 152 + } 153 + } 154 + </style> 155 + 156 + <style 157 + set:html={` 158 + :root { 159 + color-scheme: ${ 160 + Astro.cookies.get("colour-mode")?.value === "light" 161 + ? "light" 162 + : Astro.cookies.get("colour-mode")?.value === "dark" 163 + ? "dark" 164 + : "light dark" 165 + }; 166 + 167 + --bg-main: light-dark(${light.background.main}, ${dark.background.main}); 168 + --bg-secondary: light-dark(${light.background.secondary}, ${dark.background.secondary}); 169 + --bg-code: light-dark(${light.background.code}, ${dark.background.code}); 170 + 171 + --typo-body: light-dark(${light.typography.body}, ${dark.typography.body}); 172 + --typo-heading: light-dark(${light.typography.heading}, ${dark.typography.heading}); 173 + --typo-subheading: light-dark(${light.typography.subheading}, ${dark.typography.subheading}); 174 + --typo-code: light-dark(${light.typography.code}, ${dark.typography.code}); 175 + 176 + --typo-url: light-dark(${light.typography.url}, ${dark.typography.url}); 177 + --typo-visited: light-dark(${light.typography.visited}, ${dark.typography.visited}); 178 + 179 + --rainbow-0: ${rainbow[0]}; 180 + --rainbow-1: ${rainbow[1]}; 181 + --rainbow-2: ${rainbow[2]}; 182 + --rainbow-3: ${rainbow[3]}; 183 + --rainbow-4: ${rainbow[4]}; 184 + --rainbow-5: ${rainbow[5]}; 185 + } 186 + `} 187 + ></style>
+12 -15
src/pages/blog/index.astro
··· 2 import Base from "@/Base.astro"; 3 import Post from "@/components/blog/Post.astro"; 4 import Background from "@/components/blog/Background.astro"; 5 - import Nav from "@/components/generic/Nav.astro"; 6 7 import Rss from "@/assets/rss.svg"; 8 ··· 10 import { blog } from "@/config"; 11 12 const posts = await getCollection("blog").then((x) => 13 - x.sort((a, b) => b.data.date.getTime() - a.data.date.getTime()) 14 ); 15 - const nav = await getCollection("nav").then((x) => x.map((x) => x.data)); 16 --- 17 18 <style> ··· 22 height: 2em; 23 aspect-ratio: 1; 24 padding: 0.2em; 25 - border-radius: 0.5rem; 26 27 & svg { 28 width: 1.6em; ··· 31 } 32 33 heading { 34 - font-size: 1.6rem; 35 margin-bottom: var(--y-gap); 36 color: white; 37 ··· 44 justify-content: space-between; 45 46 & a { 47 - margin: 0.5rem 1rem; 48 } 49 } 50 51 .top-offset { 52 height: var(--top-gap); 53 } 54 </style> 55 56 <Base title="Blog"> 57 <Background /> 58 <main> 59 - <heading style={`--y-gap: ${blog.post.yGap}rem`}> 60 - <Nav data={nav} current="Blog" /> 61 - 62 - <a href="/rss.xml" aria-label="Rss Feed"> 63 - <Rss width="1.6em" height="1.6em" /> 64 - </a> 65 - </heading> 66 - 67 - <div class="top-offset" style={`--top-gap: ${blog.post.topYGap}rem;`}></div> 68 69 { 70 posts.map((x, i) => (
··· 2 import Base from "@/Base.astro"; 3 import Post from "@/components/blog/Post.astro"; 4 import Background from "@/components/blog/Background.astro"; 5 + import Nav from "@/components/navigation/Nav.astro"; 6 7 import Rss from "@/assets/rss.svg"; 8 ··· 10 import { blog } from "@/config"; 11 12 const posts = await getCollection("blog").then((x) => 13 + x.sort((a, b) => b.data.date.getTime() - a.data.date.getTime()), 14 ); 15 --- 16 17 <style> ··· 21 height: 2em; 22 aspect-ratio: 1; 23 padding: 0.2em; 24 + border-radius: 5px; 25 26 & svg { 27 width: 1.6em; ··· 30 } 31 32 heading { 33 margin-bottom: var(--y-gap); 34 color: white; 35 ··· 42 justify-content: space-between; 43 44 & a { 45 + margin: 5px 10px; 46 } 47 } 48 49 .top-offset { 50 height: var(--top-gap); 51 } 52 + 53 + :global(#nav-menu) { 54 + background-color: black; 55 + padding: 10px; 56 + border-radius: 0 0 50% 0; 57 + } 58 </style> 59 60 <Base title="Blog"> 61 + <Nav /> 62 <Background /> 63 <main> 64 + <div class="top-offset" style={`--top-gap: ${blog.post.topYGap}px;`}></div> 65 66 { 67 posts.map((x, i) => (
+12 -51
src/pages/index.astro
··· 1 --- 2 - // import Map from "@/components/map.astro" 3 import Base from "@/Base.astro"; 4 - import Map from "@/components/index/Map.astro"; 5 --- 6 7 - <Base title="home"> 8 - <style slot="head"> 9 - body { 10 - width: 100vw; 11 - height: 100vh; 12 - display: flex; 13 - align-items: center; 14 - justify-content: center; 15 - flex-direction: column; 16 - gap: 5rem; 17 - padding: 0; 18 - margin: 0; 19 - background-color: #011627; 20 - color: #f8f8f2; 21 - } 22 - </style> 23 - <h1>vielle.dev ๐Ÿชค | wip</h1> 24 - <Map 25 - locations={[ 26 - { 27 - colour: "red", 28 - name: "Blog", 29 - href: "/blog", 30 - x: 6, 31 - y: 2, 32 - }, 33 - { 34 - colour: "magenta", 35 - name: "Projects", 36 - href: "/projects", 37 - x: 6, 38 - y: 5, 39 - }, 40 - { 41 - colour: "blue", 42 - name: "Hobbies", 43 - href: "/hobbies", 44 - x: 1, 45 - y: 4, 46 - }, 47 - { 48 - colour: "cyan", 49 - name: "Linktree", 50 - href: "/linktree", 51 - x: 3, 52 - y: 2, 53 - }, 54 - ]} 55 - /> 56 </Base>
··· 1 --- 2 import Base from "@/Base.astro"; 3 + import Nav from "@/components/navigation/Nav.astro"; 4 --- 5 6 + <Base> 7 + <Nav /> 8 </Base> 9 + 10 + <style> 11 + body { 12 + width: 100vw; 13 + height: 100vh; 14 + background-color: #011627; 15 + color: #f8f8f2; 16 + } 17 + </style>
-1
src/posts
··· 1 - ../posts
···
-5
svelte.config.js
··· 1 - import { vitePreprocess } from "@astrojs/svelte"; 2 - 3 - export default { 4 - preprocess: vitePreprocess(), 5 - };
···
-86
wrangler.toml
··· 1 - #:schema node_modules/wrangler/config-schema.json 2 - name = "astral-powers-v2" 3 - compatibility_date = "2025-01-09" 4 - compatibility_flags = ["nodejs_compat"] 5 - pages_build_output_dir = "./dist" 6 - 7 - # Automatically place your workloads in an optimal location to minimize latency. 8 - # If you are running back-end logic in a Pages Function, running it closer to your back-end infrastructure 9 - # rather than the end user may result in better performance. 10 - # Docs: https://developers.cloudflare.com/pages/functions/smart-placement/#smart-placement 11 - # [placement] 12 - # mode = "smart" 13 - 14 - # Variable bindings. These are arbitrary, plaintext strings (similar to environment variables) 15 - # Docs: 16 - # - https://developers.cloudflare.com/pages/functions/bindings/#environment-variables 17 - # Note: Use secrets to store sensitive data. 18 - # - https://developers.cloudflare.com/pages/functions/bindings/#secrets 19 - # [vars] 20 - # MY_VARIABLE = "production_value" 21 - 22 - # Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflareโ€™s global network 23 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#workers-ai 24 - # [ai] 25 - # binding = "AI" 26 - 27 - # Bind a D1 database. D1 is Cloudflareโ€™s native serverless SQL database. 28 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#d1-databases 29 - # [[d1_databases]] 30 - # binding = "MY_DB" 31 - # database_name = "my-database" 32 - # database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 33 - 34 - # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. 35 - # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. 36 - # Docs: https://developers.cloudflare.com/workers/runtime-apis/durable-objects 37 - # [[durable_objects.bindings]] 38 - # name = "MY_DURABLE_OBJECT" 39 - # class_name = "MyDurableObject" 40 - # script_name = 'my-durable-object' 41 - 42 - # Bind a KV Namespace. Use KV as persistent storage for small key-value pairs. 43 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#kv-namespaces 44 - # [[kv_namespaces]] 45 - # binding = "MY_KV_NAMESPACE" 46 - # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 47 - 48 - # Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer. 49 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#queue-producers 50 - # [[queues.producers]] 51 - # binding = "MY_QUEUE" 52 - # queue = "my-queue" 53 - 54 - # Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files. 55 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#r2-buckets 56 - # [[r2_buckets]] 57 - # binding = "MY_BUCKET" 58 - # bucket_name = "my-bucket" 59 - 60 - # Bind another Worker service. Use this binding to call another Worker without network overhead. 61 - # Docs: https://developers.cloudflare.com/pages/functions/bindings/#service-bindings 62 - # [[services]] 63 - # binding = "MY_SERVICE" 64 - # service = "my-service" 65 - 66 - # To use different bindings for preview and production environments, follow the examples below. 67 - # When using environment-specific overrides for bindings, ALL bindings must be specified on a per-environment basis. 68 - # Docs: https://developers.cloudflare.com/pages/functions/wrangler-configuration#environment-specific-overrides 69 - 70 - ######## PREVIEW environment config ######## 71 - 72 - # [env.preview.vars] 73 - # API_KEY = "xyz789" 74 - 75 - # [[env.preview.kv_namespaces]] 76 - # binding = "MY_KV_NAMESPACE" 77 - # id = "<PREVIEW_NAMESPACE_ID>" 78 - 79 - ######## PRODUCTION environment config ######## 80 - 81 - # [env.production.vars] 82 - # API_KEY = "abc123" 83 - 84 - # [[env.production.kv_namespaces]] 85 - # binding = "MY_KV_NAMESPACE" 86 - # id = "<PRODUCTION_NAMESPACE_ID>"
···