+3
-15
astro.config.mjs
+3
-15
astro.config.mjs
···
1
1
// @ts-check
2
2
import { defineConfig } from "astro/config";
3
+
3
4
import mdx from "@astrojs/mdx";
5
+
4
6
import sitemap from "@astrojs/sitemap";
5
-
6
-
import { rehypeAccessibleEmojis } from "rehype-accessible-emojis";
7
-
import rehypeCustomHtml from "./rehype-custom-html";
8
7
9
8
// https://astro.build/config
10
9
export default defineConfig({
11
10
integrations: [mdx(), sitemap()],
12
11
13
12
output: "server",
14
-
site: "https://vielle.dev",
15
13
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
-
},
14
+
site: "https://vielle.dev",
27
15
});
+6
-12
package.json
+6
-12
package.json
···
12
12
},
13
13
"dependencies": {
14
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",
15
+
"@astrojs/mdx": "^4.2.6",
16
+
"@astrojs/rss": "^4.0.11",
17
+
"@astrojs/sitemap": "^3.4.0",
18
+
"astro": "5.7.13",
19
19
"lunarphase-js": "^2.0.3",
20
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"
21
+
"typescript": "^5.8.3"
25
22
},
26
23
"devDependencies": {
27
-
"@types/hast": "^3.0.4",
28
24
"prettier": "3.5.3",
29
-
"prettier-plugin-astro": "0.14.1",
30
-
"pretty-quick": "^4.1.1",
31
-
"simple-git-hooks": "^2.13.0"
25
+
"prettier-plugin-astro": "0.14.1"
32
26
}
33
27
}
+48
-258
pnpm-lock.yaml
+48
-258
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.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))
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
16
"@astrojs/rss":
17
-
specifier: ^4.0.12
18
-
version: 4.0.12
17
+
specifier: ^4.0.11
18
+
version: 4.0.11
19
19
"@astrojs/sitemap":
20
-
specifier: ^3.4.1
21
-
version: 3.4.1
20
+
specifier: ^3.4.0
21
+
version: 3.4.0
22
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)
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
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
37
31
typescript:
38
32
specifier: ^5.8.3
39
33
version: 5.8.3
40
-
unified:
41
-
specifier: ^11.0.5
42
-
version: 11.0.5
43
34
devDependencies:
44
-
"@types/hast":
45
-
specifier: ^3.0.4
46
-
version: 3.0.4
47
35
prettier:
48
36
specifier: 3.5.3
49
37
version: 3.5.3
50
38
prettier-plugin-astro:
51
39
specifier: 0.14.1
52
40
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
41
60
42
packages:
61
43
"@astrojs/check@0.9.4":
···
73
55
integrity: sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA==,
74
56
}
75
57
76
-
"@astrojs/compiler@2.12.2":
77
-
resolution:
78
-
{
79
-
integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==,
80
-
}
81
-
82
58
"@astrojs/internal-helpers@0.6.1":
83
59
resolution:
84
60
{
···
100
76
prettier-plugin-astro:
101
77
optional: true
102
78
103
-
"@astrojs/markdown-remark@6.3.2":
79
+
"@astrojs/markdown-remark@6.3.1":
104
80
resolution:
105
81
{
106
-
integrity: sha512-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q==,
82
+
integrity: sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg==,
107
83
}
108
84
109
-
"@astrojs/mdx@4.3.0":
85
+
"@astrojs/mdx@4.2.6":
110
86
resolution:
111
87
{
112
-
integrity: sha512-OGX2KvPeBzjSSKhkCqrUoDMyzFcjKt5nTE5SFw3RdoLf0nrhyCXBQcCyclzWy1+P+XpOamn+p+hm1EhpCRyPxw==,
88
+
integrity: sha512-0i/GmOm6d0qq1/SCfcUgY/IjDc/bS0i42u7h85TkPFBmlFOcBZfkYhR5iyz6hZLwidvJOEq5yGfzt9B1Azku4w==,
113
89
}
114
-
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
90
+
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
115
91
peerDependencies:
116
92
astro: ^5.0.0
117
93
118
-
"@astrojs/prism@3.3.0":
94
+
"@astrojs/prism@3.2.0":
119
95
resolution:
120
96
{
121
-
integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==,
97
+
integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==,
122
98
}
123
-
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
99
+
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
124
100
125
-
"@astrojs/rss@4.0.12":
101
+
"@astrojs/rss@4.0.11":
126
102
resolution:
127
103
{
128
-
integrity: sha512-O5yyxHuDVb6DQ6VLOrbUVFSm+NpObulPxjs6XT9q3tC+RoKbN4HXMZLpv0LvXd1qdAjzVgJ1NFD+zKHJNDXikw==,
104
+
integrity: sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==,
129
105
}
130
106
131
-
"@astrojs/sitemap@3.4.1":
107
+
"@astrojs/sitemap@3.4.0":
132
108
resolution:
133
109
{
134
-
integrity: sha512-VjZvr1e4FH6NHyyHXOiQgLiw94LnCVY4v06wN/D0gZKchTMkg71GrAHJz81/huafcmavtLkIv26HnpfDq6/h/Q==,
110
+
integrity: sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ==,
135
111
}
136
112
137
-
"@astrojs/telemetry@3.3.0":
113
+
"@astrojs/telemetry@3.2.1":
138
114
resolution:
139
115
{
140
-
integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==,
116
+
integrity: sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg==,
141
117
}
142
-
engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 }
118
+
engines: { node: ^18.17.1 || ^20.3.0 || >=22.0.0 }
143
119
144
120
"@astrojs/yaml2ts@0.2.2":
145
121
resolution:
···
948
924
integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==,
949
925
}
950
926
951
-
"@types/ungap__structured-clone@1.2.0":
952
-
resolution:
953
-
{
954
-
integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==,
955
-
}
956
-
957
927
"@types/unist@2.0.11":
958
928
resolution:
959
929
{
···
1117
1087
}
1118
1088
hasBin: true
1119
1089
1120
-
astro@5.11.0:
1090
+
astro@5.7.13:
1121
1091
resolution:
1122
1092
{
1123
-
integrity: sha512-MEICntERthUxJPSSDsDiZuwiCMrsaYy3fnDhp4c6ScUfldCB8RBnB/myYdpTFXpwYBy6SgVsHQ1H4MuuA7ro/Q==,
1093
+
integrity: sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w==,
1124
1094
}
1125
1095
engines:
1126
-
{ node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" }
1096
+
{ node: ^18.17.1 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" }
1127
1097
hasBin: true
1128
1098
1129
1099
axobject-query@4.1.0:
···
1587
1557
integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==,
1588
1558
}
1589
1559
1590
-
fast-xml-parser@5.2.3:
1560
+
fast-xml-parser@4.5.3:
1591
1561
resolution:
1592
1562
{
1593
-
integrity: sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==,
1563
+
integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==,
1594
1564
}
1595
1565
hasBin: true
1596
1566
···
1618
1588
}
1619
1589
engines: { node: ">=8" }
1620
1590
1621
-
find-up@5.0.0:
1622
-
resolution:
1623
-
{
1624
-
integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==,
1625
-
}
1626
-
engines: { node: ">=10" }
1627
-
1628
1591
flattie@1.1.1:
1629
1592
resolution:
1630
1593
{
···
1651
1614
}
1652
1615
engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
1653
1616
os: [darwin]
1654
-
1655
-
gemoji@4.2.1:
1656
-
resolution:
1657
-
{
1658
-
integrity: sha512-V9lUpRSn+KQGavZx8Pk+6mxG3kaz21ae2kTCXuT36KaRPNgYU8eHtj/RcUCNFVvmwppsYYz3nnNS9lmcP5kTsg==,
1659
-
}
1660
1617
1661
1618
get-caller-file@2.0.5:
1662
1619
resolution:
···
1703
1660
integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==,
1704
1661
}
1705
1662
1706
-
hast-util-is-element@1.1.0:
1707
-
resolution:
1708
-
{
1709
-
integrity: sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==,
1710
-
}
1711
-
1712
1663
hast-util-is-element@3.0.0:
1713
1664
resolution:
1714
1665
{
···
1786
1737
{
1787
1738
integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==,
1788
1739
}
1789
-
1790
-
ignore@7.0.5:
1791
-
resolution:
1792
-
{
1793
-
integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==,
1794
-
}
1795
-
engines: { node: ">= 4" }
1796
1740
1797
1741
import-meta-resolve@4.1.0:
1798
1742
resolution:
···
1945
1889
integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==,
1946
1890
}
1947
1891
1948
-
locate-path@6.0.0:
1949
-
resolution:
1950
-
{
1951
-
integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==,
1952
-
}
1953
-
engines: { node: ">=10" }
1954
-
1955
1892
lodash@4.17.21:
1956
1893
resolution:
1957
1894
{
···
2108
2045
resolution:
2109
2046
{
2110
2047
integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==,
2111
-
}
2112
-
2113
-
mdast-util-toc@7.1.0:
2114
-
resolution:
2115
-
{
2116
-
integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==,
2117
2048
}
2118
2049
2119
2050
mdn-data@2.12.2:
···
2352
2283
}
2353
2284
engines: { node: ">=8.6" }
2354
2285
2355
-
mri@1.2.0:
2356
-
resolution:
2357
-
{
2358
-
integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==,
2359
-
}
2360
-
engines: { node: ">=4" }
2361
-
2362
2286
mrmime@2.0.1:
2363
2287
resolution:
2364
2288
{
···
2454
2378
integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==,
2455
2379
}
2456
2380
2457
-
p-limit@3.1.0:
2458
-
resolution:
2459
-
{
2460
-
integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==,
2461
-
}
2462
-
engines: { node: ">=10" }
2463
-
2464
2381
p-limit@6.2.0:
2465
2382
resolution:
2466
2383
{
2467
2384
integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==,
2468
2385
}
2469
2386
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
2387
2478
2388
p-queue@8.1.0:
2479
2389
resolution:
···
2524
2434
{
2525
2435
integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==,
2526
2436
}
2527
-
2528
-
path-exists@4.0.0:
2529
-
resolution:
2530
-
{
2531
-
integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==,
2532
-
}
2533
-
engines: { node: ">=8" }
2534
2437
2535
2438
picocolors@1.1.1:
2536
2439
resolution:
···
2582
2485
engines: { node: ">=14" }
2583
2486
hasBin: true
2584
2487
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
2488
prismjs@1.30.0:
2596
2489
resolution:
2597
2490
{
···
2686
2579
integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==,
2687
2580
}
2688
2581
2689
-
rehype-accessible-emojis@0.3.2:
2690
-
resolution:
2691
-
{
2692
-
integrity: sha512-kChZo+EZsuFQYHUPu6kOZFjDrG7UtQdGxkrCvHBVo9ariKPL6S68QdPVxLxwcAtZSRZIXZhDuTJHgIM8KW24Qw==,
2693
-
}
2694
-
2695
2582
rehype-parse@9.0.1:
2696
2583
resolution:
2697
2584
{
···
2759
2646
integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==,
2760
2647
}
2761
2648
2762
-
remark-toc@9.0.0:
2763
-
resolution:
2764
-
{
2765
-
integrity: sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA==,
2766
-
}
2767
-
2768
2649
request-light@0.5.8:
2769
2650
resolution:
2770
2651
{
···
2881
2762
integrity: sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==,
2882
2763
}
2883
2764
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
2765
simple-swizzle@0.2.2:
2892
2766
resolution:
2893
2767
{
···
2975
2849
}
2976
2850
engines: { node: ">=12" }
2977
2851
2978
-
strnum@2.1.1:
2852
+
strnum@1.1.2:
2979
2853
resolution:
2980
2854
{
2981
-
integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==,
2855
+
integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==,
2982
2856
}
2983
2857
2984
2858
style-to-js@1.1.16:
···
3147
3021
resolution:
3148
3022
{
3149
3023
integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==,
3150
-
}
3151
-
3152
-
unist-util-flatmap@1.0.0:
3153
-
resolution:
3154
-
{
3155
-
integrity: sha512-IG32jcKJlhARCYT2LsYPJWdoXYkzz3ESAdl1aa2hn9Auh+cgUmU6wgkII4yCc/1GgeWibRdELdCZh/p3QKQ1dQ==,
3156
3024
}
3157
3025
3158
3026
unist-util-is@6.0.0:
···
3607
3475
}
3608
3476
engines: { node: ">=12" }
3609
3477
3610
-
yocto-queue@0.1.0:
3611
-
resolution:
3612
-
{
3613
-
integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==,
3614
-
}
3615
-
engines: { node: ">=10" }
3616
-
3617
3478
yocto-queue@1.2.1:
3618
3479
resolution:
3619
3480
{
···
3678
3539
3679
3540
"@astrojs/compiler@2.12.0": {}
3680
3541
3681
-
"@astrojs/compiler@2.12.2": {}
3682
-
3683
3542
"@astrojs/internal-helpers@0.6.1": {}
3684
3543
3685
3544
"@astrojs/language-server@2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)":
···
3708
3567
transitivePeerDependencies:
3709
3568
- typescript
3710
3569
3711
-
"@astrojs/markdown-remark@6.3.2":
3570
+
"@astrojs/markdown-remark@6.3.1":
3712
3571
dependencies:
3713
3572
"@astrojs/internal-helpers": 0.6.1
3714
-
"@astrojs/prism": 3.3.0
3573
+
"@astrojs/prism": 3.2.0
3715
3574
github-slugger: 2.0.0
3716
3575
hast-util-from-html: 2.0.3
3717
3576
hast-util-to-text: 4.0.2
···
3734
3593
transitivePeerDependencies:
3735
3594
- supports-color
3736
3595
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))":
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))":
3738
3597
dependencies:
3739
-
"@astrojs/markdown-remark": 6.3.2
3598
+
"@astrojs/markdown-remark": 6.3.1
3740
3599
"@mdx-js/mdx": 3.1.0(acorn@8.14.1)
3741
3600
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)
3601
+
astro: 5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0)
3743
3602
es-module-lexer: 1.7.0
3744
3603
estree-util-visit: 2.0.0
3745
3604
hast-util-to-html: 9.0.5
···
3753
3612
transitivePeerDependencies:
3754
3613
- supports-color
3755
3614
3756
-
"@astrojs/prism@3.3.0":
3615
+
"@astrojs/prism@3.2.0":
3757
3616
dependencies:
3758
3617
prismjs: 1.30.0
3759
3618
3760
-
"@astrojs/rss@4.0.12":
3619
+
"@astrojs/rss@4.0.11":
3761
3620
dependencies:
3762
-
fast-xml-parser: 5.2.3
3621
+
fast-xml-parser: 4.5.3
3763
3622
kleur: 4.1.5
3764
3623
3765
-
"@astrojs/sitemap@3.4.1":
3624
+
"@astrojs/sitemap@3.4.0":
3766
3625
dependencies:
3767
3626
sitemap: 8.0.0
3768
3627
stream-replace-string: 2.0.0
3769
3628
zod: 3.25.7
3770
3629
3771
-
"@astrojs/telemetry@3.3.0":
3630
+
"@astrojs/telemetry@3.2.1":
3772
3631
dependencies:
3773
3632
ci-info: 4.2.0
3774
3633
debug: 4.4.1
···
4172
4031
4173
4032
"@types/sax@1.2.7":
4174
4033
dependencies:
4175
-
"@types/node": 22.15.20
4176
-
4177
-
"@types/ungap__structured-clone@1.2.0": {}
4034
+
"@types/node": 17.0.45
4178
4035
4179
4036
"@types/unist@2.0.11": {}
4180
4037
···
4274
4131
4275
4132
astring@1.9.0: {}
4276
4133
4277
-
astro@5.11.0(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0):
4134
+
astro@5.7.13(@types/node@22.15.20)(rollup@4.41.0)(typescript@5.8.3)(yaml@2.8.0):
4278
4135
dependencies:
4279
-
"@astrojs/compiler": 2.12.2
4136
+
"@astrojs/compiler": 2.12.0
4280
4137
"@astrojs/internal-helpers": 0.6.1
4281
-
"@astrojs/markdown-remark": 6.3.2
4282
-
"@astrojs/telemetry": 3.3.0
4138
+
"@astrojs/markdown-remark": 6.3.1
4139
+
"@astrojs/telemetry": 3.2.1
4283
4140
"@capsizecss/unpack": 2.4.0
4284
4141
"@oslojs/encoding": 1.1.0
4285
4142
"@rollup/pluginutils": 5.1.4(rollup@4.41.0)
···
4306
4163
github-slugger: 2.0.0
4307
4164
html-escaper: 3.0.3
4308
4165
http-cache-semantics: 4.2.0
4309
-
import-meta-resolve: 4.1.0
4310
4166
js-yaml: 4.1.0
4311
4167
kleur: 4.1.5
4312
4168
magic-string: 0.30.17
···
4627
4483
4628
4484
fast-uri@3.0.6: {}
4629
4485
4630
-
fast-xml-parser@5.2.3:
4486
+
fast-xml-parser@4.5.3:
4631
4487
dependencies:
4632
-
strnum: 2.1.1
4488
+
strnum: 1.1.2
4633
4489
4634
4490
fastq@1.19.1:
4635
4491
dependencies:
···
4643
4499
dependencies:
4644
4500
to-regex-range: 5.0.1
4645
4501
4646
-
find-up@5.0.0:
4647
-
dependencies:
4648
-
locate-path: 6.0.0
4649
-
path-exists: 4.0.0
4650
-
4651
4502
flattie@1.1.1: {}
4652
4503
4653
4504
fontace@0.3.0:
···
4669
4520
4670
4521
fsevents@2.3.3:
4671
4522
optional: true
4672
-
4673
-
gemoji@4.2.1: {}
4674
4523
4675
4524
get-caller-file@2.0.5: {}
4676
4525
···
4713
4562
vfile: 6.0.3
4714
4563
vfile-location: 5.0.3
4715
4564
web-namespaces: 2.0.1
4716
-
4717
-
hast-util-is-element@1.1.0: {}
4718
4565
4719
4566
hast-util-is-element@3.0.0:
4720
4567
dependencies:
···
4829
4676
html-void-elements@3.0.0: {}
4830
4677
4831
4678
http-cache-semantics@4.2.0: {}
4832
-
4833
-
ignore@7.0.5: {}
4834
4679
4835
4680
import-meta-resolve@4.1.0: {}
4836
4681
···
4892
4737
dependencies:
4893
4738
uc.micro: 2.1.0
4894
4739
4895
-
locate-path@6.0.0:
4896
-
dependencies:
4897
-
p-locate: 5.0.0
4898
-
4899
4740
lodash@4.17.21: {}
4900
4741
4901
4742
longest-streak@3.1.0: {}
···
5095
4936
mdast-util-to-string@4.0.0:
5096
4937
dependencies:
5097
4938
"@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
4939
5109
4940
mdn-data@2.12.2: {}
5110
4941
···
5381
5212
braces: 3.0.3
5382
5213
picomatch: 2.3.1
5383
5214
5384
-
mri@1.2.0: {}
5385
-
5386
5215
mrmime@2.0.1: {}
5387
5216
5388
5217
ms@2.1.3: {}
···
5423
5252
regex: 6.0.1
5424
5253
regex-recursion: 6.0.2
5425
5254
5426
-
p-limit@3.1.0:
5427
-
dependencies:
5428
-
yocto-queue: 0.1.0
5429
-
5430
5255
p-limit@6.2.0:
5431
5256
dependencies:
5432
5257
yocto-queue: 1.2.1
5433
-
5434
-
p-locate@5.0.0:
5435
-
dependencies:
5436
-
p-limit: 3.1.0
5437
5258
5438
5259
p-queue@8.1.0:
5439
5260
dependencies:
···
5471
5292
5472
5293
path-browserify@1.0.1: {}
5473
5294
5474
-
path-exists@4.0.0: {}
5475
-
5476
5295
picocolors@1.1.1: {}
5477
5296
5478
5297
picomatch@2.3.1: {}
···
5496
5315
5497
5316
prettier@3.5.3: {}
5498
5317
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
5318
prismjs@1.30.0: {}
5511
5319
5512
5320
prompts@2.4.2:
···
5566
5374
dependencies:
5567
5375
regex-utilities: 2.3.0
5568
5376
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
5377
rehype-parse@9.0.1:
5577
5378
dependencies:
5578
5379
"@types/hast": 3.0.4
···
5654
5455
mdast-util-to-markdown: 2.1.2
5655
5456
unified: 11.0.5
5656
5457
5657
-
remark-toc@9.0.0:
5658
-
dependencies:
5659
-
"@types/mdast": 4.0.4
5660
-
mdast-util-toc: 7.1.0
5661
-
5662
5458
request-light@0.5.8: {}
5663
5459
5664
5460
request-light@0.7.0: {}
···
5774
5570
"@shikijs/vscode-textmate": 10.0.2
5775
5571
"@types/hast": 3.0.4
5776
5572
5777
-
simple-git-hooks@2.13.0: {}
5778
-
5779
5573
simple-swizzle@0.2.2:
5780
5574
dependencies:
5781
5575
is-arrayish: 0.3.2
···
5825
5619
dependencies:
5826
5620
ansi-regex: 6.1.0
5827
5621
5828
-
strnum@2.1.1: {}
5622
+
strnum@1.1.2: {}
5829
5623
5830
5624
style-to-js@1.1.16:
5831
5625
dependencies:
···
5914
5708
"@types/unist": 3.0.3
5915
5709
unist-util-is: 6.0.0
5916
5710
5917
-
unist-util-flatmap@1.0.0: {}
5918
-
5919
5711
unist-util-is@6.0.0:
5920
5712
dependencies:
5921
5713
"@types/unist": 3.0.3
···
6171
5963
string-width: 4.2.3
6172
5964
y18n: 5.0.8
6173
5965
yargs-parser: 21.1.1
6174
-
6175
-
yocto-queue@0.1.0: {}
6176
5966
6177
5967
yocto-queue@1.2.1: {}
6178
5968
-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
-

