+1
.gitignore
+1
.gitignore
+15
-3
astro.config.mjs
+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
-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
+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
+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::  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
+

131
+
132
+
 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
+

+1
-7
posts/test.mdx
+1
-7
posts/test.mdx
+175
rehype-custom-html.ts
+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
+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
+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
+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
-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
-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
+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
+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
+1
-2
src/assets/hamburger.svg
src/assets/mc_map.png
src/assets/mc_map.png
This is a binary file and will not be displayed.
src/assets/mc_map_contents.png
src/assets/mc_map_contents.png
This is a binary file and will not be displayed.
+15
src/assets/moon.svg
+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
+1
src/assets/rss.svg
+23
src/assets/sun.svg
+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
-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
+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
+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
+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
-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
+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
+3
-3
src/components/blog/background/Clouds.astro
+10
-9
src/components/blog/background/Moon.astro
+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
+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
+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
+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
+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>
-210
src/components/index/Map.astro
-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>
···
+70
-25
src/config.ts
+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
+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 };
+1
src/content/posts
+1
src/content/posts
···
···
1
+
../../posts
-49
src/content.config.ts
-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 };
···
+178
-6
src/pages/blog/[id].astro
+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
+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
+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
src/posts
-1
src/posts
···
1
-
../posts
···
-5
svelte.config.js
-5
svelte.config.js
-86
wrangler.toml
-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>"
···