+15
-3
astro.config.mjs
+15
-3
astro.config.mjs
···
1
1
// @ts-check
2
2
import { defineConfig } from "astro/config";
3
-
4
3
import mdx from "@astrojs/mdx";
4
+
import sitemap from "@astrojs/sitemap";
5
5
6
-
import sitemap from "@astrojs/sitemap";
6
+
import { rehypeAccessibleEmojis } from "rehype-accessible-emojis";
7
+
import rehypeCustomHtml from "./rehype-custom-html";
7
8
8
9
// https://astro.build/config
9
10
export default defineConfig({
10
11
integrations: [mdx(), sitemap()],
11
12
12
13
output: "server",
13
-
14
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
+
},
15
27
});
+12
-6
package.json
+12
-6
package.json
···
12
12
},
13
13
"dependencies": {
14
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",
15
+
"@astrojs/mdx": "^4.3.0",
16
+
"@astrojs/rss": "^4.0.12",
17
+
"@astrojs/sitemap": "^3.4.1",
18
+
"astro": "5.11.0",
19
19
"lunarphase-js": "^2.0.3",
20
20
"markdown-it": "^14.1.0",
21
-
"typescript": "^5.8.3"
21
+
"rehype-accessible-emojis": "^0.3.2",
22
+
"remark-toc": "^9.0.0",
23
+
"typescript": "^5.8.3",
24
+
"unified": "^11.0.5"
22
25
},
23
26
"devDependencies": {
27
+
"@types/hast": "^3.0.4",
24
28
"prettier": "3.5.3",
25
-
"prettier-plugin-astro": "0.14.1"
29
+
"prettier-plugin-astro": "0.14.1",
30
+
"pretty-quick": "^4.1.1",
31
+
"simple-git-hooks": "^2.13.0"
26
32
}
27
33
}
+258
-48
pnpm-lock.yaml
+258
-48
pnpm-lock.yaml
···
11
11
specifier: ^0.9.4
12
12
version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)
13
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))
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
16
"@astrojs/rss":
17
-
specifier: ^4.0.11
18
-
version: 4.0.11
17
+
specifier: ^4.0.12
18
+
version: 4.0.12
19
19
"@astrojs/sitemap":
20
-
specifier: ^3.4.0
21
-
version: 3.4.0
20
+
specifier: ^3.4.1
21
+
version: 3.4.1
22
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)
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
25
lunarphase-js:
26
26
specifier: ^2.0.3
27
27
version: 2.0.3
28
28
markdown-it:
29
29
specifier: ^14.1.0
30
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
31
37
typescript:
32
38
specifier: ^5.8.3
33
39
version: 5.8.3
40
+
unified:
41
+
specifier: ^11.0.5
42
+
version: 11.0.5
34
43
devDependencies:
44
+
"@types/hast":
45
+
specifier: ^3.0.4
46
+
version: 3.0.4
35
47
prettier:
36
48
specifier: 3.5.3
37
49
version: 3.5.3
38
50
prettier-plugin-astro:
39
51
specifier: 0.14.1
40
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
41
59
42
60
packages:
43
61
"@astrojs/check@0.9.4":
···
55
73
integrity: sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA==,
56
74
}
57
75
76
+
"@astrojs/compiler@2.12.2":
77
+
resolution:
78
+
{
79
+
integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==,
80
+
}
81
+
58
82
"@astrojs/internal-helpers@0.6.1":
59
83
resolution:
60
84
{
···
76
100
prettier-plugin-astro:
77
101
optional: true
78
102
79
-
"@astrojs/markdown-remark@6.3.1":
103
+
"@astrojs/markdown-remark@6.3.2":
80
104
resolution:
81
105
{
82
-
integrity: sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg==,
106
+
integrity: sha512-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q==,
83
107
}
84
108
85
-
"@astrojs/mdx@4.2.6":
109
+
"@astrojs/mdx@4.3.0":
86
110
resolution:
87
111
{
88
-
integrity: sha512-0i/GmOm6d0qq1/SCfcUgY/IjDc/bS0i42u7h85TkPFBmlFOcBZfkYhR5iyz6hZLwidvJOEq5yGfzt9B1Azku4w==,
112
+
integrity: sha512-OGX2KvPeBzjSSKhkCqrUoDMyzFcjKt5nTE5SFw3RdoLf0nrhyCXBQcCyclzWy1+P+XpOamn+p+hm1EhpCRyPxw==,
89
113
}
90
-
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
114
+
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
91
115
peerDependencies:
92
116
astro: ^5.0.0
93
117
94
-
"@astrojs/prism@3.2.0":
118
+
"@astrojs/prism@3.3.0":
95
119
resolution:
96
120
{
97
-
integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==,
121
+
integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==,
98
122
}
99
-
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
123
+
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
100
124
101
-
"@astrojs/rss@4.0.11":
125
+
"@astrojs/rss@4.0.12":
102
126
resolution:
103
127
{
104
-
integrity: sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==,
128
+
integrity: sha512-O5yyxHuDVb6DQ6VLOrbUVFSm+NpObulPxjs6XT9q3tC+RoKbN4HXMZLpv0LvXd1qdAjzVgJ1NFD+zKHJNDXikw==,
105
129
}
106
130
107
-
"@astrojs/sitemap@3.4.0":
131
+
"@astrojs/sitemap@3.4.1":
108
132
resolution:
109
133
{
110
-
integrity: sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ==,
134
+
integrity: sha512-VjZvr1e4FH6NHyyHXOiQgLiw94LnCVY4v06wN/D0gZKchTMkg71GrAHJz81/huafcmavtLkIv26HnpfDq6/h/Q==,
111
135
}
112
136
113
-
"@astrojs/telemetry@3.2.1":
137
+
"@astrojs/telemetry@3.3.0":
114
138
resolution:
115
139
{
116
-
integrity: sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg==,
140
+
integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==,
117
141
}
118
-
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
142
+
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
119
143
120
144
"@astrojs/yaml2ts@0.2.2":
121
145
resolution:
···
924
948
integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==,
925
949
}
926
950
951
+
"@types/ungap__structured-clone@1.2.0":
952
+
resolution:
953
+
{
954
+
integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==,
955
+
}
956
+
927
957
"@types/unist@2.0.11":
928
958
resolution:
929
959
{
···
1087
1117
}
1088
1118
hasBin: true
1089
1119
1090
-
astro@5.7.13:
1120
+
astro@5.11.0:
1091
1121
resolution:
1092
1122
{
1093
-
integrity: sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w==,
1123
+
integrity: sha512-MEICntERthUxJPSSDsDiZuwiCMrsaYy3fnDhp4c6ScUfldCB8RBnB/myYdpTFXpwYBy6SgVsHQ1H4MuuA7ro/Q==,
1094
1124
}
1095
1125
engines:
1096
-
{ node: ^18.17.1 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" }
1126
+
{ node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" }
1097
1127
hasBin: true
1098
1128
1099
1129
axobject-query@4.1.0:
···
1557
1587
integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==,
1558
1588
}
1559
1589
1560
-
fast-xml-parser@4.5.3:
1590
+
fast-xml-parser@5.2.3:
1561
1591
resolution:
1562
1592
{
1563
-
integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==,
1593
+
integrity: sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==,
1564
1594
}
1565
1595
hasBin: true
1566
1596
···
1588
1618
}
1589
1619
engines: { node: ">=8" }
1590
1620
1621
+
find-up@5.0.0:
1622
+
resolution:
1623
+
{
1624
+
integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==,
1625
+
}
1626
+
engines: { node: ">=10" }
1627
+
1591
1628
flattie@1.1.1:
1592
1629
resolution:
1593
1630
{
···
1614
1651
}
1615
1652
engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
1616
1653
os: [darwin]
1654
+
1655
+
gemoji@4.2.1:
1656
+
resolution:
1657
+
{
1658
+
integrity: sha512-V9lUpRSn+KQGavZx8Pk+6mxG3kaz21ae2kTCXuT36KaRPNgYU8eHtj/RcUCNFVvmwppsYYz3nnNS9lmcP5kTsg==,
1659
+
}
1617
1660
1618
1661
get-caller-file@2.0.5:
1619
1662
resolution:
···
1660
1703
integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==,
1661
1704
}
1662
1705
1706
+
hast-util-is-element@1.1.0:
1707
+
resolution:
1708
+
{
1709
+
integrity: sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==,
1710
+
}
1711
+
1663
1712
hast-util-is-element@3.0.0:
1664
1713
resolution:
1665
1714
{
···
1737
1786
{
1738
1787
integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==,
1739
1788
}
1789
+
1790
+
ignore@7.0.5:
1791
+
resolution:
1792
+
{
1793
+
integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==,
1794
+
}
1795
+
engines: { node: ">= 4" }
1740
1796
1741
1797
import-meta-resolve@4.1.0:
1742
1798
resolution:
···
1889
1945
integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==,
1890
1946
}
1891
1947
1948
+
locate-path@6.0.0:
1949
+
resolution:
1950
+
{
1951
+
integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==,
1952
+
}
1953
+
engines: { node: ">=10" }
1954
+
1892
1955
lodash@4.17.21:
1893
1956
resolution:
1894
1957
{
···
2045
2108
resolution:
2046
2109
{
2047
2110
integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==,
2111
+
}
2112
+
2113
+
mdast-util-toc@7.1.0:
2114
+
resolution:
2115
+
{
2116
+
integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==,
2048
2117
}
2049
2118
2050
2119
mdn-data@2.12.2:
···
2283
2352
}
2284
2353
engines: { node: ">=8.6" }
2285
2354
2355
+
mri@1.2.0:
2356
+
resolution:
2357
+
{
2358
+
integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==,
2359
+
}
2360
+
engines: { node: ">=4" }
2361
+
2286
2362
mrmime@2.0.1:
2287
2363
resolution:
2288
2364
{
···
2378
2454
integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==,
2379
2455
}
2380
2456
2457
+
p-limit@3.1.0:
2458
+
resolution:
2459
+
{
2460
+
integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==,
2461
+
}
2462
+
engines: { node: ">=10" }
2463
+
2381
2464
p-limit@6.2.0:
2382
2465
resolution:
2383
2466
{
2384
2467
integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==,
2385
2468
}
2386
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" }
2387
2477
2388
2478
p-queue@8.1.0:
2389
2479
resolution:
···
2434
2524
{
2435
2525
integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==,
2436
2526
}
2527
+
2528
+
path-exists@4.0.0:
2529
+
resolution:
2530
+
{
2531
+
integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==,
2532
+
}
2533
+
engines: { node: ">=8" }
2437
2534
2438
2535
picocolors@1.1.1:
2439
2536
resolution:
···
2485
2582
engines: { node: ">=14" }
2486
2583
hasBin: true
2487
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
+
2488
2595
prismjs@1.30.0:
2489
2596
resolution:
2490
2597
{
···
2579
2686
integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==,
2580
2687
}
2581
2688
2689
+
rehype-accessible-emojis@0.3.2:
2690
+
resolution:
2691
+
{
2692
+
integrity: sha512-kChZo+EZsuFQYHUPu6kOZFjDrG7UtQdGxkrCvHBVo9ariKPL6S68QdPVxLxwcAtZSRZIXZhDuTJHgIM8KW24Qw==,
2693
+
}
2694
+
2582
2695
rehype-parse@9.0.1:
2583
2696
resolution:
2584
2697
{
···
2646
2759
integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==,
2647
2760
}
2648
2761
2762
+
remark-toc@9.0.0:
2763
+
resolution:
2764
+
{
2765
+
integrity: sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA==,
2766
+
}
2767
+
2649
2768
request-light@0.5.8:
2650
2769
resolution:
2651
2770
{
···
2762
2881
integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==,
2763
2882
}
2764
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
+
2765
2891
simple-swizzle@0.2.2:
2766
2892
resolution:
2767
2893
{
···
2849
2975
}
2850
2976
engines: { node: ">=12" }
2851
2977
2852
-
strnum@1.1.2:
2978
+
strnum@2.1.1:
2853
2979
resolution:
2854
2980
{
2855
-
integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==,
2981
+
integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==,
2856
2982
}
2857
2983
2858
2984
style-to-js@1.1.16:
···
3021
3147
resolution:
3022
3148
{
3023
3149
integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==,
3150
+
}
3151
+
3152
+
unist-util-flatmap@1.0.0:
3153
+
resolution:
3154
+
{
3155
+
integrity: sha512-IG32jcKJlhARCYT2LsYPJWdoXYkzz3ESAdl1aa2hn9Auh+cgUmU6wgkII4yCc/1GgeWibRdELdCZh/p3QKQ1dQ==,
3024
3156
}
3025
3157
3026
3158
unist-util-is@6.0.0:
···
3475
3607
}
3476
3608
engines: { node: ">=12" }
3477
3609
3610
+
yocto-queue@0.1.0:
3611
+
resolution:
3612
+
{
3613
+
integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==,
3614
+
}
3615
+
engines: { node: ">=10" }
3616
+
3478
3617
yocto-queue@1.2.1:
3479
3618
resolution:
3480
3619
{
···
3539
3678
3540
3679
"@astrojs/compiler@2.12.0": {}
3541
3680
3681
+
"@astrojs/compiler@2.12.2": {}
3682
+
3542
3683
"@astrojs/internal-helpers@0.6.1": {}
3543
3684
3544
3685
"@astrojs/language-server@2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)":
···
3567
3708
transitivePeerDependencies:
3568
3709
- typescript
3569
3710
3570
-
"@astrojs/markdown-remark@6.3.1":
3711
+
"@astrojs/markdown-remark@6.3.2":
3571
3712
dependencies:
3572
3713
"@astrojs/internal-helpers": 0.6.1
3573
-
"@astrojs/prism": 3.2.0
3714
+
"@astrojs/prism": 3.3.0
3574
3715
github-slugger: 2.0.0
3575
3716
hast-util-from-html: 2.0.3
3576
3717
hast-util-to-text: 4.0.2
···
3593
3734
transitivePeerDependencies:
3594
3735
- supports-color
3595
3736
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))":
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))":
3597
3738
dependencies:
3598
-
"@astrojs/markdown-remark": 6.3.1
3739
+
"@astrojs/markdown-remark": 6.3.2
3599
3740
"@mdx-js/mdx": 3.1.0(acorn@8.14.1)
3600
3741
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)
3742
+
astro: 5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0)
3602
3743
es-module-lexer: 1.7.0
3603
3744
estree-util-visit: 2.0.0
3604
3745
hast-util-to-html: 9.0.5
···
3612
3753
transitivePeerDependencies:
3613
3754
- supports-color
3614
3755
3615
-
"@astrojs/prism@3.2.0":
3756
+
"@astrojs/prism@3.3.0":
3616
3757
dependencies:
3617
3758
prismjs: 1.30.0
3618
3759
3619
-
"@astrojs/rss@4.0.11":
3760
+
"@astrojs/rss@4.0.12":
3620
3761
dependencies:
3621
-
fast-xml-parser: 4.5.3
3762
+
fast-xml-parser: 5.2.3
3622
3763
kleur: 4.1.5
3623
3764
3624
-
"@astrojs/sitemap@3.4.0":
3765
+
"@astrojs/sitemap@3.4.1":
3625
3766
dependencies:
3626
3767
sitemap: 8.0.0
3627
3768
stream-replace-string: 2.0.0
3628
3769
zod: 3.25.7
3629
3770
3630
-
"@astrojs/telemetry@3.2.1":
3771
+
"@astrojs/telemetry@3.3.0":
3631
3772
dependencies:
3632
3773
ci-info: 4.2.0
3633
3774
debug: 4.4.1
···
4031
4172
4032
4173
"@types/sax@1.2.7":
4033
4174
dependencies:
4034
-
"@types/node": 17.0.45
4175
+
"@types/node": 22.15.20
4176
+
4177
+
"@types/ungap__structured-clone@1.2.0": {}
4035
4178
4036
4179
"@types/unist@2.0.11": {}
4037
4180
···
4131
4274
4132
4275
astring@1.9.0: {}
4133
4276
4134
-
astro@5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0):
4277
+
astro@5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0):
4135
4278
dependencies:
4136
-
"@astrojs/compiler": 2.12.0
4279
+
"@astrojs/compiler": 2.12.2
4137
4280
"@astrojs/internal-helpers": 0.6.1
4138
-
"@astrojs/markdown-remark": 6.3.1
4139
-
"@astrojs/telemetry": 3.2.1
4281
+
"@astrojs/markdown-remark": 6.3.2
4282
+
"@astrojs/telemetry": 3.3.0
4140
4283
"@capsizecss/unpack": 2.4.0
4141
4284
"@oslojs/encoding": 1.1.0
4142
4285
"@rollup/pluginutils": 5.1.4(rollup@4.41.0)
···
4163
4306
github-slugger: 2.0.0
4164
4307
html-escaper: 3.0.3
4165
4308
http-cache-semantics: 4.2.0
4309
+
import-meta-resolve: 4.1.0
4166
4310
js-yaml: 4.1.0
4167
4311
kleur: 4.1.5
4168
4312
magic-string: 0.30.17
···
4483
4627
4484
4628
fast-uri@3.0.6: {}
4485
4629
4486
-
fast-xml-parser@4.5.3:
4630
+
fast-xml-parser@5.2.3:
4487
4631
dependencies:
4488
-
strnum: 1.1.2
4632
+
strnum: 2.1.1
4489
4633
4490
4634
fastq@1.19.1:
4491
4635
dependencies:
···
4499
4643
dependencies:
4500
4644
to-regex-range: 5.0.1
4501
4645
4646
+
find-up@5.0.0:
4647
+
dependencies:
4648
+
locate-path: 6.0.0
4649
+
path-exists: 4.0.0
4650
+
4502
4651
flattie@1.1.1: {}
4503
4652
4504
4653
fontace@0.3.0:
···
4520
4669
4521
4670
fsevents@2.3.3:
4522
4671
optional: true
4672
+
4673
+
gemoji@4.2.1: {}
4523
4674
4524
4675
get-caller-file@2.0.5: {}
4525
4676
···
4562
4713
vfile: 6.0.3
4563
4714
vfile-location: 5.0.3
4564
4715
web-namespaces: 2.0.1
4716
+
4717
+
hast-util-is-element@1.1.0: {}
4565
4718
4566
4719
hast-util-is-element@3.0.0:
4567
4720
dependencies:
···
4676
4829
html-void-elements@3.0.0: {}
4677
4830
4678
4831
http-cache-semantics@4.2.0: {}
4832
+
4833
+
ignore@7.0.5: {}
4679
4834
4680
4835
import-meta-resolve@4.1.0: {}
4681
4836
···
4737
4892
dependencies:
4738
4893
uc.micro: 2.1.0
4739
4894
4895
+
locate-path@6.0.0:
4896
+
dependencies:
4897
+
p-locate: 5.0.0
4898
+
4740
4899
lodash@4.17.21: {}
4741
4900
4742
4901
longest-streak@3.1.0: {}
···
4936
5095
mdast-util-to-string@4.0.0:
4937
5096
dependencies:
4938
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
4939
5108
4940
5109
mdn-data@2.12.2: {}
4941
5110
···
5212
5381
braces: 3.0.3
5213
5382
picomatch: 2.3.1
5214
5383
5384
+
mri@1.2.0: {}
5385
+
5215
5386
mrmime@2.0.1: {}
5216
5387
5217
5388
ms@2.1.3: {}
···
5252
5423
regex: 6.0.1
5253
5424
regex-recursion: 6.0.2
5254
5425
5426
+
p-limit@3.1.0:
5427
+
dependencies:
5428
+
yocto-queue: 0.1.0
5429
+
5255
5430
p-limit@6.2.0:
5256
5431
dependencies:
5257
5432
yocto-queue: 1.2.1
5433
+
5434
+
p-locate@5.0.0:
5435
+
dependencies:
5436
+
p-limit: 3.1.0
5258
5437
5259
5438
p-queue@8.1.0:
5260
5439
dependencies:
···
5292
5471
5293
5472
path-browserify@1.0.1: {}
5294
5473
5474
+
path-exists@4.0.0: {}
5475
+
5295
5476
picocolors@1.1.1: {}
5296
5477
5297
5478
picomatch@2.3.1: {}
···
5315
5496
5316
5497
prettier@3.5.3: {}
5317
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
+
5318
5510
prismjs@1.30.0: {}
5319
5511
5320
5512
prompts@2.4.2:
···
5374
5566
dependencies:
5375
5567
regex-utilities: 2.3.0
5376
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
+
5377
5576
rehype-parse@9.0.1:
5378
5577
dependencies:
5379
5578
"@types/hast": 3.0.4
···
5455
5654
mdast-util-to-markdown: 2.1.2
5456
5655
unified: 11.0.5
5457
5656
5657
+
remark-toc@9.0.0:
5658
+
dependencies:
5659
+
"@types/mdast": 4.0.4
5660
+
mdast-util-toc: 7.1.0
5661
+
5458
5662
request-light@0.5.8: {}
5459
5663
5460
5664
request-light@0.7.0: {}
···
5570
5774
"@shikijs/vscode-textmate": 10.0.2
5571
5775
"@types/hast": 3.0.4
5572
5776
5777
+
simple-git-hooks@2.13.0: {}
5778
+
5573
5779
simple-swizzle@0.2.2:
5574
5780
dependencies:
5575
5781
is-arrayish: 0.3.2
···
5619
5825
dependencies:
5620
5826
ansi-regex: 6.1.0
5621
5827
5622
-
strnum@1.1.2: {}
5828
+
strnum@2.1.1: {}
5623
5829
5624
5830
style-to-js@1.1.16:
5625
5831
dependencies:
···
5708
5914
"@types/unist": 3.0.3
5709
5915
unist-util-is: 6.0.0
5710
5916
5917
+
unist-util-flatmap@1.0.0: {}
5918
+
5711
5919
unist-util-is@6.0.0:
5712
5920
dependencies:
5713
5921
"@types/unist": 3.0.3
···
5963
6171
string-width: 4.2.3
5964
6172
y18n: 5.0.8
5965
6173
yargs-parser: 21.1.1
6174
+
6175
+
yocto-queue@0.1.0: {}
5966
6176
5967
6177
yocto-queue@1.2.1: {}
5968
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
···
2
2
title: Test Post
3
3
---
4
4
5
-
import Balloon from "@components/blog/balloon.svelte";
6
-
7
5
whats this about dawg
8
6
9
-
<div style="padding: 15rem;"></div>
10
-
11
-
<div style="position: absolute">
12
-
<Balloon client:load id={0} boundingWidth={300} boundingHeight={0} />
13
-
</div>
7
+
(Vi a vis .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
1
---
2
2
interface Props {
3
-
title: string;
3
+
title?: string;
4
4
dataset?: Record<string, any>;
5
5
[key: string]: any;
6
6
}
···
27
27
<meta name="viewport" content="width=device-width" />
28
28
<meta name="generator" content={Astro.generator} />
29
29
<link rel="sitemap" href="/sitemap-index.xml" />
30
-
<title>{title} | vielle.dev</title>
30
+
<title>{title ? `${title} | vielle.dev` : "vielle.dev"}</title>
31
31
<script>
32
32
// sets the timezone offset
33
-
document.cookie = `timezone=${new Date().toString()}`;
33
+
document.cookie = `timezone=${new Date().toString()};path=/`;
34
34
</script>
35
-
<!-- default styles (rem, *) -->
35
+
<!-- default styles -->
36
36
<style is:global>
37
37
@layer reset {
38
-
:root {
39
-
font-size: 62.5%;
40
-
}
41
38
body {
42
-
font-size: 1.6rem;
43
39
line-height: 1.5;
44
40
-webkit-font-smoothing: antialiased;
45
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
···
9
9
stroke-linecap="round"
10
10
stroke-linejoin="round"
11
11
class="lucide lucide-menu-icon lucide-menu"
12
-
title=""
13
12
>
14
-
<title><!-- no alt text as used for buttons --></title>
13
+
<title>Menu</title>
15
14
<path d="M4 12h16" />
16
15
<path d="M4 18h16" />
17
16
<path d="M4 6h16" />
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
12
Astro.cookies.get("timezone")?.value ??
13
13
Astro.request.headers.get("Date") ??
14
14
Astro.request.headers.get("date") ?? // idk if it cares about capitals so Both
15
-
Date.now()
15
+
Date.now(),
16
16
);
17
17
18
18
const accurateHours =
···
65
65
<div
66
66
id="background"
67
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}`}
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
74
aria-hidden="true"
75
75
>
76
76
{
+21
-24
src/components/blog/Balloon.astro
+21
-24
src/components/blog/Balloon.astro
···
17
17
18
18
<div
19
19
class="cable"
20
-
style={`--length: ${length}rem;
20
+
style={`--length: ${length}px;
21
21
--id: ${id};
22
22
--of: ${of};
23
-
--offset: ${offset}rem;
23
+
--offset: ${offset}px;
24
24
${rotation.map((x, i) => `--rot-${i}: ${x}deg;`).join(" ")}
25
25
--timing: ${utils.getRandom(blog.balloons.timing)}s;
26
26
`}
27
27
>
28
28
<div
29
29
class="balloon"
30
-
style={`--width: ${utils.getRandom(blog.balloons.size[0])}rem;
31
-
--height: ${utils.getRandom(blog.balloons.size[1])}rem;`}
30
+
style={`--width: ${utils.getRandom(blog.balloons.size[0])}px;
31
+
--height: ${utils.getRandom(blog.balloons.size[1])}px;`}
32
32
tabindex="-1"
33
33
data-min-time={blog.balloons.time[0]}
34
34
data-max-time={blog.balloons.time[1]}
···
41
41
42
42
<script>
43
43
const balloons = document.querySelectorAll(".balloon");
44
-
console.log(balloons);
45
44
balloons.forEach((el) => {
46
45
if (!(el instanceof HTMLElement)) return;
47
46
···
53
52
const postParent = el.parentElement?.parentElement;
54
53
if (!cableParent) throw new Error("No parent 1 level up!!!");
55
54
if (!postParent) throw new Error("No parent 2 levels up!!!");
56
-
console.log("clicked! popping", el, "with post", postParent);
57
55
58
56
el.blur();
59
57
···
63
61
{
64
62
duration: 100,
65
63
fill: "forwards",
66
-
}
64
+
},
67
65
).finished,
68
66
69
67
cableParent.animate(
···
77
75
{
78
76
duration: 500,
79
77
fill: "forwards",
80
-
}
78
+
},
81
79
),
82
80
83
81
postParent.animate(
84
82
[
85
83
{},
86
84
{
87
-
top: "calc(var(--x-offset-0) + 50rem)",
85
+
top: "calc(var(--x-offset-0) + 500px)",
88
86
},
89
87
],
90
88
{
91
89
duration: 1000,
92
90
easing: "ease-in-out",
93
-
}
91
+
},
94
92
).finished,
95
93
]).then(() => {
96
94
const duration = (mintime + Math.random() * (maxtime - mintime)) * 1000;
···
105
103
duration,
106
104
fill: "forwards",
107
105
// easing: "ease-in",
108
-
}
106
+
},
109
107
);
110
108
111
109
cableParent.animate(
···
122
120
{
123
121
duration,
124
122
fill: "forwards",
125
-
}
123
+
},
126
124
);
127
125
128
126
postParent.animate(
129
127
[
130
128
{
131
-
top: "calc(var(--x-offset-0) + 50rem)",
129
+
top: "calc(var(--x-offset-0) + 500px)",
132
130
},
133
131
{},
134
132
],
···
136
134
duration,
137
135
fill: "forwards",
138
136
easing: "ease-in",
139
-
}
137
+
},
140
138
);
141
139
});
142
140
});
···
233
231
.cable {
234
232
position: absolute;
235
233
236
-
width: 0.5rem;
234
+
width: 5px;
237
235
height: var(--length);
238
-
border-radius: 0.25rem;
236
+
border-radius: 2.5px;
239
237
background: black;
240
238
241
239
[data-time="night"] + * & {
242
240
background: #404040;
243
241
}
244
242
245
-
/* .5rem accounts for border (z-index doesn't work) */
246
243
z-index: -99;
247
244
top: calc(-1 * var(--length));
248
245
left: calc(
···
277
274
}
278
275
279
276
.cable-tie {
280
-
width: 1.75rem;
281
-
height: 0.5rem;
277
+
width: 17.5px;
278
+
height: 5px;
282
279
283
280
position: absolute;
284
-
bottom: -0.25rem;
281
+
bottom: -2.5px;
285
282
left: 50%;
286
283
translate: -50%;
287
284
z-index: 1;
288
285
289
-
border-radius: 0.25rem;
286
+
border-radius: 2.5px;
290
287
background-color: black;
291
288
292
289
[data-time="night"] + * & {
···
295
292
}
296
293
297
294
.tie {
298
-
width: 2rem;
299
-
height: 2rem;
295
+
width: 20px;
296
+
height: 20px;
300
297
background-color: var(--colour);
301
298
clip-path: polygon(50% 0, 0 100%, 100% 100%);
302
299
position: absolute;
303
-
bottom: -1rem;
300
+
bottom: -10px;
304
301
left: 50%;
305
302
translate: -50%;
306
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
17
if (!data.image) return;
18
18
const img = data.image.match(/.*(?=\.png)/gm);
19
19
if (img === null) return;
20
-
return await import(`../../posts/assets/${img[0]}.png`).then(
21
-
(x) => x.default
20
+
return await import(`../../content/posts/assets/${img[0]}.png`).then(
21
+
(x) => x.default,
22
22
);
23
23
})();
24
24
···
61
61
${offsets
62
62
.map(
63
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;`
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
66
)
67
67
.join("\n")}
68
68
···
73
73
74
74
/* config */
75
75
76
-
--width: ${blog.post.width}rem;
77
-
--y-gap: ${blog.post.yGap}rem;
76
+
--width: ${blog.post.width}px;
77
+
--y-gap: ${blog.post.yGap}px;
78
78
`}
79
79
>
80
80
{
···
172
172
173
173
section {
174
174
width: var(--width);
175
-
padding: 1rem;
175
+
padding: 10px;
176
176
margin-bottom: var(--y-gap);
177
177
178
178
position: relative;
···
185
185
content: "" / "";
186
186
display: block;
187
187
position: absolute;
188
-
top: -0.5rem;
189
-
left: -0.5rem;
188
+
top: -5px;
189
+
left: -5px;
190
190
z-index: -2;
191
191
192
-
width: calc(var(--width) + 1rem);
193
-
height: calc(100% + 1rem);
192
+
width: calc(var(--width) + 10px);
193
+
height: calc(100% + 10px);
194
194
195
195
background-color: white;
196
-
border: 0.5rem solid var(--colour, dodgerblue);
197
-
border-radius: 2.5rem;
196
+
border: 5px solid var(--colour, dodgerblue);
197
+
border-radius: 25px;
198
198
199
-
box-shadow: 0 0 7.5rem var(--box-shadow-colour, #00000080);
199
+
box-shadow: 0 0 75px var(--box-shadow-colour, #00000080);
200
200
}
201
201
202
202
/* default, overridden by reduced motion */
···
217
217
}
218
218
219
219
& > img {
220
-
border-radius: 1.5rem;
220
+
border-radius: 15px;
221
221
222
-
width: 30rem;
223
-
height: 20rem;
222
+
width: 300px;
223
+
height: 200px;
224
224
object-fit: cover;
225
225
}
226
226
}
+11
-7
src/components/blog/background/Cloud.astro
+11
-7
src/components/blog/background/Cloud.astro
···
36
36
37
37
const vectorOffset = (
38
38
v: [number, number],
39
-
o: [number, number]
39
+
o: [number, number],
40
40
): [number, number] => {
41
41
return [o[0] - v[0], o[1] - v[1]];
42
42
};
···
89
89
];
90
90
const newDistance = Math.sqrt(
91
91
(newCenter[0] - p.origin[0]) ** 2 +
92
-
(newCenter[1] - p.origin[1]) ** 2
92
+
(newCenter[1] - p.origin[1]) ** 2,
93
93
);
94
94
return {
95
95
origin: vectorOffset(vector(ang, c), p.origin),
···
120
120
prev: 0,
121
121
output: [] as any[],
122
122
complete: false,
123
-
}
123
+
},
124
124
).output
125
125
}
126
126
<circle cx={r} cy={r} r={r}></circle>
···
133
133
y1="0"
134
134
y2="1"
135
135
>
136
-
<stop offset="0%" stop-color={blog.palette.clouds}></stop>
136
+
<stop offset="0%" stop-color={blog.palette.environment.clouds}></stop>
137
137
<stop
138
138
offset={`${blog.background.clouds.gradientStops[0]}%`}
139
-
stop-color={blog.palette.clouds}></stop>
139
+
stop-color={blog.palette.environment.clouds}></stop>
140
140
<stop
141
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>
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>
144
148
</linearGradient>
145
149
</defs>
146
150
+3
-3
src/components/blog/background/Clouds.astro
+3
-3
src/components/blog/background/Clouds.astro
···
30
30
...prev.output,
31
31
<Cloud
32
32
style={`--parallax-speed: ${blog.background.parallax.clouds};
33
-
width: ${width}rem;
34
-
height: ${height}rem;
35
-
top: ${y}rem;
33
+
width: ${width}px;
34
+
height: ${height}px;
35
+
top: ${y}px;
36
36
left: calc(${x} * 200lvw - 100lvw);
37
37
position: absolute;`}
38
38
id={"cloud-" + i}
+10
-9
src/components/blog/background/Moon.astro
+10
-9
src/components/blog/background/Moon.astro
···
8
8
9
9
<style>
10
10
svg {
11
-
width: 20rem;
12
-
height: 20rem;
13
-
font-size: 20rem;
11
+
width: 200px;
12
+
height: 200px;
13
+
font-size: 200px;
14
14
15
15
position: absolute;
16
-
top: 30rem;
17
-
right: 1rem;
16
+
top: 300px;
17
+
right: 10px;
18
18
}
19
19
</style>
20
20
···
32
32
</defs>
33
33
34
34
<!-- base -->
35
-
<circle fill={blog.palette.moon} cx="100" cy="100" r="100"></circle>
35
+
<circle fill={blog.palette.environment.moon} cx="100" cy="100" r="100"
36
+
></circle>
36
37
<!-- half shadow -->
37
38
<circle
38
-
fill={blog.palette.sky.night}
39
+
fill={blog.palette.environment.sky.night}
39
40
cx="100"
40
41
cy="100"
41
42
r="100"
···
43
44
<!-- rotation shadow bulge thing -->
44
45
<ellipse
45
46
fill={phase < 0.25 || phase > 0.75
46
-
? blog.palette.moon
47
-
: blog.palette.sky.night}
47
+
? blog.palette.environment.moon
48
+
: blog.palette.environment.sky.night}
48
49
cx="100"
49
50
cy="100"
50
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
39
const prongs = Math.round(
40
40
blog.background.stars.prongs[0] +
41
41
Math.random() *
42
-
(blog.background.stars.prongs[1] - blog.background.stars.prongs[0])
42
+
(blog.background.stars.prongs[1] - blog.background.stars.prongs[0]),
43
43
);
44
44
45
45
return (
46
46
<svg
47
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;
48
+
--size: ${blog.background.stars.size[0] + sizeSeed * (blog.background.stars.size[1] - blog.background.stars.size[0])}px;
49
49
--x: ${Math.random()};
50
50
--y: ${Math.random()};
51
51
--rotate-speed: ${blog.background.stars.rotateSpeed[0] + Math.random() * (blog.background.stars.rotateSpeed[1] - blog.background.stars.rotateSpeed[0])}s;
···
57
57
>
58
58
{new Array(prongs).fill(0).map((_, i) => (
59
59
<polygon
60
-
fill={blog.palette.stars}
60
+
fill={blog.palette.environment.stars}
61
61
points="50 0, 75 50, 25 50"
62
62
transform={`rotate(${(i / prongs) * 360})`}
63
63
transform-origin="center"
+4
-4
src/components/blog/background/Sun.astro
+4
-4
src/components/blog/background/Sun.astro
···
13
13
svg {
14
14
position: absolute;
15
15
border-radius: 100%;
16
-
top: 15rem;
17
-
left: calc(100lvw * var(--sun-progress-percent) - 7.5rem);
16
+
top: 150px;
17
+
left: calc(100lvw * var(--sun-progress-percent) - 75px);
18
18
z-index: -1;
19
19
20
20
animation:
···
33
33
--sun-progress-percent: ${percent}`}
34
34
data-parallax
35
35
>
36
-
<circle fill={blog.palette.sun} cx="50" cy="50" r="35"></circle>
36
+
<circle fill={blog.palette.environment.sun} cx="50" cy="50" r="35"></circle>
37
37
38
38
{
39
39
new Array(prongs)
40
40
.fill(0)
41
41
.map((_, i) => (
42
42
<polygon
43
-
fill={blog.palette.sun}
43
+
fill={blog.palette.environment.sun}
44
44
points="50 0, 55 10, 45 10"
45
45
transform={`rotate(${(i / prongs) * 360})`}
46
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
1
export const blog = {
2
2
// overrideHour: 0,
3
3
post: {
4
-
width: 30,
5
-
xPadding: 2,
6
-
yLeeway: 5,
7
-
yGap: 20,
8
-
topYGap: 35,
4
+
width: 300,
5
+
xPadding: 20,
6
+
yLeeway: 50,
7
+
yGap: 200,
8
+
topYGap: 350,
9
9
drift: [0.1, 1],
10
10
timing: [10, 20],
11
11
},
···
19
19
20
20
clouds: {
21
21
count: 8,
22
-
width: [40, 80],
23
-
height: [15, 30],
24
-
yGap: [15, 25],
22
+
width: [400, 800],
23
+
height: [150, 300],
24
+
yGap: [150, 250],
25
25
26
26
bumpRadius: [20, 60],
27
27
gradientStops: [35, 80],
···
29
29
30
30
stars: {
31
31
count: 40,
32
-
size: [2, 5],
32
+
size: [20, 50],
33
33
prongs: [4, 8],
34
34
rotateSpeed: [20, 40],
35
35
},
···
40
40
},
41
41
balloons: {
42
42
numBalloons: [1, 3],
43
-
length: [5, 15],
44
-
offset: [-2.5, 2.5],
43
+
length: [50, 150],
44
+
offset: [-25, 25],
45
45
rotation: [-10, 10],
46
46
timing: [30, 45],
47
47
size: [
48
-
[5, 10],
49
-
[10, 20],
48
+
[50, 100],
49
+
[100, 200],
50
50
],
51
51
opacity: [0.6, 0.9],
52
52
time: [2, 5],
53
53
},
54
54
palette: {
55
-
sky: {
56
-
// blue
57
-
day: "#1E90FF",
58
-
// black
59
-
night: "#39375B"
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
+
],
60
111
},
61
-
// yellow
62
-
sun: "#FFEC51",
63
-
// whites
64
-
moon: "#E5D4ED",
65
-
clouds: "#E5D4ED",
66
-
stars: "#ffffff",
67
-
}
112
+
},
68
113
} as const;
69
114
70
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
1
---
2
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";
3
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
+
4
18
const { id } = Astro.params;
5
-
const r404 = Astro.redirect("/404");
19
+
if (!id) return Astro.redirect("/404");
6
20
7
-
if (!id) return r404;
8
21
const post = await getEntry("blog", id);
9
-
if (!post) return r404;
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
+
})();
10
36
---
11
37
12
-
<Base title={post.data.title}>
13
-
<h1>{post.data.title}</h1>
14
-
<p>{JSON.stringify(post)}</p>
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>
15
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
2
import Base from "@/Base.astro";
3
3
import Post from "@/components/blog/Post.astro";
4
4
import Background from "@/components/blog/Background.astro";
5
-
import Nav from "@/components/generic/Nav.astro";
5
+
import Nav from "@/components/navigation/Nav.astro";
6
6
7
7
import Rss from "@/assets/rss.svg";
8
8
···
10
10
import { blog } from "@/config";
11
11
12
12
const posts = await getCollection("blog").then((x) =>
13
-
x.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
13
+
x.sort((a, b) => b.data.date.getTime() - a.data.date.getTime()),
14
14
);
15
-
const nav = await getCollection("nav").then((x) => x.map((x) => x.data));
16
15
---
17
16
18
17
<style>
···
22
21
height: 2em;
23
22
aspect-ratio: 1;
24
23
padding: 0.2em;
25
-
border-radius: 0.5rem;
24
+
border-radius: 5px;
26
25
27
26
& svg {
28
27
width: 1.6em;
···
31
30
}
32
31
33
32
heading {
34
-
font-size: 1.6rem;
35
33
margin-bottom: var(--y-gap);
36
34
color: white;
37
35
···
44
42
justify-content: space-between;
45
43
46
44
& a {
47
-
margin: 0.5rem 1rem;
45
+
margin: 5px 10px;
48
46
}
49
47
}
50
48
51
49
.top-offset {
52
50
height: var(--top-gap);
53
51
}
52
+
53
+
:global(#nav-menu) {
54
+
background-color: black;
55
+
padding: 10px;
56
+
border-radius: 0 0 50% 0;
57
+
}
54
58
</style>
55
59
56
60
<Base title="Blog">
61
+
<Nav />
57
62
<Background />
58
63
<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>
64
+
<div class="top-offset" style={`--top-gap: ${blog.post.topYGap}px;`}></div>
68
65
69
66
{
70
67
posts.map((x, i) => (
+12
-51
src/pages/index.astro
+12
-51
src/pages/index.astro
···
1
1
---
2
-
// import Map from "@/components/map.astro"
3
2
import Base from "@/Base.astro";
4
-
import Map from "@/components/index/Map.astro";
3
+
import Nav from "@/components/navigation/Nav.astro";
5
4
---
6
5
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
-
/>
6
+
<Base>
7
+
<Nav />
56
8
</Base>
9
+
10
+
<style>
11
+
body {
12
+
width: 100vw;
13
+
height: 100vh;
14
+
background-color: #011627;
15
+
color: #f8f8f2;
16
+
}
17
+
</style>
-1
src/posts
-1
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>"