+7
-1
posts/test.mdx
+7
-1
posts/test.mdx
···
2
2
title: Test Post
3
3
---
4
4
5
+
import Balloon from "@components/blog/balloon.svelte";
6
+
5
7
whats this about dawg
6
8
7
-
(Vi a vis .MDX)
9
+
<div style="padding: 15rem;"></div>
10
+
11
+
<div style="position: absolute">
12
+
<Balloon client:load id={0} boundingWidth={300} boundingHeight={0} />
13
+
</div>
-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;
+8
-4
src/Base.astro
+8
-4
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 ? `${title} | vielle.dev` : "vielle.dev"}</title>
30
+
<title>{title} | vielle.dev</title>
31
31
<script>
32
32
// sets the timezone offset
33
-
document.cookie = `timezone=${new Date().toString()};path=/`;
33
+
document.cookie = `timezone=${new Date().toString()}`;
34
34
</script>
35
-
<!-- default styles -->
35
+
<!-- default styles (rem, *) -->
36
36
<style is:global>
37
37
@layer reset {
38
+
:root {
39
+
font-size: 62.5%;
40
+
}
38
41
body {
42
+
font-size: 1.6rem;
39
43
line-height: 1.5;
40
44
-webkit-font-smoothing: antialiased;
41
45
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>
+2
-1
src/assets/hamburger.svg
+2
-1
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=""
12
13
>
13
-
<title>Menu</title>
14
+
<title><!-- no alt text as used for buttons --></title>
14
15
<path d="M4 12h16" />
15
16
<path d="M4 18h16" />
16
17
<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.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}`}
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
74
aria-hidden="true"
75
75
>
76
76
{
+24
-21
src/components/blog/Balloon.astro
+24
-21
src/components/blog/Balloon.astro
···
17
17
18
18
<div
19
19
class="cable"
20
-
style={`--length: ${length}px;
20
+
style={`--length: ${length}rem;
21
21
--id: ${id};
22
22
--of: ${of};
23
-
--offset: ${offset}px;
23
+
--offset: ${offset}rem;
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])}px;
31
-
--height: ${utils.getRandom(blog.balloons.size[1])}px;`}
30
+
style={`--width: ${utils.getRandom(blog.balloons.size[0])}rem;
31
+
--height: ${utils.getRandom(blog.balloons.size[1])}rem;`}
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);
44
45
balloons.forEach((el) => {
45
46
if (!(el instanceof HTMLElement)) return;
46
47
···
52
53
const postParent = el.parentElement?.parentElement;
53
54
if (!cableParent) throw new Error("No parent 1 level up!!!");
54
55
if (!postParent) throw new Error("No parent 2 levels up!!!");
56
+
console.log("clicked! popping", el, "with post", postParent);
55
57
56
58
el.blur();
57
59
···
61
63
{
62
64
duration: 100,
63
65
fill: "forwards",
64
-
},
66
+
}
65
67
).finished,
66
68
67
69
cableParent.animate(
···
75
77
{
76
78
duration: 500,
77
79
fill: "forwards",
78
-
},
80
+
}
79
81
),
80
82
81
83
postParent.animate(
82
84
[
83
85
{},
84
86
{
85
-
top: "calc(var(--x-offset-0) + 500px)",
87
+
top: "calc(var(--x-offset-0) + 50rem)",
86
88
},
87
89
],
88
90
{
89
91
duration: 1000,
90
92
easing: "ease-in-out",
91
-
},
93
+
}
92
94
).finished,
93
95
]).then(() => {
94
96
const duration = (mintime + Math.random() * (maxtime - mintime)) * 1000;
···
103
105
duration,
104
106
fill: "forwards",
105
107
// easing: "ease-in",
106
-
},
108
+
}
107
109
);
108
110
109
111
cableParent.animate(
···
120
122
{
121
123
duration,
122
124
fill: "forwards",
123
-
},
125
+
}
124
126
);
125
127
126
128
postParent.animate(
127
129
[
128
130
{
129
-
top: "calc(var(--x-offset-0) + 500px)",
131
+
top: "calc(var(--x-offset-0) + 50rem)",
130
132
},
131
133
{},
132
134
],
···
134
136
duration,
135
137
fill: "forwards",
136
138
easing: "ease-in",
137
-
},
139
+
}
138
140
);
139
141
});
140
142
});
···
231
233
.cable {
232
234
position: absolute;
233
235
234
-
width: 5px;
236
+
width: 0.5rem;
235
237
height: var(--length);
236
-
border-radius: 2.5px;
238
+
border-radius: 0.25rem;
237
239
background: black;
238
240
239
241
[data-time="night"] + * & {
240
242
background: #404040;
241
243
}
242
244
245
+
/* .5rem accounts for border (z-index doesn't work) */
243
246
z-index: -99;
244
247
top: calc(-1 * var(--length));
245
248
left: calc(
···
274
277
}
275
278
276
279
.cable-tie {
277
-
width: 17.5px;
278
-
height: 5px;
280
+
width: 1.75rem;
281
+
height: 0.5rem;
279
282
280
283
position: absolute;
281
-
bottom: -2.5px;
284
+
bottom: -0.25rem;
282
285
left: 50%;
283
286
translate: -50%;
284
287
z-index: 1;
285
288
286
-
border-radius: 2.5px;
289
+
border-radius: 0.25rem;
287
290
background-color: black;
288
291
289
292
[data-time="night"] + * & {
···
292
295
}
293
296
294
297
.tie {
295
-
width: 20px;
296
-
height: 20px;
298
+
width: 2rem;
299
+
height: 2rem;
297
300
background-color: var(--colour);
298
301
clip-path: polygon(50% 0, 0 100%, 100% 100%);
299
302
position: absolute;
300
-
bottom: -10px;
303
+
bottom: -1rem;
301
304
left: 50%;
302
305
translate: -50%;
303
306
}
-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(`../../content/posts/assets/${img[0]}.png`).then(
21
-
(x) => x.default,
20
+
return await import(`../../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}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;`,
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
66
)
67
67
.join("\n")}
68
68
···
73
73
74
74
/* config */
75
75
76
-
--width: ${blog.post.width}px;
77
-
--y-gap: ${blog.post.yGap}px;
76
+
--width: ${blog.post.width}rem;
77
+
--y-gap: ${blog.post.yGap}rem;
78
78
`}
79
79
>
80
80
{
···
172
172
173
173
section {
174
174
width: var(--width);
175
-
padding: 10px;
175
+
padding: 1rem;
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: -5px;
189
-
left: -5px;
188
+
top: -0.5rem;
189
+
left: -0.5rem;
190
190
z-index: -2;
191
191
192
-
width: calc(var(--width) + 10px);
193
-
height: calc(100% + 10px);
192
+
width: calc(var(--width) + 1rem);
193
+
height: calc(100% + 1rem);
194
194
195
195
background-color: white;
196
-
border: 5px solid var(--colour, dodgerblue);
197
-
border-radius: 25px;
196
+
border: 0.5rem solid var(--colour, dodgerblue);
197
+
border-radius: 2.5rem;
198
198
199
-
box-shadow: 0 0 75px var(--box-shadow-colour, #00000080);
199
+
box-shadow: 0 0 7.5rem 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: 15px;
220
+
border-radius: 1.5rem;
221
221
222
-
width: 300px;
223
-
height: 200px;
222
+
width: 30rem;
223
+
height: 20rem;
224
224
object-fit: cover;
225
225
}
226
226
}
+7
-11
src/components/blog/background/Cloud.astro
+7
-11
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.environment.clouds}></stop>
136
+
<stop offset="0%" stop-color={blog.palette.clouds}></stop>
137
137
<stop
138
138
offset={`${blog.background.clouds.gradientStops[0]}%`}
139
-
stop-color={blog.palette.environment.clouds}></stop>
139
+
stop-color={blog.palette.clouds}></stop>
140
140
<stop
141
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>
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>
148
144
</linearGradient>
149
145
</defs>
150
146
+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}px;
34
-
height: ${height}px;
35
-
top: ${y}px;
33
+
width: ${width}rem;
34
+
height: ${height}rem;
35
+
top: ${y}rem;
36
36
left: calc(${x} * 200lvw - 100lvw);
37
37
position: absolute;`}
38
38
id={"cloud-" + i}
+9
-10
src/components/blog/background/Moon.astro
+9
-10
src/components/blog/background/Moon.astro
···
8
8
9
9
<style>
10
10
svg {
11
-
width: 200px;
12
-
height: 200px;
13
-
font-size: 200px;
11
+
width: 20rem;
12
+
height: 20rem;
13
+
font-size: 20rem;
14
14
15
15
position: absolute;
16
-
top: 300px;
17
-
right: 10px;
16
+
top: 30rem;
17
+
right: 1rem;
18
18
}
19
19
</style>
20
20
···
32
32
</defs>
33
33
34
34
<!-- base -->
35
-
<circle fill={blog.palette.environment.moon} cx="100" cy="100" r="100"
36
-
></circle>
35
+
<circle fill={blog.palette.moon} cx="100" cy="100" r="100"></circle>
37
36
<!-- half shadow -->
38
37
<circle
39
-
fill={blog.palette.environment.sky.night}
38
+
fill={blog.palette.sky.night}
40
39
cx="100"
41
40
cy="100"
42
41
r="100"
···
44
43
<!-- rotation shadow bulge thing -->
45
44
<ellipse
46
45
fill={phase < 0.25 || phase > 0.75
47
-
? blog.palette.environment.moon
48
-
: blog.palette.environment.sky.night}
46
+
? blog.palette.moon
47
+
: blog.palette.sky.night}
49
48
cx="100"
50
49
cy="100"
51
50
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])}px;
48
+
--size: ${blog.background.stars.size[0] + sizeSeed * (blog.background.stars.size[1] - blog.background.stars.size[0])}rem;
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.environment.stars}
60
+
fill={blog.palette.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: 150px;
17
-
left: calc(100lvw * var(--sun-progress-percent) - 75px);
16
+
top: 15rem;
17
+
left: calc(100lvw * var(--sun-progress-percent) - 7.5rem);
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.environment.sun} cx="50" cy="50" r="35"></circle>
36
+
<circle fill={blog.palette.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.environment.sun}
43
+
fill={blog.palette.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>
+25
-70
src/config.ts
+25
-70
src/config.ts
···
1
1
export const blog = {
2
2
// overrideHour: 0,
3
3
post: {
4
-
width: 300,
5
-
xPadding: 20,
6
-
yLeeway: 50,
7
-
yGap: 200,
8
-
topYGap: 350,
4
+
width: 30,
5
+
xPadding: 2,
6
+
yLeeway: 5,
7
+
yGap: 20,
8
+
topYGap: 35,
9
9
drift: [0.1, 1],
10
10
timing: [10, 20],
11
11
},
···
19
19
20
20
clouds: {
21
21
count: 8,
22
-
width: [400, 800],
23
-
height: [150, 300],
24
-
yGap: [150, 250],
22
+
width: [40, 80],
23
+
height: [15, 30],
24
+
yGap: [15, 25],
25
25
26
26
bumpRadius: [20, 60],
27
27
gradientStops: [35, 80],
···
29
29
30
30
stars: {
31
31
count: 40,
32
-
size: [20, 50],
32
+
size: [2, 5],
33
33
prongs: [4, 8],
34
34
rotateSpeed: [20, 40],
35
35
},
···
40
40
},
41
41
balloons: {
42
42
numBalloons: [1, 3],
43
-
length: [50, 150],
44
-
offset: [-25, 25],
43
+
length: [5, 15],
44
+
offset: [-2.5, 2.5],
45
45
rotation: [-10, 10],
46
46
timing: [30, 45],
47
47
size: [
48
-
[50, 100],
49
-
[100, 200],
48
+
[5, 10],
49
+
[10, 20],
50
50
],
51
51
opacity: [0.6, 0.9],
52
52
time: [2, 5],
53
53
},
54
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",
55
+
sky: {
56
+
// blue
57
+
day: "#1E90FF",
58
+
// black
59
+
night: "#39375B"
68
60
},
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
-
},
61
+
// yellow
62
+
sun: "#FFEC51",
63
+
// whites
64
+
moon: "#E5D4ED",
65
+
clouds: "#E5D4ED",
66
+
stars: "#ffffff",
67
+
}
113
68
} as const;
114
69
115
70
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 };
+6
-178
src/pages/blog/[id].astro
+6
-178
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";
8
3
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
4
const { id } = Astro.params;
19
-
if (!id) return Astro.redirect("/404");
5
+
const r404 = Astro.redirect("/404");
20
6
7
+
if (!id) return r404;
21
8
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
-
})();
9
+
if (!post) return r404;
36
10
---
37
11
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>
12
+
<Base title={post.data.title}>
13
+
<h1>{post.data.title}</h1>
14
+
<p>{JSON.stringify(post)}</p>
53
15
</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>
+15
-12
src/pages/blog/index.astro
+15
-12
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/navigation/Nav.astro";
5
+
import Nav from "@/components/generic/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));
15
16
---
16
17
17
18
<style>
···
21
22
height: 2em;
22
23
aspect-ratio: 1;
23
24
padding: 0.2em;
24
-
border-radius: 5px;
25
+
border-radius: 0.5rem;
25
26
26
27
& svg {
27
28
width: 1.6em;
···
30
31
}
31
32
32
33
heading {
34
+
font-size: 1.6rem;
33
35
margin-bottom: var(--y-gap);
34
36
color: white;
35
37
···
42
44
justify-content: space-between;
43
45
44
46
& a {
45
-
margin: 5px 10px;
47
+
margin: 0.5rem 1rem;
46
48
}
47
49
}
48
50
49
51
.top-offset {
50
52
height: var(--top-gap);
51
53
}
52
-
53
-
:global(#nav-menu) {
54
-
background-color: black;
55
-
padding: 10px;
56
-
border-radius: 0 0 50% 0;
57
-
}
58
54
</style>
59
55
60
56
<Base title="Blog">
61
-
<Nav />
62
57
<Background />
63
58
<main>
64
-
<div class="top-offset" style={`--top-gap: ${blog.post.topYGap}px;`}></div>
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>
65
68
66
69
{
67
70
posts.map((x, i) => (
+51
-12
src/pages/index.astro
+51
-12
src/pages/index.astro
···
1
1
---
2
+
// import Map from "@/components/map.astro"
2
3
import Base from "@/Base.astro";
3
-
import Nav from "@/components/navigation/Nav.astro";
4
+
import Map from "@/components/index/Map.astro";
4
5
---
5
6
6
-
<Base>
7
-
<Nav />
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
+
/>
8
56
</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>"