initial commit

Seto committed Nov 12, 2025 at 22:48 UTC 14234ff6296284f9cf9ffa06120622dc5c08550e
95 files changed +11203
.github/dependabot.yml new
+30
@@ -0,0 +1,30 @@
1 +version: 2
2 +updates:
3 + # Enable npm (pnpm) dependency updates
4 + - package-ecosystem: 'npm'
5 + directory: '/'
6 + schedule:
7 + # Check for updates every Monday at 09:00 (Asia/Shanghai)
8 + interval: 'weekly'
9 + day: 'monday'
10 + time: '09:00'
11 + timezone: 'Asia/Shanghai'
12 + # Limit the number of open PRs created by Dependabot
13 + open-pull-requests-limit: 10
14 + commit-message:
15 + # Use 'chore' as the commit message prefix
16 + prefix: 'chore'
17 + include: 'scope'
18 + # Labels to add to Dependabot PRs
19 + labels:
20 + - 'dependencies'
21 + - 'automated'
22 + ignore:
23 + # Ignore major version updates (breaking changes)
24 + - dependency-name: '*'
25 + update-types: ['version-update:semver-major']
26 + allow:
27 + # Allow updates for development dependencies
28 + - dependency-type: 'development'
29 + # Allow updates for direct dependencies
30 + - dependency-type: 'direct'
.github/workflows/ci.yml new
+56
@@ -0,0 +1,56 @@
1 +name: CI
2 +
3 +on:
4 + push:
5 + branches: [main, master]
6 + pull_request:
7 + branches: [main, master]
8 +
9 +jobs:
10 + # Validate dependencies and build
11 + validate:
12 + runs-on: ubuntu-latest
13 + steps:
14 + - name: Checkout code
15 + uses: actions/checkout@v4
16 +
17 + - name: Setup pnpm
18 + uses: pnpm/action-setup@v4
19 + with:
20 + version: latest
21 +
22 + - name: Setup Node.js
23 + uses: actions/setup-node@v4
24 + with:
25 + node-version: 'latest'
26 + cache: 'pnpm'
27 +
28 + - name: Install dependencies
29 + run: pnpm install --frozen-lockfile
30 +
31 + - name: Run linting
32 + run: pnpm lint
33 +
34 + - name: Build project
35 + run: pnpm build
36 +
37 + # Auto-merge Dependabot PRs
38 + auto-merge:
39 + if: |
40 + github.event_name == 'pull_request' &&
41 + github.actor == 'dependabot[bot]' &&
42 + contains(github.event.pull_request.labels.*.name, 'dependencies')
43 + needs: validate
44 + runs-on: ubuntu-latest
45 + permissions:
46 + contents: write
47 + pull-requests: write
48 + steps:
49 + - name: Checkout code
50 + uses: actions/checkout@v4
51 +
52 + - name: Enable auto-merge for Dependabot PRs
53 + run: |
54 + gh pr merge --auto --squash "${{ github.event.pull_request.number }}"
55 + env:
56 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
.gitignore new
+26
@@ -0,0 +1,26 @@
1 +# Build output
2 +dist/
3 +.output/
4 +
5 +# Generated types
6 +.astro/
7 +
8 +# Dependencies
9 +node_modules/
10 +
11 +# Logs
12 +npm-debug.log*
13 +yarn-debug.log*
14 +yarn-error.log*
15 +pnpm-debug.log*
16 +
17 +# Environment variables
18 +.env
19 +.env.production
20 +
21 +# macOS-specific files
22 +.DS_Store
23 +
24 +# IDE settings
25 +.idea/
26 +
.prettierignore new
+40
@@ -0,0 +1,40 @@
1 +# Build output
2 +dist/
3 +.output/
4 +
5 +# Dependencies
6 +node_modules/
7 +
8 +# Package manager files
9 +package-lock.json
10 +yarn.lock
11 +pnpm-lock.yaml
12 +
13 +# Log files
14 +*.log
15 +
16 +# Environment variables
17 +.env
18 +.env.*
19 +
20 +# Cache directories
21 +.cache/
22 +.astro/
23 +
24 +# Others
25 +.DS_Store
26 +coverage/
27 +
28 +# Media files
29 +*.png
30 +*.jpg
31 +*.jpeg
32 +*.gif
33 +*.svg
34 +*.ico
35 +*.webp
36 +*.mp4
37 +*.webm
38 +*.mp3
39 +*.wav
40 +*.pdf
\ No newline at end of file
.prettierrc new
+8
@@ -0,0 +1,8 @@
1 +{
2 + "plugins": ["prettier-plugin-astro"],
3 + "semi": false,
4 + "singleQuote": true,
5 + "trailingComma": "none",
6 + "printWidth": 100,
7 + "tabWidth": 2
8 +}
.smb/config.toml new
+11
@@ -0,0 +1,11 @@
1 +
2 +name = "superteamstockholmweb"
3 +description = "superteamstockholmweb"
4 +[project]
5 +id = 39
6 +name = "superteamstockholmweb"
7 +runner = 0
8 +repository = "superteamstockholmweb"
9 +description = "superteamstockholmweb"
10 +created_at = "2025-07-12T09:52:43.117655+00:00"
11 +updated_at = "2025-07-12T09:52:43.117655+00:00"
.vscode/extensions.json new
+4
@@ -0,0 +1,4 @@
1 +{
2 + "recommendations": ["astro-build.astro-vscode", "unifiedjs.vscode-mdx"],
3 + "unwantedRecommendations": []
4 +}
.vscode/launch.json new
+11
@@ -0,0 +1,11 @@
1 +{
2 + "version": "0.2.0",
3 + "configurations": [
4 + {
5 + "command": "./node_modules/.bin/astro dev",
6 + "name": "Development server",
7 + "request": "launch",
8 + "type": "node-terminal"
9 + }
10 + ]
11 +}
LICENSE new
+21
@@ -0,0 +1,21 @@
1 +MIT License
2 +
3 +Copyright (c) 2025 SuperTeam Stockholm
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
README.md new
+3
@@ -0,0 +1,3 @@
1 +# SuperTeam Stockholm
2 +
3 +Solana SuperTeam Stockholm chapter.
astro.config.ts new
+65
@@ -0,0 +1,65 @@
1 +import { defineConfig } from 'astro/config'
2 +import mdx from '@astrojs/mdx'
3 +import sitemap from '@astrojs/sitemap'
4 +import remarkMath from 'remark-math'
5 +import remarkDirective from 'remark-directive'
6 +import rehypeKatex from 'rehype-katex'
7 +import remarkEmbeddedMedia from './src/plugins/remark-embedded-media.mjs'
8 +import remarkReadingTime from './src/plugins/remark-reading-time.mjs'
9 +import rehypeCleanup from './src/plugins/rehype-cleanup.mjs'
10 +import rehypeImageProcessor from './src/plugins/rehype-image-processor.mjs'
11 +import rehypeCopyCode from './src/plugins/rehype-copy-code.mjs'
12 +import remarkTOC from './src/plugins/remark-toc.mjs'
13 +import { SITE } from './src/config'
14 +import path from 'path'
15 +
16 +import tailwindcss from '@tailwindcss/vite';
17 +
18 +export default defineConfig({
19 + site: SITE.website,
20 + devToolbar: {
21 + enabled: false
22 + },
23 + output: 'static',
24 + build: {
25 + inlineStylesheets: 'auto'
26 + },
27 + image: {
28 + service: {
29 + entrypoint: 'astro/assets/services/sharp'
30 + }
31 + },
32 + markdown: {
33 + shikiConfig: {
34 + theme: 'css-variables',
35 + wrap: false
36 + },
37 + remarkPlugins: [remarkMath, remarkDirective, remarkEmbeddedMedia, remarkReadingTime, remarkTOC],
38 + rehypePlugins: [rehypeKatex, rehypeCleanup, rehypeImageProcessor, rehypeCopyCode]
39 + },
40 + integrations: [mdx(), sitemap()],
41 + vite: {
42 + resolve: {
43 + alias: {
44 + '@': path.resolve('./src')
45 + }
46 + },
47 +
48 + build: {
49 + rollupOptions: {
50 + output: {
51 + manualChunks: {
52 + 'vendor-katex': ['katex'],
53 + 'vendor-utils': ['reading-time', 'mdast-util-to-string']
54 + }
55 + }
56 + }
57 + },
58 +
59 + optimizeDeps: {
60 + include: ['katex', 'reading-time']
61 + },
62 +
63 + plugins: [tailwindcss()]
64 + }
65 +})
\ No newline at end of file
eslint.config.js new
+41
@@ -0,0 +1,41 @@
1 +import eslint from '@eslint/js'
2 +import globals from 'globals'
3 +import tseslint from 'typescript-eslint'
4 +import prettier from 'eslint-config-prettier'
5 +import eslintPluginAstro from 'eslint-plugin-astro'
6 +
7 +export default [
8 + eslint.configs.recommended,
9 + ...tseslint.configs.recommended,
10 + ...eslintPluginAstro.configs.recommended,
11 + {
12 + languageOptions: {
13 + globals: {
14 + ...globals.browser,
15 + ...globals.node
16 + }
17 + }
18 + },
19 + {
20 + rules: {
21 + 'no-console': ['warn', { allow: ['warn', 'error'] }],
22 + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
23 + '@typescript-eslint/no-explicit-any': 'warn',
24 + 'astro/no-set-html-directive': 'off'
25 + }
26 + },
27 + prettier,
28 + {
29 + ignores: [
30 + 'dist/**',
31 + '.output/**',
32 + 'node_modules/**',
33 + '*.log',
34 + '.env*',
35 + '.cache/**',
36 + '.astro/**',
37 + '.DS_Store',
38 + 'coverage/**'
39 + ]
40 + }
41 +]
package.json new
+48
@@ -0,0 +1,48 @@
1 +{
2 + "name": "superteamstockholm-web",
3 + "type": "module",
4 + "version": "0.5.0",
5 + "license": "MIT",
6 + "scripts": {
7 + "dev": "astro dev",
8 + "build": "astro build",
9 + "preview": "astro preview",
10 + "astro": "astro",
11 + "lint": "eslint .",
12 + "lint:fix": "eslint . --fix",
13 + "format": "prettier --write .",
14 + "format:check": "prettier --check .",
15 + "new": "tsx scripts/new-post.ts",
16 + "update-theme": "tsx scripts/update-theme.ts",
17 + "start-superteamstockholmweb": "astro start -p 5002"
18 + },
19 + "dependencies": {
20 + "@astrojs/mdx": "^4.3.10",
21 + "@astrojs/sitemap": "^3.6.0",
22 + "@tailwindcss/vite": "^4.1.13",
23 + "astro": "^5.15.5",
24 + "katex": "^0.16.22",
25 + "mdast-util-to-string": "^4.0.0",
26 + "reading-time": "^1.5.0",
27 + "rehype-katex": "^7.0.1",
28 + "remark-directive": "^4.0.0",
29 + "remark-math": "^6.0.0",
30 + "sharp": "^0.34.3",
31 + "tailwindcss": "^4.1.13",
32 + "unist-util-visit": "^5.0.0"
33 + },
34 + "devDependencies": {
35 + "@eslint/js": "^9.30.1",
36 + "@typescript-eslint/eslint-plugin": "^8.35.1",
37 + "@typescript-eslint/parser": "^8.36.0",
38 + "eslint": "^9.30.1",
39 + "eslint-config-prettier": "^10.1.5",
40 + "eslint-plugin-astro": "^1.3.1",
41 + "globals": "^16.3.0",
42 + "prettier": "^3.6.2",
43 + "prettier-plugin-astro": "^0.14.1",
44 + "tsx": "^4.19.2",
45 + "typescript": "^5.8.3",
46 + "typescript-eslint": "^8.36.0"
47 + }
48 +}
pnpm-lock.yaml new
+5456
@@ -0,0 +1,5456 @@
1 +lockfileVersion: '9.0'
2 +
3 +settings:
4 + autoInstallPeers: true
5 + excludeLinksFromLockfile: false
6 +
7 +importers:
8 +
9 + .:
10 + dependencies:
11 + '@astrojs/mdx':
12 + specifier: ^4.3.10
13 + version: 4.3.10(astro@5.15.5(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(rollup@4.44.1)(tsx@4.20.3)(typescript@5.8.3))
14 + '@astrojs/sitemap':
15 + specifier: ^3.6.0
16 + version: 3.6.0
17 + '@tailwindcss/vite':
18 + specifier: ^4.1.13
19 + version: 4.1.13(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.20.3))
20 + astro:
21 + specifier: ^5.15.5
22 + version: 5.15.5(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(rollup@4.44.1)(tsx@4.20.3)(typescript@5.8.3)
23 + katex:
24 + specifier: ^0.16.22
25 + version: 0.16.22
26 + mdast-util-to-string:
27 + specifier: ^4.0.0
28 + version: 4.0.0
29 + reading-time:
30 + specifier: ^1.5.0
31 + version: 1.5.0
32 + rehype-katex:
33 + specifier: ^7.0.1
34 + version: 7.0.1
35 + remark-directive:
36 + specifier: ^4.0.0
37 + version: 4.0.0
38 + remark-math:
39 + specifier: ^6.0.0
40 + version: 6.0.0
41 + sharp:
42 + specifier: ^0.34.3
43 + version: 0.34.3
44 + tailwindcss:
45 + specifier: ^4.1.13
46 + version: 4.1.13
47 + unist-util-visit:
48 + specifier: ^5.0.0
49 + version: 5.0.0
50 + devDependencies:
51 + '@eslint/js':
52 + specifier: ^9.30.1
53 + version: 9.30.1
54 + '@typescript-eslint/eslint-plugin':
55 + specifier: ^8.35.1
56 + version: 8.35.1(@typescript-eslint/parser@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
57 + '@typescript-eslint/parser':
58 + specifier: ^8.36.0
59 + version: 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
60 + eslint:
61 + specifier: ^9.30.1
62 + version: 9.30.1(jiti@2.6.0)
63 + eslint-config-prettier:
64 + specifier: ^10.1.5
65 + version: 10.1.5(eslint@9.30.1(jiti@2.6.0))
66 + eslint-plugin-astro:
67 + specifier: ^1.3.1
68 + version: 1.3.1(eslint@9.30.1(jiti@2.6.0))
69 + globals:
70 + specifier: ^16.3.0
71 + version: 16.3.0
72 + prettier:
73 + specifier: ^3.6.2
74 + version: 3.6.2
75 + prettier-plugin-astro:
76 + specifier: ^0.14.1
77 + version: 0.14.1
78 + tsx:
79 + specifier: ^4.19.2
80 + version: 4.20.3
81 + typescript:
82 + specifier: ^5.8.3
83 + version: 5.8.3
84 + typescript-eslint:
85 + specifier: ^8.36.0
86 + version: 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
87 +
88 +packages:
89 +
90 + '@astrojs/compiler@2.12.2':
91 + resolution: {integrity: sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==}
92 +
93 + '@astrojs/internal-helpers@0.7.4':
94 + resolution: {integrity: sha512-lDA9MqE8WGi7T/t2BMi+EAXhs4Vcvr94Gqx3q15cFEz8oFZMO4/SFBqYr/UcmNlvW+35alowkVj+w9VhLvs5Cw==}
95 +
96 + '@astrojs/markdown-remark@6.3.8':
97 + resolution: {integrity: sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg==}
98 +
99 + '@astrojs/mdx@4.3.10':
100 + resolution: {integrity: sha512-2T5+XIr7PMqMeXhRofXY5NlY4lA0Km+wkfsqmr9lq5KXUHpGlKPQ9dlDZJP9E/CtljJyEBNS17zq66LrIJ1tiQ==}
101 + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
102 + peerDependencies:
103 + astro: ^5.0.0
104 +
105 + '@astrojs/prism@3.3.0':
106 + resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
107 + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
108 +
109 + '@astrojs/sitemap@3.6.0':
110 + resolution: {integrity: sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg==}
111 +
112 + '@astrojs/telemetry@3.3.0':
113 + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==}
114 + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
115 +
116 + '@babel/helper-string-parser@7.27.1':
117 + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
118 + engines: {node: '>=6.9.0'}
119 +
120 + '@babel/helper-validator-identifier@7.27.1':
121 + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
122 + engines: {node: '>=6.9.0'}
123 +
124 + '@babel/parser@7.28.0':
125 + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==}
126 + engines: {node: '>=6.0.0'}
127 + hasBin: true
128 +
129 + '@babel/types@7.28.0':
130 + resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==}
131 + engines: {node: '>=6.9.0'}
132 +
133 + '@capsizecss/unpack@3.0.1':
134 + resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==}
135 + engines: {node: '>=18'}
136 +
137 + '@emnapi/runtime@1.4.4':
138 + resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==}
139 +
140 + '@esbuild/aix-ppc64@0.25.5':
141 + resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
142 + engines: {node: '>=18'}
143 + cpu: [ppc64]
144 + os: [aix]
145 +
146 + '@esbuild/android-arm64@0.25.5':
147 + resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
148 + engines: {node: '>=18'}
149 + cpu: [arm64]
150 + os: [android]
151 +
152 + '@esbuild/android-arm@0.25.5':
153 + resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
154 + engines: {node: '>=18'}
155 + cpu: [arm]
156 + os: [android]
157 +
158 + '@esbuild/android-x64@0.25.5':
159 + resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
160 + engines: {node: '>=18'}
161 + cpu: [x64]
162 + os: [android]
163 +
164 + '@esbuild/darwin-arm64@0.25.5':
165 + resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
166 + engines: {node: '>=18'}
167 + cpu: [arm64]
168 + os: [darwin]
169 +
170 + '@esbuild/darwin-x64@0.25.5':
171 + resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
172 + engines: {node: '>=18'}
173 + cpu: [x64]
174 + os: [darwin]
175 +
176 + '@esbuild/freebsd-arm64@0.25.5':
177 + resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
178 + engines: {node: '>=18'}
179 + cpu: [arm64]
180 + os: [freebsd]
181 +
182 + '@esbuild/freebsd-x64@0.25.5':
183 + resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
184 + engines: {node: '>=18'}
185 + cpu: [x64]
186 + os: [freebsd]
187 +
188 + '@esbuild/linux-arm64@0.25.5':
189 + resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
190 + engines: {node: '>=18'}
191 + cpu: [arm64]
192 + os: [linux]
193 +
194 + '@esbuild/linux-arm@0.25.5':
195 + resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
196 + engines: {node: '>=18'}
197 + cpu: [arm]
198 + os: [linux]
199 +
200 + '@esbuild/linux-ia32@0.25.5':
201 + resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
202 + engines: {node: '>=18'}
203 + cpu: [ia32]
204 + os: [linux]
205 +
206 + '@esbuild/linux-loong64@0.25.5':
207 + resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
208 + engines: {node: '>=18'}
209 + cpu: [loong64]
210 + os: [linux]
211 +
212 + '@esbuild/linux-mips64el@0.25.5':
213 + resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
214 + engines: {node: '>=18'}
215 + cpu: [mips64el]
216 + os: [linux]
217 +
218 + '@esbuild/linux-ppc64@0.25.5':
219 + resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
220 + engines: {node: '>=18'}
221 + cpu: [ppc64]
222 + os: [linux]
223 +
224 + '@esbuild/linux-riscv64@0.25.5':
225 + resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
226 + engines: {node: '>=18'}
227 + cpu: [riscv64]
228 + os: [linux]
229 +
230 + '@esbuild/linux-s390x@0.25.5':
231 + resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
232 + engines: {node: '>=18'}
233 + cpu: [s390x]
234 + os: [linux]
235 +
236 + '@esbuild/linux-x64@0.25.5':
237 + resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
238 + engines: {node: '>=18'}
239 + cpu: [x64]
240 + os: [linux]
241 +
242 + '@esbuild/netbsd-arm64@0.25.5':
243 + resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
244 + engines: {node: '>=18'}
245 + cpu: [arm64]
246 + os: [netbsd]
247 +
248 + '@esbuild/netbsd-x64@0.25.5':
249 + resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
250 + engines: {node: '>=18'}
251 + cpu: [x64]
252 + os: [netbsd]
253 +
254 + '@esbuild/openbsd-arm64@0.25.5':
255 + resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
256 + engines: {node: '>=18'}
257 + cpu: [arm64]
258 + os: [openbsd]
259 +
260 + '@esbuild/openbsd-x64@0.25.5':
261 + resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
262 + engines: {node: '>=18'}
263 + cpu: [x64]
264 + os: [openbsd]
265 +
266 + '@esbuild/sunos-x64@0.25.5':
267 + resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
268 + engines: {node: '>=18'}
269 + cpu: [x64]
270 + os: [sunos]
271 +
272 + '@esbuild/win32-arm64@0.25.5':
273 + resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
274 + engines: {node: '>=18'}
275 + cpu: [arm64]
276 + os: [win32]
277 +
278 + '@esbuild/win32-ia32@0.25.5':
279 + resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
280 + engines: {node: '>=18'}
281 + cpu: [ia32]
282 + os: [win32]
283 +
284 + '@esbuild/win32-x64@0.25.5':
285 + resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
286 + engines: {node: '>=18'}
287 + cpu: [x64]
288 + os: [win32]
289 +
290 + '@eslint-community/eslint-utils@4.7.0':
291 + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
292 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
293 + peerDependencies:
294 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
295 +
296 + '@eslint-community/regexpp@4.12.1':
297 + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
298 + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
299 +
300 + '@eslint/config-array@0.21.0':
301 + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
302 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
303 +
304 + '@eslint/config-helpers@0.3.0':
305 + resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==}
306 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
307 +
308 + '@eslint/core@0.14.0':
309 + resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==}
310 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
311 +
312 + '@eslint/core@0.15.1':
313 + resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==}
314 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
315 +
316 + '@eslint/eslintrc@3.3.1':
317 + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
318 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
319 +
320 + '@eslint/js@9.30.1':
321 + resolution: {integrity: sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==}
322 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
323 +
324 + '@eslint/object-schema@2.1.6':
325 + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
326 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
327 +
328 + '@eslint/plugin-kit@0.3.3':
329 + resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==}
330 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
331 +
332 + '@humanfs/core@0.19.1':
333 + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
334 + engines: {node: '>=18.18.0'}
335 +
336 + '@humanfs/node@0.16.6':
337 + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
338 + engines: {node: '>=18.18.0'}
339 +
340 + '@humanwhocodes/module-importer@1.0.1':
341 + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
342 + engines: {node: '>=12.22'}
343 +
344 + '@humanwhocodes/retry@0.3.1':
345 + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
346 + engines: {node: '>=18.18'}
347 +
348 + '@humanwhocodes/retry@0.4.3':
349 + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
350 + engines: {node: '>=18.18'}
351 +
352 + '@img/sharp-darwin-arm64@0.34.3':
353 + resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==}
354 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
355 + cpu: [arm64]
356 + os: [darwin]
357 +
358 + '@img/sharp-darwin-x64@0.34.3':
359 + resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==}
360 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
361 + cpu: [x64]
362 + os: [darwin]
363 +
364 + '@img/sharp-libvips-darwin-arm64@1.2.0':
365 + resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==}
366 + cpu: [arm64]
367 + os: [darwin]
368 +
369 + '@img/sharp-libvips-darwin-x64@1.2.0':
370 + resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==}
371 + cpu: [x64]
372 + os: [darwin]
373 +
374 + '@img/sharp-libvips-linux-arm64@1.2.0':
375 + resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
376 + cpu: [arm64]
377 + os: [linux]
378 +
379 + '@img/sharp-libvips-linux-arm@1.2.0':
380 + resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
381 + cpu: [arm]
382 + os: [linux]
383 +
384 + '@img/sharp-libvips-linux-ppc64@1.2.0':
385 + resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
386 + cpu: [ppc64]
387 + os: [linux]
388 +
389 + '@img/sharp-libvips-linux-s390x@1.2.0':
390 + resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
391 + cpu: [s390x]
392 + os: [linux]
393 +
394 + '@img/sharp-libvips-linux-x64@1.2.0':
395 + resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
396 + cpu: [x64]
397 + os: [linux]
398 +
399 + '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
400 + resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
401 + cpu: [arm64]
402 + os: [linux]
403 +
404 + '@img/sharp-libvips-linuxmusl-x64@1.2.0':
405 + resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
406 + cpu: [x64]
407 + os: [linux]
408 +
409 + '@img/sharp-linux-arm64@0.34.3':
410 + resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
411 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
412 + cpu: [arm64]
413 + os: [linux]
414 +
415 + '@img/sharp-linux-arm@0.34.3':
416 + resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
417 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
418 + cpu: [arm]
419 + os: [linux]
420 +
421 + '@img/sharp-linux-ppc64@0.34.3':
422 + resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==}
423 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
424 + cpu: [ppc64]
425 + os: [linux]
426 +
427 + '@img/sharp-linux-s390x@0.34.3':
428 + resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
429 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
430 + cpu: [s390x]
431 + os: [linux]
432 +
433 + '@img/sharp-linux-x64@0.34.3':
434 + resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
435 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
436 + cpu: [x64]
437 + os: [linux]
438 +
439 + '@img/sharp-linuxmusl-arm64@0.34.3':
440 + resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
441 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
442 + cpu: [arm64]
443 + os: [linux]
444 +
445 + '@img/sharp-linuxmusl-x64@0.34.3':
446 + resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
447 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
448 + cpu: [x64]
449 + os: [linux]
450 +
451 + '@img/sharp-wasm32@0.34.3':
452 + resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
453 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
454 + cpu: [wasm32]
455 +
456 + '@img/sharp-win32-arm64@0.34.3':
457 + resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==}
458 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
459 + cpu: [arm64]
460 + os: [win32]
461 +
462 + '@img/sharp-win32-ia32@0.34.3':
463 + resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==}
464 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
465 + cpu: [ia32]
466 + os: [win32]
467 +
468 + '@img/sharp-win32-x64@0.34.3':
469 + resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==}
470 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
471 + cpu: [x64]
472 + os: [win32]
473 +
474 + '@isaacs/fs-minipass@4.0.1':
475 + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
476 + engines: {node: '>=18.0.0'}
477 +
478 + '@jridgewell/gen-mapping@0.3.13':
479 + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
480 +
481 + '@jridgewell/remapping@2.3.5':
482 + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
483 +
484 + '@jridgewell/resolve-uri@3.1.2':
485 + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
486 + engines: {node: '>=6.0.0'}
487 +
488 + '@jridgewell/sourcemap-codec@1.5.4':
489 + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
490 +
491 + '@jridgewell/sourcemap-codec@1.5.5':
492 + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
493 +
494 + '@jridgewell/trace-mapping@0.3.31':
495 + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
496 +
497 + '@mdx-js/mdx@3.1.1':
498 + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
499 +
500 + '@nodelib/fs.scandir@2.1.5':
501 + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
502 + engines: {node: '>= 8'}
503 +
504 + '@nodelib/fs.stat@2.0.5':
505 + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
506 + engines: {node: '>= 8'}
507 +
508 + '@nodelib/fs.walk@1.2.8':
509 + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
510 + engines: {node: '>= 8'}
511 +
512 + '@oslojs/encoding@1.1.0':
513 + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
514 +
515 + '@pkgr/core@0.2.7':
516 + resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==}
517 + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
518 +
519 + '@rollup/pluginutils@5.2.0':
520 + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==}
521 + engines: {node: '>=14.0.0'}
522 + peerDependencies:
523 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
524 + peerDependenciesMeta:
525 + rollup:
526 + optional: true
527 +
528 + '@rollup/rollup-android-arm-eabi@4.44.1':
529 + resolution: {integrity: sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==}
530 + cpu: [arm]
531 + os: [android]
532 +
533 + '@rollup/rollup-android-arm64@4.44.1':
534 + resolution: {integrity: sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==}
535 + cpu: [arm64]
536 + os: [android]
537 +
538 + '@rollup/rollup-darwin-arm64@4.44.1':
539 + resolution: {integrity: sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==}
540 + cpu: [arm64]
541 + os: [darwin]
542 +
543 + '@rollup/rollup-darwin-x64@4.44.1':
544 + resolution: {integrity: sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==}
545 + cpu: [x64]
546 + os: [darwin]
547 +
548 + '@rollup/rollup-freebsd-arm64@4.44.1':
549 + resolution: {integrity: sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==}
550 + cpu: [arm64]
551 + os: [freebsd]
552 +
553 + '@rollup/rollup-freebsd-x64@4.44.1':
554 + resolution: {integrity: sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==}
555 + cpu: [x64]
556 + os: [freebsd]
557 +
558 + '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
559 + resolution: {integrity: sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==}
560 + cpu: [arm]
561 + os: [linux]
562 +
563 + '@rollup/rollup-linux-arm-musleabihf@4.44.1':
564 + resolution: {integrity: sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==}
565 + cpu: [arm]
566 + os: [linux]
567 +
568 + '@rollup/rollup-linux-arm64-gnu@4.44.1':
569 + resolution: {integrity: sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==}
570 + cpu: [arm64]
571 + os: [linux]
572 +
573 + '@rollup/rollup-linux-arm64-musl@4.44.1':
574 + resolution: {integrity: sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==}
575 + cpu: [arm64]
576 + os: [linux]
577 +
578 + '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
579 + resolution: {integrity: sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==}
580 + cpu: [loong64]
581 + os: [linux]
582 +
583 + '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
584 + resolution: {integrity: sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==}
585 + cpu: [ppc64]
586 + os: [linux]
587 +
588 + '@rollup/rollup-linux-riscv64-gnu@4.44.1':
589 + resolution: {integrity: sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==}
590 + cpu: [riscv64]
591 + os: [linux]
592 +
593 + '@rollup/rollup-linux-riscv64-musl@4.44.1':
594 + resolution: {integrity: sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==}
595 + cpu: [riscv64]
596 + os: [linux]
597 +
598 + '@rollup/rollup-linux-s390x-gnu@4.44.1':
599 + resolution: {integrity: sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==}
600 + cpu: [s390x]
601 + os: [linux]
602 +
603 + '@rollup/rollup-linux-x64-gnu@4.44.1':
604 + resolution: {integrity: sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==}
605 + cpu: [x64]
606 + os: [linux]
607 +
608 + '@rollup/rollup-linux-x64-musl@4.44.1':
609 + resolution: {integrity: sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==}
610 + cpu: [x64]
611 + os: [linux]
612 +
613 + '@rollup/rollup-win32-arm64-msvc@4.44.1':
614 + resolution: {integrity: sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==}
615 + cpu: [arm64]
616 + os: [win32]
617 +
618 + '@rollup/rollup-win32-ia32-msvc@4.44.1':
619 + resolution: {integrity: sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==}
620 + cpu: [ia32]
621 + os: [win32]
622 +
623 + '@rollup/rollup-win32-x64-msvc@4.44.1':
624 + resolution: {integrity: sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==}
625 + cpu: [x64]
626 + os: [win32]
627 +
628 + '@shikijs/core@3.15.0':
629 + resolution: {integrity: sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg==}
630 +
631 + '@shikijs/engine-javascript@3.15.0':
632 + resolution: {integrity: sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg==}
633 +
634 + '@shikijs/engine-oniguruma@3.15.0':
635 + resolution: {integrity: sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA==}
636 +
637 + '@shikijs/langs@3.15.0':
638 + resolution: {integrity: sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A==}
639 +
640 + '@shikijs/themes@3.15.0':
641 + resolution: {integrity: sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ==}
642 +
643 + '@shikijs/types@3.15.0':
644 + resolution: {integrity: sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw==}
645 +
646 + '@shikijs/vscode-textmate@10.0.2':
647 + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
648 +
649 + '@swc/helpers@0.5.17':
650 + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
651 +
652 + '@tailwindcss/node@4.1.13':
653 + resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==}
654 +
655 + '@tailwindcss/oxide-android-arm64@4.1.13':
656 + resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==}
657 + engines: {node: '>= 10'}
658 + cpu: [arm64]
659 + os: [android]
660 +
661 + '@tailwindcss/oxide-darwin-arm64@4.1.13':
662 + resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==}
663 + engines: {node: '>= 10'}
664 + cpu: [arm64]
665 + os: [darwin]
666 +
667 + '@tailwindcss/oxide-darwin-x64@4.1.13':
668 + resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==}
669 + engines: {node: '>= 10'}
670 + cpu: [x64]
671 + os: [darwin]
672 +
673 + '@tailwindcss/oxide-freebsd-x64@4.1.13':
674 + resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==}
675 + engines: {node: '>= 10'}
676 + cpu: [x64]
677 + os: [freebsd]
678 +
679 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
680 + resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==}
681 + engines: {node: '>= 10'}
682 + cpu: [arm]
683 + os: [linux]
684 +
685 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
686 + resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==}
687 + engines: {node: '>= 10'}
688 + cpu: [arm64]
689 + os: [linux]
690 +
691 + '@tailwindcss/oxide-linux-arm64-musl@4.1.13':
692 + resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==}
693 + engines: {node: '>= 10'}
694 + cpu: [arm64]
695 + os: [linux]
696 +
697 + '@tailwindcss/oxide-linux-x64-gnu@4.1.13':
698 + resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==}
699 + engines: {node: '>= 10'}
700 + cpu: [x64]
701 + os: [linux]
702 +
703 + '@tailwindcss/oxide-linux-x64-musl@4.1.13':
704 + resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==}
705 + engines: {node: '>= 10'}
706 + cpu: [x64]
707 + os: [linux]
708 +
709 + '@tailwindcss/oxide-wasm32-wasi@4.1.13':
710 + resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==}
711 + engines: {node: '>=14.0.0'}
712 + cpu: [wasm32]
713 + bundledDependencies:
714 + - '@napi-rs/wasm-runtime'
715 + - '@emnapi/core'
716 + - '@emnapi/runtime'
717 + - '@tybys/wasm-util'
718 + - '@emnapi/wasi-threads'
719 + - tslib
720 +
721 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
722 + resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==}
723 + engines: {node: '>= 10'}
724 + cpu: [arm64]
725 + os: [win32]
726 +
727 + '@tailwindcss/oxide-win32-x64-msvc@4.1.13':
728 + resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==}
729 + engines: {node: '>= 10'}
730 + cpu: [x64]
731 + os: [win32]
732 +
733 + '@tailwindcss/oxide@4.1.13':
734 + resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==}
735 + engines: {node: '>= 10'}
736 +
737 + '@tailwindcss/vite@4.1.13':
738 + resolution: {integrity: sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ==}
739 + peerDependencies:
740 + vite: ^5.2.0 || ^6 || ^7
741 +
742 + '@types/debug@4.1.12':
743 + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
744 +
745 + '@types/estree-jsx@1.0.5':
746 + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
747 +
748 + '@types/estree@1.0.8':
749 + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
750 +
751 + '@types/fontkit@2.0.8':
752 + resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==}
753 +
754 + '@types/hast@3.0.4':
755 + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
756 +
757 + '@types/json-schema@7.0.15':
758 + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
759 +
760 + '@types/katex@0.16.7':
761 + resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
762 +
763 + '@types/mdast@4.0.4':
764 + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
765 +
766 + '@types/mdx@2.0.13':
767 + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
768 +
769 + '@types/ms@2.1.0':
770 + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
771 +
772 + '@types/nlcst@2.0.3':
773 + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
774 +
775 + '@types/node@17.0.45':
776 + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
777 +
778 + '@types/node@24.0.10':
779 + resolution: {integrity: sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==}
780 +
781 + '@types/sax@1.2.7':
782 + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
783 +
784 + '@types/unist@2.0.11':
785 + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
786 +
787 + '@types/unist@3.0.3':
788 + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
789 +
790 + '@typescript-eslint/eslint-plugin@8.35.1':
791 + resolution: {integrity: sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==}
792 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
793 + peerDependencies:
794 + '@typescript-eslint/parser': ^8.35.1
795 + eslint: ^8.57.0 || ^9.0.0
796 + typescript: '>=4.8.4 <5.9.0'
797 +
798 + '@typescript-eslint/eslint-plugin@8.36.0':
799 + resolution: {integrity: sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==}
800 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
801 + peerDependencies:
802 + '@typescript-eslint/parser': ^8.36.0
803 + eslint: ^8.57.0 || ^9.0.0
804 + typescript: '>=4.8.4 <5.9.0'
805 +
806 + '@typescript-eslint/parser@8.36.0':
807 + resolution: {integrity: sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==}
808 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
809 + peerDependencies:
810 + eslint: ^8.57.0 || ^9.0.0
811 + typescript: '>=4.8.4 <5.9.0'
812 +
813 + '@typescript-eslint/project-service@8.35.1':
814 + resolution: {integrity: sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==}
815 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
816 + peerDependencies:
817 + typescript: '>=4.8.4 <5.9.0'
818 +
819 + '@typescript-eslint/project-service@8.36.0':
820 + resolution: {integrity: sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==}
821 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
822 + peerDependencies:
823 + typescript: '>=4.8.4 <5.9.0'
824 +
825 + '@typescript-eslint/scope-manager@8.35.1':
826 + resolution: {integrity: sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==}
827 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
828 +
829 + '@typescript-eslint/scope-manager@8.36.0':
830 + resolution: {integrity: sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==}
831 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
832 +
833 + '@typescript-eslint/tsconfig-utils@8.35.1':
834 + resolution: {integrity: sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==}
835 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
836 + peerDependencies:
837 + typescript: '>=4.8.4 <5.9.0'
838 +
839 + '@typescript-eslint/tsconfig-utils@8.36.0':
840 + resolution: {integrity: sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==}
841 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
842 + peerDependencies:
843 + typescript: '>=4.8.4 <5.9.0'
844 +
845 + '@typescript-eslint/type-utils@8.35.1':
846 + resolution: {integrity: sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==}
847 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
848 + peerDependencies:
849 + eslint: ^8.57.0 || ^9.0.0
850 + typescript: '>=4.8.4 <5.9.0'
851 +
852 + '@typescript-eslint/type-utils@8.36.0':
853 + resolution: {integrity: sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==}
854 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
855 + peerDependencies:
856 + eslint: ^8.57.0 || ^9.0.0
857 + typescript: '>=4.8.4 <5.9.0'
858 +
859 + '@typescript-eslint/types@8.35.1':
860 + resolution: {integrity: sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==}
861 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
862 +
863 + '@typescript-eslint/types@8.36.0':
864 + resolution: {integrity: sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==}
865 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
866 +
867 + '@typescript-eslint/typescript-estree@8.35.1':
868 + resolution: {integrity: sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==}
869 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
870 + peerDependencies:
871 + typescript: '>=4.8.4 <5.9.0'
872 +
873 + '@typescript-eslint/typescript-estree@8.36.0':
874 + resolution: {integrity: sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==}
875 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
876 + peerDependencies:
877 + typescript: '>=4.8.4 <5.9.0'
878 +
879 + '@typescript-eslint/utils@8.35.1':
880 + resolution: {integrity: sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==}
881 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
882 + peerDependencies:
883 + eslint: ^8.57.0 || ^9.0.0
884 + typescript: '>=4.8.4 <5.9.0'
885 +
886 + '@typescript-eslint/utils@8.36.0':
887 + resolution: {integrity: sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==}
888 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
889 + peerDependencies:
890 + eslint: ^8.57.0 || ^9.0.0
891 + typescript: '>=4.8.4 <5.9.0'
892 +
893 + '@typescript-eslint/visitor-keys@8.35.1':
894 + resolution: {integrity: sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==}
895 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
896 +
897 + '@typescript-eslint/visitor-keys@8.36.0':
898 + resolution: {integrity: sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==}
899 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
900 +
901 + '@ungap/structured-clone@1.3.0':
902 + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
903 +
904 + acorn-jsx@5.3.2:
905 + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
906 + peerDependencies:
907 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
908 +
909 + acorn@8.15.0:
910 + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
911 + engines: {node: '>=0.4.0'}
912 + hasBin: true
913 +
914 + ajv@6.12.6:
915 + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
916 +
917 + ansi-align@3.0.1:
918 + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
919 +
920 + ansi-regex@5.0.1:
921 + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
922 + engines: {node: '>=8'}
923 +
924 + ansi-regex@6.1.0:
925 + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
926 + engines: {node: '>=12'}
927 +
928 + ansi-styles@4.3.0:
929 + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
930 + engines: {node: '>=8'}
931 +
932 + ansi-styles@6.2.1:
933 + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
934 + engines: {node: '>=12'}
935 +
936 + anymatch@3.1.3:
937 + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
938 + engines: {node: '>= 8'}
939 +
940 + arg@5.0.2:
941 + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
942 +
943 + argparse@2.0.1:
944 + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
945 +
946 + aria-query@5.3.2:
947 + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
948 + engines: {node: '>= 0.4'}
949 +
950 + array-iterate@2.0.1:
951 + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==}
952 +
953 + astring@1.9.0:
954 + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
955 + hasBin: true
956 +
957 + astro-eslint-parser@1.2.2:
958 + resolution: {integrity: sha512-JepyLROIad6f44uyqMF6HKE2QbunNzp3mYKRcPoDGt0QkxXmH222FAFC64WTyQu2Kg8NNEXHTN/sWuUId9sSxw==}
959 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
960 +
961 + astro@5.15.5:
962 + resolution: {integrity: sha512-A56u4H6gFHEb0yRHcGTOADBb7jmEwfDjQpkqVV/Z+ZWlu6mYuwCrIcOUtZjNno0chrRKmOeZWDofW23ql18y3w==}
963 + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'}
964 + hasBin: true
965 +
966 + astrojs-compiler-sync@1.1.1:
967 + resolution: {integrity: sha512-0mKvB9sDQRIZPsEJadw6OaFbGJ92cJPPR++ICca9XEyiUAZqgVuk25jNmzHPT0KF80rI94trSZrUR5iHFXGGOQ==}
968 + engines: {node: ^18.18.0 || >=20.9.0}
969 + peerDependencies:
970 + '@astrojs/compiler': '>=0.27.0'
971 +
972 + axobject-query@4.1.0:
973 + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
974 + engines: {node: '>= 0.4'}
975 +
976 + bail@2.0.2:
977 + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
978 +
979 + balanced-match@1.0.2:
980 + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
981 +
982 + base-64@1.0.0:
983 + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
984 +
985 + base64-js@1.5.1:
986 + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
987 +
988 + boxen@8.0.1:
989 + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
990 + engines: {node: '>=18'}
991 +
992 + brace-expansion@1.1.12:
993 + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
994 +
995 + brace-expansion@2.0.2:
996 + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
997 +
998 + braces@3.0.3:
999 + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
1000 + engines: {node: '>=8'}
1001 +
1002 + brotli@1.3.3:
1003 + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==}
1004 +
1005 + callsites@3.1.0:
1006 + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
1007 + engines: {node: '>=6'}
1008 +
1009 + camelcase@8.0.0:
1010 + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
1011 + engines: {node: '>=16'}
1012 +
1013 + ccount@2.0.1:
1014 + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
1015 +
1016 + chalk@4.1.2:
1017 + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
1018 + engines: {node: '>=10'}
1019 +
1020 + chalk@5.4.1:
1021 + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
1022 + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
1023 +
1024 + character-entities-html4@2.1.0:
1025 + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
1026 +
1027 + character-entities-legacy@3.0.0:
1028 + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
1029 +
1030 + character-entities@2.0.2:
1031 + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
1032 +
1033 + character-reference-invalid@2.0.1:
1034 + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
1035 +
1036 + chokidar@4.0.3:
1037 + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
1038 + engines: {node: '>= 14.16.0'}
1039 +
1040 + chownr@3.0.0:
1041 + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
1042 + engines: {node: '>=18'}
1043 +
1044 + ci-info@4.3.1:
1045 + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==}
1046 + engines: {node: '>=8'}
1047 +
1048 + cli-boxes@3.0.0:
1049 + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
1050 + engines: {node: '>=10'}
1051 +
1052 + clone@2.1.2:
1053 + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
1054 + engines: {node: '>=0.8'}
1055 +
1056 + clsx@2.1.1:
1057 + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
1058 + engines: {node: '>=6'}
1059 +
1060 + collapse-white-space@2.1.0:
1061 + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
1062 +
1063 + color-convert@2.0.1:
1064 + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
1065 + engines: {node: '>=7.0.0'}
1066 +
1067 + color-name@1.1.4:
1068 + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
1069 +
1070 + color-string@1.9.1:
1071 + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
1072 +
1073 + color@4.2.3:
1074 + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
1075 + engines: {node: '>=12.5.0'}
1076 +
1077 + comma-separated-tokens@2.0.3:
1078 + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
1079 +
1080 + commander@8.3.0:
1081 + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
1082 + engines: {node: '>= 12'}
1083 +
1084 + common-ancestor-path@1.0.1:
1085 + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==}
1086 +
1087 + concat-map@0.0.1:
1088 + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
1089 +
1090 + cookie-es@1.2.2:
1091 + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
1092 +
1093 + cookie@1.0.2:
1094 + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
1095 + engines: {node: '>=18'}
1096 +
1097 + cross-spawn@7.0.6:
1098 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
1099 + engines: {node: '>= 8'}
1100 +
1101 + crossws@0.3.5:
1102 + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
1103 +
1104 + css-tree@3.1.0:
1105 + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
1106 + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
1107 +
1108 + cssesc@3.0.0:
1109 + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
1110 + engines: {node: '>=4'}
1111 + hasBin: true
1112 +
1113 + debug@4.4.1:
1114 + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
1115 + engines: {node: '>=6.0'}
1116 + peerDependencies:
1117 + supports-color: '*'
1118 + peerDependenciesMeta:
1119 + supports-color:
1120 + optional: true
1121 +
1122 + decode-named-character-reference@1.2.0:
1123 + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
1124 +
1125 + deep-is@0.1.4:
1126 + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
1127 +
1128 + defu@6.1.4:
1129 + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
1130 +
1131 + dequal@2.0.3:
1132 + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
1133 + engines: {node: '>=6'}
1134 +
1135 + destr@2.0.5:
1136 + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
1137 +
1138 + detect-libc@2.0.4:
1139 + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
1140 + engines: {node: '>=8'}
1141 +
1142 + deterministic-object-hash@2.0.2:
1143 + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==}
1144 + engines: {node: '>=18'}
1145 +
1146 + devalue@5.5.0:
1147 + resolution: {integrity: sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==}
1148 +
1149 + devlop@1.1.0:
1150 + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
1151 +
1152 + dfa@1.2.0:
1153 + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==}
1154 +
1155 + diff@5.2.0:
1156 + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
1157 + engines: {node: '>=0.3.1'}
1158 +
1159 + dlv@1.1.3:
1160 + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
1161 +
1162 + dset@3.1.4:
1163 + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
1164 + engines: {node: '>=4'}
1165 +
1166 + emoji-regex@10.4.0:
1167 + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
1168 +
1169 + emoji-regex@8.0.0:
1170 + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
1171 +
1172 + enhanced-resolve@5.18.3:
1173 + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
1174 + engines: {node: '>=10.13.0'}
1175 +
1176 + entities@6.0.1:
1177 + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
1178 + engines: {node: '>=0.12'}
1179 +
1180 + es-module-lexer@1.7.0:
1181 + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
1182 +
1183 + esast-util-from-estree@2.0.0:
1184 + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
1185 +
1186 + esast-util-from-js@2.0.1:
1187 + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==}
1188 +
1189 + esbuild@0.25.5:
1190 + resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
1191 + engines: {node: '>=18'}
1192 + hasBin: true
1193 +
1194 + escape-string-regexp@4.0.0:
1195 + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
1196 + engines: {node: '>=10'}
1197 +
1198 + escape-string-regexp@5.0.0:
1199 + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
1200 + engines: {node: '>=12'}
1201 +
1202 + eslint-compat-utils@0.6.5:
1203 + resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==}
1204 + engines: {node: '>=12'}
1205 + peerDependencies:
1206 + eslint: '>=6.0.0'
1207 +
1208 + eslint-config-prettier@10.1.5:
1209 + resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==}
1210 + hasBin: true
1211 + peerDependencies:
1212 + eslint: '>=7.0.0'
1213 +
1214 + eslint-plugin-astro@1.3.1:
1215 + resolution: {integrity: sha512-2XaLCMQm8htW1UvJvy1Zcmg8l0ziskitiUfJTn/w1Mk7r4Mxj0fZeNpN6UTNrm64XBIXSa5h8UCGrg8mdu47+g==}
1216 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1217 + peerDependencies:
1218 + eslint: '>=8.57.0'
1219 +
1220 + eslint-scope@8.4.0:
1221 + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
1222 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1223 +
1224 + eslint-visitor-keys@3.4.3:
1225 + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
1226 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1227 +
1228 + eslint-visitor-keys@4.2.1:
1229 + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
1230 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1231 +
1232 + eslint@9.30.1:
1233 + resolution: {integrity: sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==}
1234 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1235 + hasBin: true
1236 + peerDependencies:
1237 + jiti: '*'
1238 + peerDependenciesMeta:
1239 + jiti:
1240 + optional: true
1241 +
1242 + espree@10.4.0:
1243 + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
1244 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
1245 +
1246 + esquery@1.6.0:
1247 + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
1248 + engines: {node: '>=0.10'}
1249 +
1250 + esrecurse@4.3.0:
1251 + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
1252 + engines: {node: '>=4.0'}
1253 +
1254 + estraverse@5.3.0:
1255 + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
1256 + engines: {node: '>=4.0'}
1257 +
1258 + estree-util-attach-comments@3.0.0:
1259 + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==}
1260 +
1261 + estree-util-build-jsx@3.0.1:
1262 + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==}
1263 +
1264 + estree-util-is-identifier-name@3.0.0:
1265 + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==}
1266 +
1267 + estree-util-scope@1.0.0:
1268 + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==}
1269 +
1270 + estree-util-to-js@2.0.0:
1271 + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==}
1272 +
1273 + estree-util-visit@2.0.0:
1274 + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
1275 +
1276 + estree-walker@2.0.2:
1277 + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
1278 +
1279 + estree-walker@3.0.3:
1280 + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
1281 +
1282 + esutils@2.0.3:
1283 + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
1284 + engines: {node: '>=0.10.0'}
1285 +
1286 + eventemitter3@5.0.1:
1287 + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
1288 +
1289 + extend@3.0.2:
1290 + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
1291 +
1292 + fast-deep-equal@3.1.3:
1293 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
1294 +
1295 + fast-glob@3.3.3:
1296 + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
1297 + engines: {node: '>=8.6.0'}
1298 +
1299 + fast-json-stable-stringify@2.1.0:
1300 + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
1301 +
1302 + fast-levenshtein@2.0.6:
1303 + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
1304 +
1305 + fastq@1.19.1:
1306 + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
1307 +
1308 + fdir@6.4.6:
1309 + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
1310 + peerDependencies:
1311 + picomatch: ^3 || ^4
1312 + peerDependenciesMeta:
1313 + picomatch:
1314 + optional: true
1315 +
1316 + file-entry-cache@8.0.0:
1317 + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
1318 + engines: {node: '>=16.0.0'}
1319 +
1320 + fill-range@7.1.1:
1321 + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
1322 + engines: {node: '>=8'}
1323 +
1324 + find-up@5.0.0:
1325 + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
1326 + engines: {node: '>=10'}
1327 +
1328 + flat-cache@4.0.1:
1329 + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
1330 + engines: {node: '>=16'}
1331 +
1332 + flatted@3.3.3:
1333 + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
1334 +
1335 + flattie@1.1.1:
1336 + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
1337 + engines: {node: '>=8'}
1338 +
1339 + fontace@0.3.0:
1340 + resolution: {integrity: sha512-czoqATrcnxgWb/nAkfyIrRp6Q8biYj7nGnL6zfhTcX+JKKpWHFBnb8uNMw/kZr7u++3Y3wYSYoZgHkCcsuBpBg==}
1341 +
1342 + fontkit@2.0.4:
1343 + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==}
1344 +
1345 + fsevents@2.3.3:
1346 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
1347 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1348 + os: [darwin]
1349 +
1350 + get-east-asian-width@1.3.0:
1351 + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
1352 + engines: {node: '>=18'}
1353 +
1354 + get-tsconfig@4.10.1:
1355 + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
1356 +
1357 + github-slugger@2.0.0:
1358 + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
1359 +
1360 + glob-parent@5.1.2:
1361 + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
1362 + engines: {node: '>= 6'}
1363 +
1364 + glob-parent@6.0.2:
1365 + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
1366 + engines: {node: '>=10.13.0'}
1367 +
1368 + globals@14.0.0:
1369 + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
1370 + engines: {node: '>=18'}
1371 +
1372 + globals@15.15.0:
1373 + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
1374 + engines: {node: '>=18'}
1375 +
1376 + globals@16.3.0:
1377 + resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==}
1378 + engines: {node: '>=18'}
1379 +
1380 + graceful-fs@4.2.11:
1381 + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
1382 +
1383 + graphemer@1.4.0:
1384 + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
1385 +
1386 + h3@1.15.4:
1387 + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
1388 +
1389 + has-flag@4.0.0:
1390 + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
1391 + engines: {node: '>=8'}
1392 +
1393 + hast-util-from-dom@5.0.1:
1394 + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==}
1395 +
1396 + hast-util-from-html-isomorphic@2.0.0:
1397 + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==}
1398 +
1399 + hast-util-from-html@2.0.3:
1400 + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
1401 +
1402 + hast-util-from-parse5@8.0.3:
1403 + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
1404 +
1405 + hast-util-is-element@3.0.0:
1406 + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
1407 +
1408 + hast-util-parse-selector@4.0.0:
1409 + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
1410 +
1411 + hast-util-raw@9.1.0:
1412 + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==}
1413 +
1414 + hast-util-to-estree@3.1.3:
1415 + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==}
1416 +
1417 + hast-util-to-html@9.0.5:
1418 + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
1419 +
1420 + hast-util-to-jsx-runtime@2.3.6:
1421 + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
1422 +
1423 + hast-util-to-parse5@8.0.0:
1424 + resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
1425 +
1426 + hast-util-to-text@4.0.2:
1427 + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
1428 +
1429 + hast-util-whitespace@3.0.0:
1430 + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
1431 +
1432 + hastscript@9.0.1:
1433 + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
1434 +
1435 + html-escaper@3.0.3:
1436 + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
1437 +
1438 + html-void-elements@3.0.0:
1439 + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
1440 +
1441 + http-cache-semantics@4.2.0:
1442 + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
1443 +
1444 + ignore@5.3.2:
1445 + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
1446 + engines: {node: '>= 4'}
1447 +
1448 + ignore@7.0.5:
1449 + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
1450 + engines: {node: '>= 4'}
1451 +
1452 + import-fresh@3.3.1:
1453 + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
1454 + engines: {node: '>=6'}
1455 +
1456 + import-meta-resolve@4.2.0:
1457 + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
1458 +
1459 + imurmurhash@0.1.4:
1460 + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
1461 + engines: {node: '>=0.8.19'}
1462 +
1463 + inline-style-parser@0.2.4:
1464 + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
1465 +
1466 + iron-webcrypto@1.2.1:
1467 + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
1468 +
1469 + is-alphabetical@2.0.1:
1470 + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
1471 +
1472 + is-alphanumerical@2.0.1:
1473 + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
1474 +
1475 + is-arrayish@0.3.2:
1476 + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
1477 +
1478 + is-decimal@2.0.1:
1479 + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
1480 +
1481 + is-docker@3.0.0:
1482 + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
1483 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
1484 + hasBin: true
1485 +
1486 + is-extglob@2.1.1:
1487 + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
1488 + engines: {node: '>=0.10.0'}
1489 +
1490 + is-fullwidth-code-point@3.0.0:
1491 + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
1492 + engines: {node: '>=8'}
1493 +
1494 + is-glob@4.0.3:
1495 + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
1496 + engines: {node: '>=0.10.0'}
1497 +
1498 + is-hexadecimal@2.0.1:
1499 + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==}
1500 +
1501 + is-inside-container@1.0.0:
1502 + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
1503 + engines: {node: '>=14.16'}
1504 + hasBin: true
1505 +
1506 + is-number@7.0.0:
1507 + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
1508 + engines: {node: '>=0.12.0'}
1509 +
1510 + is-plain-obj@4.1.0:
1511 + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
1512 + engines: {node: '>=12'}
1513 +
1514 + is-wsl@3.1.0:
1515 + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
1516 + engines: {node: '>=16'}
1517 +
1518 + isexe@2.0.0:
1519 + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1520 +
1521 + jiti@2.6.0:
1522 + resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==}
1523 + hasBin: true
1524 +
1525 + js-yaml@4.1.0:
1526 + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
1527 + hasBin: true
1528 +
1529 + json-buffer@3.0.1:
1530 + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
1531 +
1532 + json-schema-traverse@0.4.1:
1533 + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
1534 +
1535 + json-stable-stringify-without-jsonify@1.0.1:
1536 + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
1537 +
1538 + katex@0.16.22:
1539 + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==}
1540 + hasBin: true
1541 +
1542 + keyv@4.5.4:
1543 + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
1544 +
1545 + kleur@3.0.3:
1546 + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
1547 + engines: {node: '>=6'}
1548 +
1549 + levn@0.4.1:
1550 + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
1551 + engines: {node: '>= 0.8.0'}
1552 +
1553 + lightningcss-darwin-arm64@1.30.1:
1554 + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
1555 + engines: {node: '>= 12.0.0'}
1556 + cpu: [arm64]
1557 + os: [darwin]
1558 +
1559 + lightningcss-darwin-x64@1.30.1:
1560 + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
1561 + engines: {node: '>= 12.0.0'}
1562 + cpu: [x64]
1563 + os: [darwin]
1564 +
1565 + lightningcss-freebsd-x64@1.30.1:
1566 + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
1567 + engines: {node: '>= 12.0.0'}
1568 + cpu: [x64]
1569 + os: [freebsd]
1570 +
1571 + lightningcss-linux-arm-gnueabihf@1.30.1:
1572 + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
1573 + engines: {node: '>= 12.0.0'}
1574 + cpu: [arm]
1575 + os: [linux]
1576 +
1577 + lightningcss-linux-arm64-gnu@1.30.1:
1578 + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
1579 + engines: {node: '>= 12.0.0'}
1580 + cpu: [arm64]
1581 + os: [linux]
1582 +
1583 + lightningcss-linux-arm64-musl@1.30.1:
1584 + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
1585 + engines: {node: '>= 12.0.0'}
1586 + cpu: [arm64]
1587 + os: [linux]
1588 +
1589 + lightningcss-linux-x64-gnu@1.30.1:
1590 + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
1591 + engines: {node: '>= 12.0.0'}
1592 + cpu: [x64]
1593 + os: [linux]
1594 +
1595 + lightningcss-linux-x64-musl@1.30.1:
1596 + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
1597 + engines: {node: '>= 12.0.0'}
1598 + cpu: [x64]
1599 + os: [linux]
1600 +
1601 + lightningcss-win32-arm64-msvc@1.30.1:
1602 + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
1603 + engines: {node: '>= 12.0.0'}
1604 + cpu: [arm64]
1605 + os: [win32]
1606 +
1607 + lightningcss-win32-x64-msvc@1.30.1:
1608 + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
1609 + engines: {node: '>= 12.0.0'}
1610 + cpu: [x64]
1611 + os: [win32]
1612 +
1613 + lightningcss@1.30.1:
1614 + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
1615 + engines: {node: '>= 12.0.0'}
1616 +
1617 + locate-path@6.0.0:
1618 + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
1619 + engines: {node: '>=10'}
1620 +
1621 + lodash.merge@4.6.2:
1622 + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
1623 +
1624 + longest-streak@3.1.0:
1625 + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
1626 +
1627 + lru-cache@10.4.3:
1628 + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
1629 +
1630 + magic-string@0.30.19:
1631 + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
1632 +
1633 + magicast@0.3.5:
1634 + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
1635 +
1636 + markdown-extensions@2.0.0:
1637 + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
1638 + engines: {node: '>=16'}
1639 +
1640 + markdown-table@3.0.4:
1641 + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
1642 +
1643 + mdast-util-definitions@6.0.0:
1644 + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
1645 +
1646 + mdast-util-directive@3.1.0:
1647 + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==}
1648 +
1649 + mdast-util-find-and-replace@3.0.2:
1650 + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
1651 +
1652 + mdast-util-from-markdown@2.0.2:
1653 + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==}
1654 +
1655 + mdast-util-gfm-autolink-literal@2.0.1:
1656 + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
1657 +
1658 + mdast-util-gfm-footnote@2.1.0:
1659 + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
1660 +
1661 + mdast-util-gfm-strikethrough@2.0.0:
1662 + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
1663 +
1664 + mdast-util-gfm-table@2.0.0:
1665 + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
1666 +
1667 + mdast-util-gfm-task-list-item@2.0.0:
1668 + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
1669 +
1670 + mdast-util-gfm@3.1.0:
1671 + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
1672 +
1673 + mdast-util-math@3.0.0:
1674 + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==}
1675 +
1676 + mdast-util-mdx-expression@2.0.1:
1677 + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
1678 +
1679 + mdast-util-mdx-jsx@3.2.0:
1680 + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==}
1681 +
1682 + mdast-util-mdx@3.0.0:
1683 + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==}
1684 +
1685 + mdast-util-mdxjs-esm@2.0.1:
1686 + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==}
1687 +
1688 + mdast-util-phrasing@4.1.0:
1689 + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
1690 +
1691 + mdast-util-to-hast@13.2.0:
1692 + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
1693 +
1694 + mdast-util-to-markdown@2.1.2:
1695 + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
1696 +
1697 + mdast-util-to-string@4.0.0:
1698 + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
1699 +
1700 + mdn-data@2.12.2:
1701 + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
1702 +
1703 + merge2@1.4.1:
1704 + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1705 + engines: {node: '>= 8'}
1706 +
1707 + micromark-core-commonmark@2.0.3:
1708 + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
1709 +
1710 + micromark-extension-directive@4.0.0:
1711 + resolution: {integrity: sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==}
1712 +
1713 + micromark-extension-gfm-autolink-literal@2.1.0:
1714 + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
1715 +
1716 + micromark-extension-gfm-footnote@2.1.0:
1717 + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
1718 +
1719 + micromark-extension-gfm-strikethrough@2.1.0:
1720 + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
1721 +
1722 + micromark-extension-gfm-table@2.1.1:
1723 + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==}
1724 +
1725 + micromark-extension-gfm-tagfilter@2.0.0:
1726 + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
1727 +
1728 + micromark-extension-gfm-task-list-item@2.1.0:
1729 + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
1730 +
1731 + micromark-extension-gfm@3.0.0:
1732 + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
1733 +
1734 + micromark-extension-math@3.1.0:
1735 + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==}
1736 +
1737 + micromark-extension-mdx-expression@3.0.1:
1738 + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==}
1739 +
1740 + micromark-extension-mdx-jsx@3.0.2:
1741 + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==}
1742 +
1743 + micromark-extension-mdx-md@2.0.0:
1744 + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==}
1745 +
1746 + micromark-extension-mdxjs-esm@3.0.0:
1747 + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==}
1748 +
1749 + micromark-extension-mdxjs@3.0.0:
1750 + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==}
1751 +
1752 + micromark-factory-destination@2.0.1:
1753 + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
1754 +
1755 + micromark-factory-label@2.0.1:
1756 + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
1757 +
1758 + micromark-factory-mdx-expression@2.0.3:
1759 + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==}
1760 +
1761 + micromark-factory-space@2.0.1:
1762 + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
1763 +
1764 + micromark-factory-title@2.0.1:
1765 + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
1766 +
1767 + micromark-factory-whitespace@2.0.1:
1768 + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
1769 +
1770 + micromark-util-character@2.1.1:
1771 + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
1772 +
1773 + micromark-util-chunked@2.0.1:
1774 + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
1775 +
1776 + micromark-util-classify-character@2.0.1:
1777 + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
1778 +
1779 + micromark-util-combine-extensions@2.0.1:
1780 + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
1781 +
1782 + micromark-util-decode-numeric-character-reference@2.0.2:
1783 + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
1784 +
1785 + micromark-util-decode-string@2.0.1:
1786 + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
1787 +
1788 + micromark-util-encode@2.0.1:
1789 + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
1790 +
1791 + micromark-util-events-to-acorn@2.0.3:
1792 + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==}
1793 +
1794 + micromark-util-html-tag-name@2.0.1:
1795 + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
1796 +
1797 + micromark-util-normalize-identifier@2.0.1:
1798 + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
1799 +
1800 + micromark-util-resolve-all@2.0.1:
1801 + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
1802 +
1803 + micromark-util-sanitize-uri@2.0.1:
1804 + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
1805 +
1806 + micromark-util-subtokenize@2.1.0:
1807 + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
1808 +
1809 + micromark-util-symbol@2.0.1:
1810 + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
1811 +
1812 + micromark-util-types@2.0.2:
1813 + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
1814 +
1815 + micromark@4.0.2:
1816 + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
1817 +
1818 + micromatch@4.0.8:
1819 + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
1820 + engines: {node: '>=8.6'}
1821 +
1822 + minimatch@3.1.2:
1823 + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
1824 +
1825 + minimatch@9.0.5:
1826 + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
1827 + engines: {node: '>=16 || 14 >=14.17'}
1828 +
1829 + minipass@7.1.2:
1830 + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
1831 + engines: {node: '>=16 || 14 >=14.17'}
1832 +
1833 + minizlib@3.1.0:
1834 + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
1835 + engines: {node: '>= 18'}
1836 +
1837 + mrmime@2.0.1:
1838 + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
1839 + engines: {node: '>=10'}
1840 +
1841 + ms@2.1.3:
1842 + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1843 +
1844 + nanoid@3.3.11:
1845 + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
1846 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1847 + hasBin: true
1848 +
1849 + natural-compare@1.4.0:
1850 + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
1851 +
1852 + neotraverse@0.6.18:
1853 + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
1854 + engines: {node: '>= 10'}
1855 +
1856 + nlcst-to-string@4.0.0:
1857 + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==}
1858 +
1859 + node-fetch-native@1.6.6:
1860 + resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
1861 +
1862 + node-fetch-native@1.6.7:
1863 + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
1864 +
1865 + node-mock-http@1.0.3:
1866 + resolution: {integrity: sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==}
1867 +
1868 + normalize-path@3.0.0:
1869 + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
1870 + engines: {node: '>=0.10.0'}
1871 +
1872 + ofetch@1.4.1:
1873 + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==}
1874 +
1875 + ofetch@1.5.1:
1876 + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
1877 +
1878 + ohash@2.0.11:
1879 + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
1880 +
1881 + oniguruma-parser@0.12.1:
1882 + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
1883 +
1884 + oniguruma-to-es@4.3.3:
1885 + resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==}
1886 +
1887 + optionator@0.9.4:
1888 + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
1889 + engines: {node: '>= 0.8.0'}
1890 +
1891 + p-limit@3.1.0:
1892 + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
1893 + engines: {node: '>=10'}
1894 +
1895 + p-limit@6.2.0:
1896 + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==}
1897 + engines: {node: '>=18'}
1898 +
1899 + p-locate@5.0.0:
1900 + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
1901 + engines: {node: '>=10'}
1902 +
1903 + p-queue@8.1.0:
1904 + resolution: {integrity: sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==}
1905 + engines: {node: '>=18'}
1906 +
1907 + p-timeout@6.1.4:
1908 + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==}
1909 + engines: {node: '>=14.16'}
1910 +
1911 + package-manager-detector@1.3.0:
1912 + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==}
1913 +
1914 + pako@0.2.9:
1915 + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
1916 +
1917 + parent-module@1.0.1:
1918 + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
1919 + engines: {node: '>=6'}
1920 +
1921 + parse-entities@4.0.2:
1922 + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
1923 +
1924 + parse-latin@7.0.0:
1925 + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
1926 +
1927 + parse5@7.3.0:
1928 + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
1929 +
1930 + path-exists@4.0.0:
1931 + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
1932 + engines: {node: '>=8'}
1933 +
1934 + path-key@3.1.1:
1935 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1936 + engines: {node: '>=8'}
1937 +
1938 + picocolors@1.1.1:
1939 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
1940 +
1941 + picomatch@2.3.1:
1942 + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1943 + engines: {node: '>=8.6'}
1944 +
1945 + picomatch@4.0.3:
1946 + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
1947 + engines: {node: '>=12'}
1948 +
1949 + postcss-selector-parser@7.1.0:
1950 + resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
1951 + engines: {node: '>=4'}
1952 +
1953 + postcss@8.5.6:
1954 + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
1955 + engines: {node: ^10 || ^12 || >=14}
1956 +
1957 + prelude-ls@1.2.1:
1958 + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
1959 + engines: {node: '>= 0.8.0'}
1960 +
1961 + prettier-plugin-astro@0.14.1:
1962 + resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==}
1963 + engines: {node: ^14.15.0 || >=16.0.0}
1964 +
1965 + prettier@3.6.2:
1966 + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
1967 + engines: {node: '>=14'}
1968 + hasBin: true
1969 +
1970 + prismjs@1.30.0:
1971 + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
1972 + engines: {node: '>=6'}
1973 +
1974 + prompts@2.4.2:
1975 + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
1976 + engines: {node: '>= 6'}
1977 +
1978 + property-information@6.5.0:
1979 + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
1980 +
1981 + property-information@7.1.0:
1982 + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
1983 +
1984 + punycode@2.3.1:
1985 + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
1986 + engines: {node: '>=6'}
1987 +
1988 + queue-microtask@1.2.3:
1989 + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1990 +
1991 + radix3@1.1.2:
1992 + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
1993 +
1994 + readdirp@4.1.2:
1995 + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
1996 + engines: {node: '>= 14.18.0'}
1997 +
1998 + reading-time@1.5.0:
1999 + resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==}
2000 +
2001 + recma-build-jsx@1.0.0:
2002 + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==}
2003 +
2004 + recma-jsx@1.0.0:
2005 + resolution: {integrity: sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==}
2006 +
2007 + recma-parse@1.0.0:
2008 + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==}
2009 +
2010 + recma-stringify@1.0.0:
2011 + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==}
2012 +
2013 + regex-recursion@6.0.2:
2014 + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
2015 +
2016 + regex-utilities@2.3.0:
2017 + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
2018 +
2019 + regex@6.0.1:
2020 + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==}
2021 +
2022 + rehype-katex@7.0.1:
2023 + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==}
2024 +
2025 + rehype-parse@9.0.1:
2026 + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==}
2027 +
2028 + rehype-raw@7.0.0:
2029 + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
2030 +
2031 + rehype-recma@1.0.0:
2032 + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==}
2033 +
2034 + rehype-stringify@10.0.1:
2035 + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==}
2036 +
2037 + rehype@13.0.2:
2038 + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==}
2039 +
2040 + remark-directive@4.0.0:
2041 + resolution: {integrity: sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==}
2042 +
2043 + remark-gfm@4.0.1:
2044 + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
2045 +
2046 + remark-math@6.0.0:
2047 + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==}
2048 +
2049 + remark-mdx@3.1.0:
2050 + resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==}
2051 +
2052 + remark-parse@11.0.0:
2053 + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
2054 +
2055 + remark-rehype@11.1.2:
2056 + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
2057 +
2058 + remark-smartypants@3.0.2:
2059 + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==}
2060 + engines: {node: '>=16.0.0'}
2061 +
2062 + remark-stringify@11.0.0:
2063 + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
2064 +
2065 + resolve-from@4.0.0:
2066 + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
2067 + engines: {node: '>=4'}
2068 +
2069 + resolve-pkg-maps@1.0.0:
2070 + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
2071 +
2072 + restructure@3.0.2:
2073 + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==}
2074 +
2075 + retext-latin@4.0.0:
2076 + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==}
2077 +
2078 + retext-smartypants@6.2.0:
2079 + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==}
2080 +
2081 + retext-stringify@4.0.0:
2082 + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==}
2083 +
2084 + retext@9.0.0:
2085 + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==}
2086 +
2087 + reusify@1.1.0:
2088 + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
2089 + engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
2090 +
2091 + rollup@4.44.1:
2092 + resolution: {integrity: sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==}
2093 + engines: {node: '>=18.0.0', npm: '>=8.0.0'}
2094 + hasBin: true
2095 +
2096 + run-parallel@1.2.0:
2097 + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
2098 +
2099 + s.color@0.0.15:
2100 + resolution: {integrity: sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==}
2101 +
2102 + sass-formatter@0.7.9:
2103 + resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
2104 +
2105 + sax@1.4.1:
2106 + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
2107 +
2108 + semver@7.7.2:
2109 + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
2110 + engines: {node: '>=10'}
2111 + hasBin: true
2112 +
2113 + sharp@0.34.3:
2114 + resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
2115 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
2116 +
2117 + shebang-command@2.0.0:
2118 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
2119 + engines: {node: '>=8'}
2120 +
2121 + shebang-regex@3.0.0:
2122 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
2123 + engines: {node: '>=8'}
2124 +
2125 + shiki@3.15.0:
2126 + resolution: {integrity: sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw==}
2127 +
2128 + simple-swizzle@0.2.2:
2129 + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
2130 +
2131 + sisteransi@1.0.5:
2132 + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
2133 +
2134 + sitemap@8.0.0:
2135 + resolution: {integrity: sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==}
2136 + engines: {node: '>=14.0.0', npm: '>=6.0.0'}
2137 + deprecated: 'SECURITY: Multiple vulnerabilities fixed in 8.0.1 (XML injection, path traversal, command injection, protocol injection). Upgrade immediately: npm install sitemap@8.0.1'
2138 + hasBin: true
2139 +
2140 + smol-toml@1.4.2:
2141 + resolution: {integrity: sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g==}
2142 + engines: {node: '>= 18'}
2143 +
2144 + source-map-js@1.2.1:
2145 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
2146 + engines: {node: '>=0.10.0'}
2147 +
2148 + source-map@0.7.6:
2149 + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
2150 + engines: {node: '>= 12'}
2151 +
2152 + space-separated-tokens@2.0.2:
2153 + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
2154 +
2155 + stream-replace-string@2.0.0:
2156 + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
2157 +
2158 + string-width@4.2.3:
2159 + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
2160 + engines: {node: '>=8'}
2161 +
2162 + string-width@7.2.0:
2163 + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
2164 + engines: {node: '>=18'}
2165 +
2166 + stringify-entities@4.0.4:
2167 + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
2168 +
2169 + strip-ansi@6.0.1:
2170 + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
2171 + engines: {node: '>=8'}
2172 +
2173 + strip-ansi@7.1.0:
2174 + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
2175 + engines: {node: '>=12'}
2176 +
2177 + strip-json-comments@3.1.1:
2178 + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
2179 + engines: {node: '>=8'}
2180 +
2181 + style-to-js@1.1.17:
2182 + resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==}
2183 +
2184 + style-to-object@1.0.9:
2185 + resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==}
2186 +
2187 + suf-log@2.5.3:
2188 + resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
2189 +
2190 + supports-color@7.2.0:
2191 + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
2192 + engines: {node: '>=8'}
2193 +
2194 + synckit@0.11.8:
2195 + resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==}
2196 + engines: {node: ^14.18.0 || >=16.0.0}
2197 +
2198 + tailwindcss@4.1.13:
2199 + resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==}
2200 +
2201 + tapable@2.2.3:
2202 + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
2203 + engines: {node: '>=6'}
2204 +
2205 + tar@7.5.1:
2206 + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==}
2207 + engines: {node: '>=18'}
2208 +
2209 + tiny-inflate@1.0.3:
2210 + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
2211 +
2212 + tinyexec@1.0.2:
2213 + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
2214 + engines: {node: '>=18'}
2215 +
2216 + tinyglobby@0.2.14:
2217 + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
2218 + engines: {node: '>=12.0.0'}
2219 +
2220 + to-regex-range@5.0.1:
2221 + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
2222 + engines: {node: '>=8.0'}
2223 +
2224 + trim-lines@3.0.1:
2225 + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
2226 +
2227 + trough@2.2.0:
2228 + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
2229 +
2230 + ts-api-utils@2.1.0:
2231 + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
2232 + engines: {node: '>=18.12'}
2233 + peerDependencies:
2234 + typescript: '>=4.8.4'
2235 +
2236 + tsconfck@3.1.6:
2237 + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
2238 + engines: {node: ^18 || >=20}
2239 + hasBin: true
2240 + peerDependencies:
2241 + typescript: ^5.0.0
2242 + peerDependenciesMeta:
2243 + typescript:
2244 + optional: true
2245 +
2246 + tslib@2.8.1:
2247 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
2248 +
2249 + tsx@4.20.3:
2250 + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==}
2251 + engines: {node: '>=18.0.0'}
2252 + hasBin: true
2253 +
2254 + type-check@0.4.0:
2255 + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
2256 + engines: {node: '>= 0.8.0'}
2257 +
2258 + type-fest@4.41.0:
2259 + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
2260 + engines: {node: '>=16'}
2261 +
2262 + typescript-eslint@8.36.0:
2263 + resolution: {integrity: sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==}
2264 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
2265 + peerDependencies:
2266 + eslint: ^8.57.0 || ^9.0.0
2267 + typescript: '>=4.8.4 <5.9.0'
2268 +
2269 + typescript@5.8.3:
2270 + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
2271 + engines: {node: '>=14.17'}
2272 + hasBin: true
2273 +
2274 + ufo@1.6.1:
2275 + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
2276 +
2277 + ultrahtml@1.6.0:
2278 + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
2279 +
2280 + uncrypto@0.1.3:
2281 + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
2282 +
2283 + undici-types@7.8.0:
2284 + resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
2285 +
2286 + unicode-properties@1.4.1:
2287 + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==}
2288 +
2289 + unicode-trie@2.0.0:
2290 + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
2291 +
2292 + unified@11.0.5:
2293 + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
2294 +
2295 + unifont@0.6.0:
2296 + resolution: {integrity: sha512-5Fx50fFQMQL5aeHyWnZX9122sSLckcDvcfFiBf3QYeHa7a1MKJooUy52b67moi2MJYkrfo/TWY+CoLdr/w0tTA==}
2297 +
2298 + unist-util-find-after@5.0.0:
2299 + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
2300 +
2301 + unist-util-is@6.0.0:
2302 + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
2303 +
2304 + unist-util-modify-children@4.0.0:
2305 + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==}
2306 +
2307 + unist-util-position-from-estree@2.0.0:
2308 + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==}
2309 +
2310 + unist-util-position@5.0.0:
2311 + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
2312 +
2313 + unist-util-remove-position@5.0.0:
2314 + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==}
2315 +
2316 + unist-util-stringify-position@4.0.0:
2317 + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
2318 +
2319 + unist-util-visit-children@3.0.0:
2320 + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==}
2321 +
2322 + unist-util-visit-parents@6.0.1:
2323 + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
2324 +
2325 + unist-util-visit@5.0.0:
2326 + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
2327 +
2328 + unstorage@1.17.2:
2329 + resolution: {integrity: sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w==}
2330 + peerDependencies:
2331 + '@azure/app-configuration': ^1.8.0
2332 + '@azure/cosmos': ^4.2.0
2333 + '@azure/data-tables': ^13.3.0
2334 + '@azure/identity': ^4.6.0
2335 + '@azure/keyvault-secrets': ^4.9.0
2336 + '@azure/storage-blob': ^12.26.0
2337 + '@capacitor/preferences': ^6.0.3 || ^7.0.0
2338 + '@deno/kv': '>=0.9.0'
2339 + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
2340 + '@planetscale/database': ^1.19.0
2341 + '@upstash/redis': ^1.34.3
2342 + '@vercel/blob': '>=0.27.1'
2343 + '@vercel/functions': ^2.2.12 || ^3.0.0
2344 + '@vercel/kv': ^1.0.1
2345 + aws4fetch: ^1.0.20
2346 + db0: '>=0.2.1'
2347 + idb-keyval: ^6.2.1
2348 + ioredis: ^5.4.2
2349 + uploadthing: ^7.4.4
2350 + peerDependenciesMeta:
2351 + '@azure/app-configuration':
2352 + optional: true
2353 + '@azure/cosmos':
2354 + optional: true
2355 + '@azure/data-tables':
2356 + optional: true
2357 + '@azure/identity':
2358 + optional: true
2359 + '@azure/keyvault-secrets':
2360 + optional: true
2361 + '@azure/storage-blob':
2362 + optional: true
2363 + '@capacitor/preferences':
2364 + optional: true
2365 + '@deno/kv':
2366 + optional: true
2367 + '@netlify/blobs':
2368 + optional: true
2369 + '@planetscale/database':
2370 + optional: true
2371 + '@upstash/redis':
2372 + optional: true
2373 + '@vercel/blob':
2374 + optional: true
2375 + '@vercel/functions':
2376 + optional: true
2377 + '@vercel/kv':
2378 + optional: true
2379 + aws4fetch:
2380 + optional: true
2381 + db0:
2382 + optional: true
2383 + idb-keyval:
2384 + optional: true
2385 + ioredis:
2386 + optional: true
2387 + uploadthing:
2388 + optional: true
2389 +
2390 + uri-js@4.4.1:
2391 + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
2392 +
2393 + util-deprecate@1.0.2:
2394 + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
2395 +
2396 + vfile-location@5.0.3:
2397 + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
2398 +
2399 + vfile-message@4.0.2:
2400 + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
2401 +
2402 + vfile@6.0.3:
2403 + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
2404 +
2405 + vite@6.4.1:
2406 + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
2407 + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
2408 + hasBin: true
2409 + peerDependencies:
2410 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
2411 + jiti: '>=1.21.0'
2412 + less: '*'
2413 + lightningcss: ^1.21.0
2414 + sass: '*'
2415 + sass-embedded: '*'
2416 + stylus: '*'
2417 + sugarss: '*'
2418 + terser: ^5.16.0
2419 + tsx: ^4.8.1
2420 + yaml: ^2.4.2
2421 + peerDependenciesMeta:
2422 + '@types/node':
2423 + optional: true
2424 + jiti:
2425 + optional: true
2426 + less:
2427 + optional: true
2428 + lightningcss:
2429 + optional: true
2430 + sass:
2431 + optional: true
2432 + sass-embedded:
2433 + optional: true
2434 + stylus:
2435 + optional: true
2436 + sugarss:
2437 + optional: true
2438 + terser:
2439 + optional: true
2440 + tsx:
2441 + optional: true
2442 + yaml:
2443 + optional: true
2444 +
2445 + vitefu@1.1.1:
2446 + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
2447 + peerDependencies:
2448 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
2449 + peerDependenciesMeta:
2450 + vite:
2451 + optional: true
2452 +
2453 + web-namespaces@2.0.1:
2454 + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
2455 +
2456 + which-pm-runs@1.1.0:
2457 + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==}
2458 + engines: {node: '>=4'}
2459 +
2460 + which@2.0.2:
2461 + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
2462 + engines: {node: '>= 8'}
2463 + hasBin: true
2464 +
2465 + widest-line@5.0.0:
2466 + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==}
2467 + engines: {node: '>=18'}
2468 +
2469 + word-wrap@1.2.5:
2470 + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
2471 + engines: {node: '>=0.10.0'}
2472 +
2473 + wrap-ansi@9.0.0:
2474 + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
2475 + engines: {node: '>=18'}
2476 +
2477 + xxhash-wasm@1.1.0:
2478 + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==}
2479 +
2480 + yallist@5.0.0:
2481 + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
2482 + engines: {node: '>=18'}
2483 +
2484 + yargs-parser@21.1.1:
2485 + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
2486 + engines: {node: '>=12'}
2487 +
2488 + yocto-queue@0.1.0:
2489 + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
2490 + engines: {node: '>=10'}
2491 +
2492 + yocto-queue@1.2.1:
2493 + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==}
2494 + engines: {node: '>=12.20'}
2495 +
2496 + yocto-spinner@0.2.3:
2497 + resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==}
2498 + engines: {node: '>=18.19'}
2499 +
2500 + yoctocolors@2.1.1:
2501 + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==}
2502 + engines: {node: '>=18'}
2503 +
2504 + zod-to-json-schema@3.24.6:
2505 + resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
2506 + peerDependencies:
2507 + zod: ^3.24.1
2508 +
2509 + zod-to-ts@1.2.0:
2510 + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
2511 + peerDependencies:
2512 + typescript: ^4.9.4 || ^5.0.2
2513 + zod: ^3
2514 +
2515 + zod@3.25.76:
2516 + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
2517 +
2518 + zwitch@2.0.4:
2519 + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
2520 +
2521 +snapshots:
2522 +
2523 + '@astrojs/compiler@2.12.2': {}
2524 +
2525 + '@astrojs/internal-helpers@0.7.4': {}
2526 +
2527 + '@astrojs/markdown-remark@6.3.8':
2528 + dependencies:
2529 + '@astrojs/internal-helpers': 0.7.4
2530 + '@astrojs/prism': 3.3.0
2531 + github-slugger: 2.0.0
2532 + hast-util-from-html: 2.0.3
2533 + hast-util-to-text: 4.0.2
2534 + import-meta-resolve: 4.2.0
2535 + js-yaml: 4.1.0
2536 + mdast-util-definitions: 6.0.0
2537 + rehype-raw: 7.0.0
2538 + rehype-stringify: 10.0.1
2539 + remark-gfm: 4.0.1
2540 + remark-parse: 11.0.0
2541 + remark-rehype: 11.1.2
2542 + remark-smartypants: 3.0.2
2543 + shiki: 3.15.0
2544 + smol-toml: 1.4.2
2545 + unified: 11.0.5
2546 + unist-util-remove-position: 5.0.0
2547 + unist-util-visit: 5.0.0
2548 + unist-util-visit-parents: 6.0.1
2549 + vfile: 6.0.3
2550 + transitivePeerDependencies:
2551 + - supports-color
2552 +
2553 + '@astrojs/mdx@4.3.10(astro@5.15.5(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(rollup@4.44.1)(tsx@4.20.3)(typescript@5.8.3))':
2554 + dependencies:
2555 + '@astrojs/markdown-remark': 6.3.8
2556 + '@mdx-js/mdx': 3.1.1
2557 + acorn: 8.15.0
2558 + astro: 5.15.5(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(rollup@4.44.1)(tsx@4.20.3)(typescript@5.8.3)
2559 + es-module-lexer: 1.7.0
2560 + estree-util-visit: 2.0.0
2561 + hast-util-to-html: 9.0.5
2562 + picocolors: 1.1.1
2563 + rehype-raw: 7.0.0
2564 + remark-gfm: 4.0.1
2565 + remark-smartypants: 3.0.2
2566 + source-map: 0.7.6
2567 + unist-util-visit: 5.0.0
2568 + vfile: 6.0.3
2569 + transitivePeerDependencies:
2570 + - supports-color
2571 +
2572 + '@astrojs/prism@3.3.0':
2573 + dependencies:
2574 + prismjs: 1.30.0
2575 +
2576 + '@astrojs/sitemap@3.6.0':
2577 + dependencies:
2578 + sitemap: 8.0.0
2579 + stream-replace-string: 2.0.0
2580 + zod: 3.25.76
2581 +
2582 + '@astrojs/telemetry@3.3.0':
2583 + dependencies:
2584 + ci-info: 4.3.1
2585 + debug: 4.4.1
2586 + dlv: 1.1.3
2587 + dset: 3.1.4
2588 + is-docker: 3.0.0
2589 + is-wsl: 3.1.0
2590 + which-pm-runs: 1.1.0
2591 + transitivePeerDependencies:
2592 + - supports-color
2593 +
2594 + '@babel/helper-string-parser@7.27.1': {}
2595 +
2596 + '@babel/helper-validator-identifier@7.27.1': {}
2597 +
2598 + '@babel/parser@7.28.0':
2599 + dependencies:
2600 + '@babel/types': 7.28.0
2601 +
2602 + '@babel/types@7.28.0':
2603 + dependencies:
2604 + '@babel/helper-string-parser': 7.27.1
2605 + '@babel/helper-validator-identifier': 7.27.1
2606 +
2607 + '@capsizecss/unpack@3.0.1':
2608 + dependencies:
2609 + fontkit: 2.0.4
2610 +
2611 + '@emnapi/runtime@1.4.4':
2612 + dependencies:
2613 + tslib: 2.8.1
2614 + optional: true
2615 +
2616 + '@esbuild/aix-ppc64@0.25.5':
2617 + optional: true
2618 +
2619 + '@esbuild/android-arm64@0.25.5':
2620 + optional: true
2621 +
2622 + '@esbuild/android-arm@0.25.5':
2623 + optional: true
2624 +
2625 + '@esbuild/android-x64@0.25.5':
2626 + optional: true
2627 +
2628 + '@esbuild/darwin-arm64@0.25.5':
2629 + optional: true
2630 +
2631 + '@esbuild/darwin-x64@0.25.5':
2632 + optional: true
2633 +
2634 + '@esbuild/freebsd-arm64@0.25.5':
2635 + optional: true
2636 +
2637 + '@esbuild/freebsd-x64@0.25.5':
2638 + optional: true
2639 +
2640 + '@esbuild/linux-arm64@0.25.5':
2641 + optional: true
2642 +
2643 + '@esbuild/linux-arm@0.25.5':
2644 + optional: true
2645 +
2646 + '@esbuild/linux-ia32@0.25.5':
2647 + optional: true
2648 +
2649 + '@esbuild/linux-loong64@0.25.5':
2650 + optional: true
2651 +
2652 + '@esbuild/linux-mips64el@0.25.5':
2653 + optional: true
2654 +
2655 + '@esbuild/linux-ppc64@0.25.5':
2656 + optional: true
2657 +
2658 + '@esbuild/linux-riscv64@0.25.5':
2659 + optional: true
2660 +
2661 + '@esbuild/linux-s390x@0.25.5':
2662 + optional: true
2663 +
2664 + '@esbuild/linux-x64@0.25.5':
2665 + optional: true
2666 +
2667 + '@esbuild/netbsd-arm64@0.25.5':
2668 + optional: true
2669 +
2670 + '@esbuild/netbsd-x64@0.25.5':
2671 + optional: true
2672 +
2673 + '@esbuild/openbsd-arm64@0.25.5':
2674 + optional: true
2675 +
2676 + '@esbuild/openbsd-x64@0.25.5':
2677 + optional: true
2678 +
2679 + '@esbuild/sunos-x64@0.25.5':
2680 + optional: true
2681 +
2682 + '@esbuild/win32-arm64@0.25.5':
2683 + optional: true
2684 +
2685 + '@esbuild/win32-ia32@0.25.5':
2686 + optional: true
2687 +
2688 + '@esbuild/win32-x64@0.25.5':
2689 + optional: true
2690 +
2691 + '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1(jiti@2.6.0))':
2692 + dependencies:
2693 + eslint: 9.30.1(jiti@2.6.0)
2694 + eslint-visitor-keys: 3.4.3
2695 +
2696 + '@eslint-community/regexpp@4.12.1': {}
2697 +
2698 + '@eslint/config-array@0.21.0':
2699 + dependencies:
2700 + '@eslint/object-schema': 2.1.6
2701 + debug: 4.4.1
2702 + minimatch: 3.1.2
2703 + transitivePeerDependencies:
2704 + - supports-color
2705 +
2706 + '@eslint/config-helpers@0.3.0': {}
2707 +
2708 + '@eslint/core@0.14.0':
2709 + dependencies:
2710 + '@types/json-schema': 7.0.15
2711 +
2712 + '@eslint/core@0.15.1':
2713 + dependencies:
2714 + '@types/json-schema': 7.0.15
2715 +
2716 + '@eslint/eslintrc@3.3.1':
2717 + dependencies:
2718 + ajv: 6.12.6
2719 + debug: 4.4.1
2720 + espree: 10.4.0
2721 + globals: 14.0.0
2722 + ignore: 5.3.2
2723 + import-fresh: 3.3.1
2724 + js-yaml: 4.1.0
2725 + minimatch: 3.1.2
2726 + strip-json-comments: 3.1.1
2727 + transitivePeerDependencies:
2728 + - supports-color
2729 +
2730 + '@eslint/js@9.30.1': {}
2731 +
2732 + '@eslint/object-schema@2.1.6': {}
2733 +
2734 + '@eslint/plugin-kit@0.3.3':
2735 + dependencies:
2736 + '@eslint/core': 0.15.1
2737 + levn: 0.4.1
2738 +
2739 + '@humanfs/core@0.19.1': {}
2740 +
2741 + '@humanfs/node@0.16.6':
2742 + dependencies:
2743 + '@humanfs/core': 0.19.1
2744 + '@humanwhocodes/retry': 0.3.1
2745 +
2746 + '@humanwhocodes/module-importer@1.0.1': {}
2747 +
2748 + '@humanwhocodes/retry@0.3.1': {}
2749 +
2750 + '@humanwhocodes/retry@0.4.3': {}
2751 +
2752 + '@img/sharp-darwin-arm64@0.34.3':
2753 + optionalDependencies:
2754 + '@img/sharp-libvips-darwin-arm64': 1.2.0
2755 + optional: true
2756 +
2757 + '@img/sharp-darwin-x64@0.34.3':
2758 + optionalDependencies:
2759 + '@img/sharp-libvips-darwin-x64': 1.2.0
2760 + optional: true
2761 +
2762 + '@img/sharp-libvips-darwin-arm64@1.2.0':
2763 + optional: true
2764 +
2765 + '@img/sharp-libvips-darwin-x64@1.2.0':
2766 + optional: true
2767 +
2768 + '@img/sharp-libvips-linux-arm64@1.2.0':
2769 + optional: true
2770 +
2771 + '@img/sharp-libvips-linux-arm@1.2.0':
2772 + optional: true
2773 +
2774 + '@img/sharp-libvips-linux-ppc64@1.2.0':
2775 + optional: true
2776 +
2777 + '@img/sharp-libvips-linux-s390x@1.2.0':
2778 + optional: true
2779 +
2780 + '@img/sharp-libvips-linux-x64@1.2.0':
2781 + optional: true
2782 +
2783 + '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
2784 + optional: true
2785 +
2786 + '@img/sharp-libvips-linuxmusl-x64@1.2.0':
2787 + optional: true
2788 +
2789 + '@img/sharp-linux-arm64@0.34.3':
2790 + optionalDependencies:
2791 + '@img/sharp-libvips-linux-arm64': 1.2.0
2792 + optional: true
2793 +
2794 + '@img/sharp-linux-arm@0.34.3':
2795 + optionalDependencies:
2796 + '@img/sharp-libvips-linux-arm': 1.2.0
2797 + optional: true
2798 +
2799 + '@img/sharp-linux-ppc64@0.34.3':
2800 + optionalDependencies:
2801 + '@img/sharp-libvips-linux-ppc64': 1.2.0
2802 + optional: true
2803 +
2804 + '@img/sharp-linux-s390x@0.34.3':
2805 + optionalDependencies:
2806 + '@img/sharp-libvips-linux-s390x': 1.2.0
2807 + optional: true
2808 +
2809 + '@img/sharp-linux-x64@0.34.3':
2810 + optionalDependencies:
2811 + '@img/sharp-libvips-linux-x64': 1.2.0
2812 + optional: true
2813 +
2814 + '@img/sharp-linuxmusl-arm64@0.34.3':
2815 + optionalDependencies:
2816 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.0
2817 + optional: true
2818 +
2819 + '@img/sharp-linuxmusl-x64@0.34.3':
2820 + optionalDependencies:
2821 + '@img/sharp-libvips-linuxmusl-x64': 1.2.0
2822 + optional: true
2823 +
2824 + '@img/sharp-wasm32@0.34.3':
2825 + dependencies:
2826 + '@emnapi/runtime': 1.4.4
2827 + optional: true
2828 +
2829 + '@img/sharp-win32-arm64@0.34.3':
2830 + optional: true
2831 +
2832 + '@img/sharp-win32-ia32@0.34.3':
2833 + optional: true
2834 +
2835 + '@img/sharp-win32-x64@0.34.3':
2836 + optional: true
2837 +
2838 + '@isaacs/fs-minipass@4.0.1':
2839 + dependencies:
2840 + minipass: 7.1.2
2841 +
2842 + '@jridgewell/gen-mapping@0.3.13':
2843 + dependencies:
2844 + '@jridgewell/sourcemap-codec': 1.5.4
2845 + '@jridgewell/trace-mapping': 0.3.31
2846 +
2847 + '@jridgewell/remapping@2.3.5':
2848 + dependencies:
2849 + '@jridgewell/gen-mapping': 0.3.13
2850 + '@jridgewell/trace-mapping': 0.3.31
2851 +
2852 + '@jridgewell/resolve-uri@3.1.2': {}
2853 +
2854 + '@jridgewell/sourcemap-codec@1.5.4': {}
2855 +
2856 + '@jridgewell/sourcemap-codec@1.5.5': {}
2857 +
2858 + '@jridgewell/trace-mapping@0.3.31':
2859 + dependencies:
2860 + '@jridgewell/resolve-uri': 3.1.2
2861 + '@jridgewell/sourcemap-codec': 1.5.4
2862 +
2863 + '@mdx-js/mdx@3.1.1':
2864 + dependencies:
2865 + '@types/estree': 1.0.8
2866 + '@types/estree-jsx': 1.0.5
2867 + '@types/hast': 3.0.4
2868 + '@types/mdx': 2.0.13
2869 + acorn: 8.15.0
2870 + collapse-white-space: 2.1.0
2871 + devlop: 1.1.0
2872 + estree-util-is-identifier-name: 3.0.0
2873 + estree-util-scope: 1.0.0
2874 + estree-walker: 3.0.3
2875 + hast-util-to-jsx-runtime: 2.3.6
2876 + markdown-extensions: 2.0.0
2877 + recma-build-jsx: 1.0.0
2878 + recma-jsx: 1.0.0(acorn@8.15.0)
2879 + recma-stringify: 1.0.0
2880 + rehype-recma: 1.0.0
2881 + remark-mdx: 3.1.0
2882 + remark-parse: 11.0.0
2883 + remark-rehype: 11.1.2
2884 + source-map: 0.7.6
2885 + unified: 11.0.5
2886 + unist-util-position-from-estree: 2.0.0
2887 + unist-util-stringify-position: 4.0.0
2888 + unist-util-visit: 5.0.0
2889 + vfile: 6.0.3
2890 + transitivePeerDependencies:
2891 + - supports-color
2892 +
2893 + '@nodelib/fs.scandir@2.1.5':
2894 + dependencies:
2895 + '@nodelib/fs.stat': 2.0.5
2896 + run-parallel: 1.2.0
2897 +
2898 + '@nodelib/fs.stat@2.0.5': {}
2899 +
2900 + '@nodelib/fs.walk@1.2.8':
2901 + dependencies:
2902 + '@nodelib/fs.scandir': 2.1.5
2903 + fastq: 1.19.1
2904 +
2905 + '@oslojs/encoding@1.1.0': {}
2906 +
2907 + '@pkgr/core@0.2.7': {}
2908 +
2909 + '@rollup/pluginutils@5.2.0(rollup@4.44.1)':
2910 + dependencies:
2911 + '@types/estree': 1.0.8
2912 + estree-walker: 2.0.2
2913 + picomatch: 4.0.3
2914 + optionalDependencies:
2915 + rollup: 4.44.1
2916 +
2917 + '@rollup/rollup-android-arm-eabi@4.44.1':
2918 + optional: true
2919 +
2920 + '@rollup/rollup-android-arm64@4.44.1':
2921 + optional: true
2922 +
2923 + '@rollup/rollup-darwin-arm64@4.44.1':
2924 + optional: true
2925 +
2926 + '@rollup/rollup-darwin-x64@4.44.1':
2927 + optional: true
2928 +
2929 + '@rollup/rollup-freebsd-arm64@4.44.1':
2930 + optional: true
2931 +
2932 + '@rollup/rollup-freebsd-x64@4.44.1':
2933 + optional: true
2934 +
2935 + '@rollup/rollup-linux-arm-gnueabihf@4.44.1':
2936 + optional: true
2937 +
2938 + '@rollup/rollup-linux-arm-musleabihf@4.44.1':
2939 + optional: true
2940 +
2941 + '@rollup/rollup-linux-arm64-gnu@4.44.1':
2942 + optional: true
2943 +
2944 + '@rollup/rollup-linux-arm64-musl@4.44.1':
2945 + optional: true
2946 +
2947 + '@rollup/rollup-linux-loongarch64-gnu@4.44.1':
2948 + optional: true
2949 +
2950 + '@rollup/rollup-linux-powerpc64le-gnu@4.44.1':
2951 + optional: true
2952 +
2953 + '@rollup/rollup-linux-riscv64-gnu@4.44.1':
2954 + optional: true
2955 +
2956 + '@rollup/rollup-linux-riscv64-musl@4.44.1':
2957 + optional: true
2958 +
2959 + '@rollup/rollup-linux-s390x-gnu@4.44.1':
2960 + optional: true
2961 +
2962 + '@rollup/rollup-linux-x64-gnu@4.44.1':
2963 + optional: true
2964 +
2965 + '@rollup/rollup-linux-x64-musl@4.44.1':
2966 + optional: true
2967 +
2968 + '@rollup/rollup-win32-arm64-msvc@4.44.1':
2969 + optional: true
2970 +
2971 + '@rollup/rollup-win32-ia32-msvc@4.44.1':
2972 + optional: true
2973 +
2974 + '@rollup/rollup-win32-x64-msvc@4.44.1':
2975 + optional: true
2976 +
2977 + '@shikijs/core@3.15.0':
2978 + dependencies:
2979 + '@shikijs/types': 3.15.0
2980 + '@shikijs/vscode-textmate': 10.0.2
2981 + '@types/hast': 3.0.4
2982 + hast-util-to-html: 9.0.5
2983 +
2984 + '@shikijs/engine-javascript@3.15.0':
2985 + dependencies:
2986 + '@shikijs/types': 3.15.0
2987 + '@shikijs/vscode-textmate': 10.0.2
2988 + oniguruma-to-es: 4.3.3
2989 +
2990 + '@shikijs/engine-oniguruma@3.15.0':
2991 + dependencies:
2992 + '@shikijs/types': 3.15.0
2993 + '@shikijs/vscode-textmate': 10.0.2
2994 +
2995 + '@shikijs/langs@3.15.0':
2996 + dependencies:
2997 + '@shikijs/types': 3.15.0
2998 +
2999 + '@shikijs/themes@3.15.0':
3000 + dependencies:
3001 + '@shikijs/types': 3.15.0
3002 +
3003 + '@shikijs/types@3.15.0':
3004 + dependencies:
3005 + '@shikijs/vscode-textmate': 10.0.2
3006 + '@types/hast': 3.0.4
3007 +
3008 + '@shikijs/vscode-textmate@10.0.2': {}
3009 +
3010 + '@swc/helpers@0.5.17':
3011 + dependencies:
3012 + tslib: 2.8.1
3013 +
3014 + '@tailwindcss/node@4.1.13':
3015 + dependencies:
3016 + '@jridgewell/remapping': 2.3.5
3017 + enhanced-resolve: 5.18.3
3018 + jiti: 2.6.0
3019 + lightningcss: 1.30.1
3020 + magic-string: 0.30.19
3021 + source-map-js: 1.2.1
3022 + tailwindcss: 4.1.13
3023 +
3024 + '@tailwindcss/oxide-android-arm64@4.1.13':
3025 + optional: true
3026 +
3027 + '@tailwindcss/oxide-darwin-arm64@4.1.13':
3028 + optional: true
3029 +
3030 + '@tailwindcss/oxide-darwin-x64@4.1.13':
3031 + optional: true
3032 +
3033 + '@tailwindcss/oxide-freebsd-x64@4.1.13':
3034 + optional: true
3035 +
3036 + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
3037 + optional: true
3038 +
3039 + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
3040 + optional: true
3041 +
3042 + '@tailwindcss/oxide-linux-arm64-musl@4.1.13':
3043 + optional: true
3044 +
3045 + '@tailwindcss/oxide-linux-x64-gnu@4.1.13':
3046 + optional: true
3047 +
3048 + '@tailwindcss/oxide-linux-x64-musl@4.1.13':
3049 + optional: true
3050 +
3051 + '@tailwindcss/oxide-wasm32-wasi@4.1.13':
3052 + optional: true
3053 +
3054 + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
3055 + optional: true
3056 +
3057 + '@tailwindcss/oxide-win32-x64-msvc@4.1.13':
3058 + optional: true
3059 +
3060 + '@tailwindcss/oxide@4.1.13':
3061 + dependencies:
3062 + detect-libc: 2.0.4
3063 + tar: 7.5.1
3064 + optionalDependencies:
3065 + '@tailwindcss/oxide-android-arm64': 4.1.13
3066 + '@tailwindcss/oxide-darwin-arm64': 4.1.13
3067 + '@tailwindcss/oxide-darwin-x64': 4.1.13
3068 + '@tailwindcss/oxide-freebsd-x64': 4.1.13
3069 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13
3070 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13
3071 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.13
3072 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.13
3073 + '@tailwindcss/oxide-linux-x64-musl': 4.1.13
3074 + '@tailwindcss/oxide-wasm32-wasi': 4.1.13
3075 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13
3076 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.13
3077 +
3078 + '@tailwindcss/vite@4.1.13(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.20.3))':
3079 + dependencies:
3080 + '@tailwindcss/node': 4.1.13
3081 + '@tailwindcss/oxide': 4.1.13
3082 + tailwindcss: 4.1.13
3083 + vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.20.3)
3084 +
3085 + '@types/debug@4.1.12':
3086 + dependencies:
3087 + '@types/ms': 2.1.0
3088 +
3089 + '@types/estree-jsx@1.0.5':
3090 + dependencies:
3091 + '@types/estree': 1.0.8
3092 +
3093 + '@types/estree@1.0.8': {}
3094 +
3095 + '@types/fontkit@2.0.8':
3096 + dependencies:
3097 + '@types/node': 24.0.10
3098 +
3099 + '@types/hast@3.0.4':
3100 + dependencies:
3101 + '@types/unist': 3.0.3
3102 +
3103 + '@types/json-schema@7.0.15': {}
3104 +
3105 + '@types/katex@0.16.7': {}
3106 +
3107 + '@types/mdast@4.0.4':
3108 + dependencies:
3109 + '@types/unist': 3.0.3
3110 +
3111 + '@types/mdx@2.0.13': {}
3112 +
3113 + '@types/ms@2.1.0': {}
3114 +
3115 + '@types/nlcst@2.0.3':
3116 + dependencies:
3117 + '@types/unist': 3.0.3
3118 +
3119 + '@types/node@17.0.45': {}
3120 +
3121 + '@types/node@24.0.10':
3122 + dependencies:
3123 + undici-types: 7.8.0
3124 +
3125 + '@types/sax@1.2.7':
3126 + dependencies:
3127 + '@types/node': 24.0.10
3128 +
3129 + '@types/unist@2.0.11': {}
3130 +
3131 + '@types/unist@3.0.3': {}
3132 +
3133 + '@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3134 + dependencies:
3135 + '@eslint-community/regexpp': 4.12.1
3136 + '@typescript-eslint/parser': 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3137 + '@typescript-eslint/scope-manager': 8.35.1
3138 + '@typescript-eslint/type-utils': 8.35.1(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3139 + '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3140 + '@typescript-eslint/visitor-keys': 8.35.1
3141 + eslint: 9.30.1(jiti@2.6.0)
3142 + graphemer: 1.4.0
3143 + ignore: 7.0.5
3144 + natural-compare: 1.4.0
3145 + ts-api-utils: 2.1.0(typescript@5.8.3)
3146 + typescript: 5.8.3
3147 + transitivePeerDependencies:
3148 + - supports-color
3149 +
3150 + '@typescript-eslint/eslint-plugin@8.36.0(@typescript-eslint/parser@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3151 + dependencies:
3152 + '@eslint-community/regexpp': 4.12.1
3153 + '@typescript-eslint/parser': 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3154 + '@typescript-eslint/scope-manager': 8.36.0
3155 + '@typescript-eslint/type-utils': 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3156 + '@typescript-eslint/utils': 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3157 + '@typescript-eslint/visitor-keys': 8.36.0
3158 + eslint: 9.30.1(jiti@2.6.0)
3159 + graphemer: 1.4.0
3160 + ignore: 7.0.5
3161 + natural-compare: 1.4.0
3162 + ts-api-utils: 2.1.0(typescript@5.8.3)
3163 + typescript: 5.8.3
3164 + transitivePeerDependencies:
3165 + - supports-color
3166 +
3167 + '@typescript-eslint/parser@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3168 + dependencies:
3169 + '@typescript-eslint/scope-manager': 8.36.0
3170 + '@typescript-eslint/types': 8.36.0
3171 + '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3)
3172 + '@typescript-eslint/visitor-keys': 8.36.0
3173 + debug: 4.4.1
3174 + eslint: 9.30.1(jiti@2.6.0)
3175 + typescript: 5.8.3
3176 + transitivePeerDependencies:
3177 + - supports-color
3178 +
3179 + '@typescript-eslint/project-service@8.35.1(typescript@5.8.3)':
3180 + dependencies:
3181 + '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3)
3182 + '@typescript-eslint/types': 8.36.0
3183 + debug: 4.4.1
3184 + typescript: 5.8.3
3185 + transitivePeerDependencies:
3186 + - supports-color
3187 +
3188 + '@typescript-eslint/project-service@8.36.0(typescript@5.8.3)':
3189 + dependencies:
3190 + '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3)
3191 + '@typescript-eslint/types': 8.36.0
3192 + debug: 4.4.1
3193 + typescript: 5.8.3
3194 + transitivePeerDependencies:
3195 + - supports-color
3196 +
3197 + '@typescript-eslint/scope-manager@8.35.1':
3198 + dependencies:
3199 + '@typescript-eslint/types': 8.35.1
3200 + '@typescript-eslint/visitor-keys': 8.35.1
3201 +
3202 + '@typescript-eslint/scope-manager@8.36.0':
3203 + dependencies:
3204 + '@typescript-eslint/types': 8.36.0
3205 + '@typescript-eslint/visitor-keys': 8.36.0
3206 +
3207 + '@typescript-eslint/tsconfig-utils@8.35.1(typescript@5.8.3)':
3208 + dependencies:
3209 + typescript: 5.8.3
3210 +
3211 + '@typescript-eslint/tsconfig-utils@8.36.0(typescript@5.8.3)':
3212 + dependencies:
3213 + typescript: 5.8.3
3214 +
3215 + '@typescript-eslint/type-utils@8.35.1(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3216 + dependencies:
3217 + '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3)
3218 + '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3219 + debug: 4.4.1
3220 + eslint: 9.30.1(jiti@2.6.0)
3221 + ts-api-utils: 2.1.0(typescript@5.8.3)
3222 + typescript: 5.8.3
3223 + transitivePeerDependencies:
3224 + - supports-color
3225 +
3226 + '@typescript-eslint/type-utils@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3227 + dependencies:
3228 + '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3)
3229 + '@typescript-eslint/utils': 8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)
3230 + debug: 4.4.1
3231 + eslint: 9.30.1(jiti@2.6.0)
3232 + ts-api-utils: 2.1.0(typescript@5.8.3)
3233 + typescript: 5.8.3
3234 + transitivePeerDependencies:
3235 + - supports-color
3236 +
3237 + '@typescript-eslint/types@8.35.1': {}
3238 +
3239 + '@typescript-eslint/types@8.36.0': {}
3240 +
3241 + '@typescript-eslint/typescript-estree@8.35.1(typescript@5.8.3)':
3242 + dependencies:
3243 + '@typescript-eslint/project-service': 8.35.1(typescript@5.8.3)
3244 + '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.8.3)
3245 + '@typescript-eslint/types': 8.35.1
3246 + '@typescript-eslint/visitor-keys': 8.35.1
3247 + debug: 4.4.1
3248 + fast-glob: 3.3.3
3249 + is-glob: 4.0.3
3250 + minimatch: 9.0.5
3251 + semver: 7.7.2
3252 + ts-api-utils: 2.1.0(typescript@5.8.3)
3253 + typescript: 5.8.3
3254 + transitivePeerDependencies:
3255 + - supports-color
3256 +
3257 + '@typescript-eslint/typescript-estree@8.36.0(typescript@5.8.3)':
3258 + dependencies:
3259 + '@typescript-eslint/project-service': 8.36.0(typescript@5.8.3)
3260 + '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3)
3261 + '@typescript-eslint/types': 8.36.0
3262 + '@typescript-eslint/visitor-keys': 8.36.0
3263 + debug: 4.4.1
3264 + fast-glob: 3.3.3
3265 + is-glob: 4.0.3
3266 + minimatch: 9.0.5
3267 + semver: 7.7.2
3268 + ts-api-utils: 2.1.0(typescript@5.8.3)
3269 + typescript: 5.8.3
3270 + transitivePeerDependencies:
3271 + - supports-color
3272 +
3273 + '@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3274 + dependencies:
3275 + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.0))
3276 + '@typescript-eslint/scope-manager': 8.35.1
3277 + '@typescript-eslint/types': 8.35.1
3278 + '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3)
3279 + eslint: 9.30.1(jiti@2.6.0)
3280 + typescript: 5.8.3
3281 + transitivePeerDependencies:
3282 + - supports-color
3283 +
3284 + '@typescript-eslint/utils@8.36.0(eslint@9.30.1(jiti@2.6.0))(typescript@5.8.3)':
3285 + dependencies:
3286 + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.0))
3287 + '@typescript-eslint/scope-manager': 8.36.0
3288 + '@typescript-eslint/types': 8.36.0
3289 + '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3)
3290 + eslint: 9.30.1(jiti@2.6.0)
3291 + typescript: 5.8.3
3292 + transitivePeerDependencies:
3293 + - supports-color
3294 +
3295 + '@typescript-eslint/visitor-keys@8.35.1':
3296 + dependencies:
3297 + '@typescript-eslint/types': 8.35.1
3298 + eslint-visitor-keys: 4.2.1
3299 +
3300 + '@typescript-eslint/visitor-keys@8.36.0':
3301 + dependencies:
3302 + '@typescript-eslint/types': 8.36.0
3303 + eslint-visitor-keys: 4.2.1
3304 +
3305 + '@ungap/structured-clone@1.3.0': {}
3306 +
3307 + acorn-jsx@5.3.2(acorn@8.15.0):
3308 + dependencies:
3309 + acorn: 8.15.0
3310 +
3311 + acorn@8.15.0: {}
3312 +
3313 + ajv@6.12.6:
3314 + dependencies:
3315 + fast-deep-equal: 3.1.3
3316 + fast-json-stable-stringify: 2.1.0
3317 + json-schema-traverse: 0.4.1
3318 + uri-js: 4.4.1
3319 +
3320 + ansi-align@3.0.1:
3321 + dependencies:
3322 + string-width: 4.2.3
3323 +
3324 + ansi-regex@5.0.1: {}
3325 +
3326 + ansi-regex@6.1.0: {}
3327 +
3328 + ansi-styles@4.3.0:
3329 + dependencies:
3330 + color-convert: 2.0.1
3331 +
3332 + ansi-styles@6.2.1: {}
3333 +
3334 + anymatch@3.1.3:
3335 + dependencies:
3336 + normalize-path: 3.0.0
3337 + picomatch: 2.3.1
3338 +
3339 + arg@5.0.2: {}
3340 +
3341 + argparse@2.0.1: {}
3342 +
3343 + aria-query@5.3.2: {}
3344 +
3345 + array-iterate@2.0.1: {}
3346 +
3347 + astring@1.9.0: {}
3348 +
3349 + astro-eslint-parser@1.2.2:
3350 + dependencies:
3351 + '@astrojs/compiler': 2.12.2
3352 + '@typescript-eslint/scope-manager': 8.36.0
3353 + '@typescript-eslint/types': 8.35.1
3354 + astrojs-compiler-sync: 1.1.1(@astrojs/compiler@2.12.2)
3355 + debug: 4.4.1
3356 + entities: 6.0.1
3357 + eslint-scope: 8.4.0
3358 + eslint-visitor-keys: 4.2.1
3359 + espree: 10.4.0
3360 + fast-glob: 3.3.3
3361 + is-glob: 4.0.3
3362 + semver: 7.7.2
3363 + transitivePeerDependencies:
3364 + - supports-color
3365 +
3366 + astro@5.15.5(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(rollup@4.44.1)(tsx@4.20.3)(typescript@5.8.3):
3367 + dependencies:
3368 + '@astrojs/compiler': 2.12.2
3369 + '@astrojs/internal-helpers': 0.7.4
3370 + '@astrojs/markdown-remark': 6.3.8
3371 + '@astrojs/telemetry': 3.3.0
3372 + '@capsizecss/unpack': 3.0.1
3373 + '@oslojs/encoding': 1.1.0
3374 + '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
3375 + acorn: 8.15.0
3376 + aria-query: 5.3.2
3377 + axobject-query: 4.1.0
3378 + boxen: 8.0.1
3379 + ci-info: 4.3.1
3380 + clsx: 2.1.1
3381 + common-ancestor-path: 1.0.1
3382 + cookie: 1.0.2
3383 + cssesc: 3.0.0
3384 + debug: 4.4.1
3385 + deterministic-object-hash: 2.0.2
3386 + devalue: 5.5.0
3387 + diff: 5.2.0
3388 + dlv: 1.1.3
3389 + dset: 3.1.4
3390 + es-module-lexer: 1.7.0
3391 + esbuild: 0.25.5
3392 + estree-walker: 3.0.3
3393 + flattie: 1.1.1
3394 + fontace: 0.3.0
3395 + github-slugger: 2.0.0
3396 + html-escaper: 3.0.3
3397 + http-cache-semantics: 4.2.0
3398 + import-meta-resolve: 4.2.0
3399 + js-yaml: 4.1.0
3400 + magic-string: 0.30.19
3401 + magicast: 0.3.5
3402 + mrmime: 2.0.1
3403 + neotraverse: 0.6.18
3404 + p-limit: 6.2.0
3405 + p-queue: 8.1.0
3406 + package-manager-detector: 1.3.0
3407 + picocolors: 1.1.1
3408 + picomatch: 4.0.3
3409 + prompts: 2.4.2
3410 + rehype: 13.0.2
3411 + semver: 7.7.2
3412 + shiki: 3.15.0
3413 + smol-toml: 1.4.2
3414 + tinyexec: 1.0.2
3415 + tinyglobby: 0.2.14
3416 + tsconfck: 3.1.6(typescript@5.8.3)
3417 + ultrahtml: 1.6.0
3418 + unifont: 0.6.0
3419 + unist-util-visit: 5.0.0
3420 + unstorage: 1.17.2
3421 + vfile: 6.0.3
3422 + vite: 6.4.1(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.20.3)
3423 + vitefu: 1.1.1(vite@6.4.1(@types/node@24.0.10)(jiti@2.6.0)(lightningcss@1.30.1)(tsx@4.20.3))
3424 + xxhash-wasm: 1.1.0
3425 + yargs-parser: 21.1.1
3426 + yocto-spinner: 0.2.3
3427 + zod: 3.25.76
3428 + zod-to-json-schema: 3.24.6(zod@3.25.76)
3429 + zod-to-ts: 1.2.0(typescript@5.8.3)(zod@3.25.76)
3430 + optionalDependencies:
3431 + sharp: 0.34.3
3432 + transitivePeerDependencies:
3433 + - '@azure/app-configuration'
3434 + - '@azure/cosmos'
3435 + - '@azure/data-tables'
3436 + - '@azure/identity'
3437 + - '@azure/keyvault-secrets'
3438 + - '@azure/storage-blob'
3439 + - '@capacitor/preferences'
3440 + - '@deno/kv'
3441 + - '@netlify/blobs'
3442 + - '@planetscale/database'
3443 + - '@types/node'
3444 + - '@upstash/redis'
3445 + - '@vercel/blob'
3446 + - '@vercel/functions'
3447 + - '@vercel/kv'
3448 + - aws4fetch
3449 + - db0
3450 + - idb-keyval
3451 + - ioredis
3452 + - jiti
3453 + - less
3454 + - lightningcss
3455 + - rollup
3456 + - sass
3457 + - sass-embedded
3458 + - stylus
3459 + - sugarss
3460 + - supports-color
3461 + - terser
3462 + - tsx
3463 + - typescript
3464 + - uploadthing
3465 + - yaml
3466 +
3467 + astrojs-compiler-sync@1.1.1(@astrojs/compiler@2.12.2):
3468 + dependencies:
3469 + '@astrojs/compiler': 2.12.2
3470 + synckit: 0.11.8
3471 +
3472 + axobject-query@4.1.0: {}
3473 +
3474 + bail@2.0.2: {}
3475 +
3476 + balanced-match@1.0.2: {}
3477 +
3478 + base-64@1.0.0: {}
3479 +
3480 + base64-js@1.5.1: {}
3481 +
3482 + boxen@8.0.1:
3483 + dependencies:
3484 + ansi-align: 3.0.1
3485 + camelcase: 8.0.0
3486 + chalk: 5.4.1
3487 + cli-boxes: 3.0.0
3488 + string-width: 7.2.0
3489 + type-fest: 4.41.0
3490 + widest-line: 5.0.0
3491 + wrap-ansi: 9.0.0
3492 +
3493 + brace-expansion@1.1.12:
3494 + dependencies:
3495 + balanced-match: 1.0.2
3496 + concat-map: 0.0.1
3497 +
3498 + brace-expansion@2.0.2:
3499 + dependencies:
3500 + balanced-match: 1.0.2
3501 +
3502 + braces@3.0.3:
3503 + dependencies:
3504 + fill-range: 7.1.1
3505 +
3506 + brotli@1.3.3:
3507 + dependencies:
3508 + base64-js: 1.5.1
3509 +
3510 + callsites@3.1.0: {}
3511 +
3512 + camelcase@8.0.0: {}
3513 +
3514 + ccount@2.0.1: {}
3515 +
3516 + chalk@4.1.2:
3517 + dependencies:
3518 + ansi-styles: 4.3.0
3519 + supports-color: 7.2.0
3520 +
3521 + chalk@5.4.1: {}
3522 +
3523 + character-entities-html4@2.1.0: {}
3524 +
3525 + character-entities-legacy@3.0.0: {}
3526 +
3527 + character-entities@2.0.2: {}
3528 +
3529 + character-reference-invalid@2.0.1: {}
3530 +
3531 + chokidar@4.0.3:
3532 + dependencies:
3533 + readdirp: 4.1.2
3534 +
3535 + chownr@3.0.0: {}
3536 +
3537 + ci-info@4.3.1: {}
3538 +
3539 + cli-boxes@3.0.0: {}
3540 +
3541 + clone@2.1.2: {}
3542 +
3543 + clsx@2.1.1: {}
3544 +
3545 + collapse-white-space@2.1.0: {}
3546 +
3547 + color-convert@2.0.1:
3548 + dependencies:
3549 + color-name: 1.1.4
3550 +
3551 + color-name@1.1.4: {}
3552 +
3553 + color-string@1.9.1:
3554 + dependencies:
3555 + color-name: 1.1.4
3556 + simple-swizzle: 0.2.2
3557 +
3558 + color@4.2.3:
3559 + dependencies:
3560 + color-convert: 2.0.1
3561 + color-string: 1.9.1
3562 +
3563 + comma-separated-tokens@2.0.3: {}
3564 +
3565 + commander@8.3.0: {}
3566 +
3567 + common-ancestor-path@1.0.1: {}
3568 +
3569 + concat-map@0.0.1: {}
3570 +
3571 + cookie-es@1.2.2: {}
3572 +
3573 + cookie@1.0.2: {}
3574 +
3575 + cross-spawn@7.0.6:
3576 + dependencies:
3577 + path-key: 3.1.1
3578 + shebang-command: 2.0.0
3579 + which: 2.0.2
3580 +
3581 + crossws@0.3.5:
3582 + dependencies:
3583 + uncrypto: 0.1.3
3584 +
3585 + css-tree@3.1.0:
3586 + dependencies:
3587 + mdn-data: 2.12.2
3588 + source-map-js: 1.2.1
3589 +
3590 + cssesc@3.0.0: {}
3591 +
3592 + debug@4.4.1:
3593 + dependencies:
3594 + ms: 2.1.3
3595 +
3596 + decode-named-character-reference@1.2.0:
3597 + dependencies:
3598 + character-entities: 2.0.2
3599 +
3600 + deep-is@0.1.4: {}
3601 +
3602 + defu@6.1.4: {}
3603 +
3604 + dequal@2.0.3: {}
3605 +
3606 + destr@2.0.5: {}
3607 +
3608 + detect-libc@2.0.4: {}
3609 +
3610 + deterministic-object-hash@2.0.2:
3611 + dependencies:
3612 + base-64: 1.0.0
3613 +
3614 + devalue@5.5.0: {}
3615 +
3616 + devlop@1.1.0:
3617 + dependencies:
3618 + dequal: 2.0.3
3619 +
3620 + dfa@1.2.0: {}
3621 +
3622 + diff@5.2.0: {}
3623 +
3624 + dlv@1.1.3: {}
3625 +
3626 + dset@3.1.4: {}
3627 +
3628 + emoji-regex@10.4.0: {}
3629 +
3630 + emoji-regex@8.0.0: {}
3631 +
3632 + enhanced-resolve@5.18.3:
3633 + dependencies:
3634 + graceful-fs: 4.2.11
3635 + tapable: 2.2.3
3636 +
3637 + entities@6.0.1: {}
3638 +
3639 + es-module-lexer@1.7.0: {}
3640 +
3641 + esast-util-from-estree@2.0.0:
3642 + dependencies:
3643 + '@types/estree-jsx': 1.0.5
3644 + devlop: 1.1.0
3645 + estree-util-visit: 2.0.0
3646 + unist-util-position-from-estree: 2.0.0
3647 +
3648 + esast-util-from-js@2.0.1:
3649 + dependencies:
3650 + '@types/estree-jsx': 1.0.5
3651 + acorn: 8.15.0
3652 + esast-util-from-estree: 2.0.0
3653 + vfile-message: 4.0.2
3654 +
3655 + esbuild@0.25.5:
3656 + optionalDependencies:
3657 + '@esbuild/aix-ppc64': 0.25.5
3658 + '@esbuild/android-arm': 0.25.5
3659 + '@esbuild/android-arm64': 0.25.5
3660 + '@esbuild/android-x64': 0.25.5
3661 + '@esbuild/darwin-arm64': 0.25.5
3662 + '@esbuild/darwin-x64': 0.25.5
3663 + '@esbuild/freebsd-arm64': 0.25.5
3664 + '@esbuild/freebsd-x64': 0.25.5
3665 + '@esbuild/linux-arm': 0.25.5
3666 + '@esbuild/linux-arm64': 0.25.5
3667 + '@esbuild/linux-ia32': 0.25.5
3668 + '@esbuild/linux-loong64': 0.25.5
3669 + '@esbuild/linux-mips64el': 0.25.5
3670 + '@esbuild/linux-ppc64': 0.25.5
3671 + '@esbuild/linux-riscv64': 0.25.5
3672 + '@esbuild/linux-s390x': 0.25.5
3673 + '@esbuild/linux-x64': 0.25.5
3674 + '@esbuild/netbsd-arm64': 0.25.5
3675 + '@esbuild/netbsd-x64': 0.25.5
3676 + '@esbuild/openbsd-arm64': 0.25.5
3677 + '@esbuild/openbsd-x64': 0.25.5
3678 + '@esbuild/sunos-x64': 0.25.5
3679 + '@esbuild/win32-arm64': 0.25.5
3680 + '@esbuild/win32-ia32': 0.25.5
3681 + '@esbuild/win32-x64': 0.25.5
3682 +
3683 + escape-string-regexp@4.0.0: {}
3684 +
3685 + escape-string-regexp@5.0.0: {}
3686 +
3687 + eslint-compat-utils@0.6.5(eslint@9.30.1(jiti@2.6.0)):
3688 + dependencies:
3689 + eslint: 9.30.1(jiti@2.6.0)
3690 + semver: 7.7.2
3691 +
3692 + eslint-config-prettier@10.1.5(eslint@9.30.1(jiti@2.6.0)):
3693 + dependencies:
3694 + eslint: 9.30.1(jiti@2.6.0)
3695 +
3696 + eslint-plugin-astro@1.3.1(eslint@9.30.1(jiti@2.6.0)):
3697 + dependencies:
3698 + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.0))
3699 + '@jridgewell/sourcemap-codec': 1.5.4
3700 + '@typescript-eslint/types': 8.35.1
3701 + astro-eslint-parser: 1.2.2
3702 + eslint: 9.30.1(jiti@2.6.0)
3703 + eslint-compat-utils: 0.6.5(eslint@9.30.1(jiti@2.6.0))
3704 + globals: 15.15.0
3705 + postcss: 8.5.6
3706 + postcss-selector-parser: 7.1.0
3707 + transitivePeerDependencies:
3708 + - supports-color
3709 +
3710 + eslint-scope@8.4.0:
3711 + dependencies:
3712 + esrecurse: 4.3.0
3713 + estraverse: 5.3.0
3714 +
3715 + eslint-visitor-keys@3.4.3: {}
3716 +
3717 + eslint-visitor-keys@4.2.1: {}
3718 +
3719 + eslint@9.30.1(jiti@2.6.0):
3720 + dependencies:
3721 + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.0))
3722 + '@eslint-community/regexpp': 4.12.1
3723 + '@eslint/config-array': 0.21.0
3724 + '@eslint/config-helpers': 0.3.0
3725 + '@eslint/core': 0.14.0
3726 + '@eslint/eslintrc': 3.3.1
3727 + '@eslint/js': 9.30.1
3728 + '@eslint/plugin-kit': 0.3.3
3729 + '@humanfs/node': 0.16.6
3730 + '@humanwhocodes/module-importer': 1.0.1
3731 + '@humanwhocodes/retry': 0.4.3
3732 + '@types/estree': 1.0.8
3733 + '@types/json-schema': 7.0.15
3734 + ajv: 6.12.6
3735 + chalk: 4.1.2
3736 + cross-spawn: 7.0.6
3737 + debug: 4.4.1
3738 + escape-string-regexp: 4.0.0
3739 + eslint-scope: 8.4.0
3740 + eslint-visitor-keys: 4.2.1
3741 + espree: 10.4.0
3742 + esquery: 1.6.0
3743 + esutils: 2.0.3
3744 + fast-deep-equal: 3.1.3
3745 + file-entry-cache: 8.0.0
3746 + find-up: 5.0.0
3747 + glob-parent: 6.0.2
3748 + ignore: 5.3.2
3749 + imurmurhash: 0.1.4
3750 + is-glob: 4.0.3
3751 + json-stable-stringify-without-jsonify: 1.0.1
3752 + lodash.merge: 4.6.2
3753 + minimatch: 3.1.2
3754 + natural-compare: 1.4.0
3755 + optionator: 0.9.4
3756 + optionalDependencies:
3757 + jiti: 2.6.0
3758 + transitivePeerDependencies:
3759 + - supports-color
3760 +
3761 + espree@10.4.0:
3762 + dependencies:
3763 + acorn: 8.15.0
3764 + acorn-jsx: 5.3.2(acorn@8.15.0)
3765 + eslint-visitor-keys: 4.2.1
3766 +
3767 + esquery@1.6.0:
3768 + dependencies:
3769 + estraverse: 5.3.0
3770 +
3771 + esrecurse@4.3.0:
3772 + dependencies:
3773 + estraverse: 5.3.0
3774 +
3775 + estraverse@5.3.0: {}
3776 +
3777 + estree-util-attach-comments@3.0.0:
3778 + dependencies:
3779 + '@types/estree': 1.0.8
3780 +
3781 + estree-util-build-jsx@3.0.1:
3782 + dependencies:
3783 + '@types/estree-jsx': 1.0.5
3784 + devlop: 1.1.0
3785 + estree-util-is-identifier-name: 3.0.0
3786 + estree-walker: 3.0.3
3787 +
3788 + estree-util-is-identifier-name@3.0.0: {}
3789 +
3790 + estree-util-scope@1.0.0:
3791 + dependencies:
3792 + '@types/estree': 1.0.8
3793 + devlop: 1.1.0
3794 +
3795 + estree-util-to-js@2.0.0:
3796 + dependencies:
3797 + '@types/estree-jsx': 1.0.5
3798 + astring: 1.9.0
3799 + source-map: 0.7.6
3800 +
3801 + estree-util-visit@2.0.0:
3802 + dependencies:
3803 + '@types/estree-jsx': 1.0.5
3804 + '@types/unist': 3.0.3
3805 +
3806 + estree-walker@2.0.2: {}
3807 +
3808 + estree-walker@3.0.3:
3809 + dependencies:
3810 + '@types/estree': 1.0.8
3811 +
3812 + esutils@2.0.3: {}
3813 +
3814 + eventemitter3@5.0.1: {}
3815 +
3816 + extend@3.0.2: {}
3817 +
3818 + fast-deep-equal@3.1.3: {}
3819 +
3820 + fast-glob@3.3.3:
3821 + dependencies:
3822 + '@nodelib/fs.stat': 2.0.5
3823 + '@nodelib/fs.walk': 1.2.8
3824 + glob-parent: 5.1.2
3825 + merge2: 1.4.1
3826 + micromatch: 4.0.8
3827 +
3828 + fast-json-stable-stringify@2.1.0: {}
3829 +
3830 + fast-levenshtein@2.0.6: {}
3831 +
3832 + fastq@1.19.1:
3833 + dependencies:
3834 + reusify: 1.1.0
3835 +
3836 + fdir@6.4.6(picomatch@4.0.3):
3837 + optionalDependencies:
3838 + picomatch: 4.0.3
3839 +
3840 + file-entry-cache@8.0.0:
3841 + dependencies:
3842 + flat-cache: 4.0.1
3843 +
3844 + fill-range@7.1.1:
3845 + dependencies:
3846 + to-regex-range: 5.0.1
3847 +
3848 + find-up@5.0.0:
3849 + dependencies:
3850 + locate-path: 6.0.0
3851 + path-exists: 4.0.0
3852 +
3853 + flat-cache@4.0.1:
3854 + dependencies:
3855 + flatted: 3.3.3
3856 + keyv: 4.5.4
3857 +
3858 + flatted@3.3.3: {}
3859 +
3860 + flattie@1.1.1: {}
3861 +
3862 + fontace@0.3.0:
3863 + dependencies:
3864 + '@types/fontkit': 2.0.8
3865 + fontkit: 2.0.4
3866 +
3867 + fontkit@2.0.4:
3868 + dependencies:
3869 + '@swc/helpers': 0.5.17
3870 + brotli: 1.3.3
3871 + clone: 2.1.2
3872 + dfa: 1.2.0
3873 + fast-deep-equal: 3.1.3
3874 + restructure: 3.0.2
3875 + tiny-inflate: 1.0.3
3876 + unicode-properties: 1.4.1
3877 + unicode-trie: 2.0.0
3878 +
3879 + fsevents@2.3.3:
3880 + optional: true
3881 +
3882 + get-east-asian-width@1.3.0: {}
3883 +
3884 + get-tsconfig@4.10.1:
3885 + dependencies:
3886 + resolve-pkg-maps: 1.0.0
3887 +
3888 + github-slugger@2.0.0: {}
3889 +
3890 + glob-parent@5.1.2:
3891 + dependencies:
3892 + is-glob: 4.0.3
3893 +
3894 + glob-parent@6.0.2:
3895 + dependencies:
3896 + is-glob: 4.0.3
3897 +
3898 + globals@14.0.0: {}
3899 +
3900 + globals@15.15.0: {}
3901 +
3902 + globals@16.3.0: {}
3903 +
3904 + graceful-fs@4.2.11: {}
3905 +
3906 + graphemer@1.4.0: {}
3907 +
3908 + h3@1.15.4:
3909 + dependencies:
3910 + cookie-es: 1.2.2
3911 + crossws: 0.3.5
3912 + defu: 6.1.4
3913 + destr: 2.0.5
3914 + iron-webcrypto: 1.2.1
3915 + node-mock-http: 1.0.3
3916 + radix3: 1.1.2
3917 + ufo: 1.6.1
3918 + uncrypto: 0.1.3
3919 +
3920 + has-flag@4.0.0: {}
3921 +
3922 + hast-util-from-dom@5.0.1:
3923 + dependencies:
3924 + '@types/hast': 3.0.4
3925 + hastscript: 9.0.1
3926 + web-namespaces: 2.0.1
3927 +
3928 + hast-util-from-html-isomorphic@2.0.0:
3929 + dependencies:
3930 + '@types/hast': 3.0.4
3931 + hast-util-from-dom: 5.0.1
3932 + hast-util-from-html: 2.0.3
3933 + unist-util-remove-position: 5.0.0
3934 +
3935 + hast-util-from-html@2.0.3:
3936 + dependencies:
3937 + '@types/hast': 3.0.4
3938 + devlop: 1.1.0
3939 + hast-util-from-parse5: 8.0.3
3940 + parse5: 7.3.0
3941 + vfile: 6.0.3
3942 + vfile-message: 4.0.2
3943 +
3944 + hast-util-from-parse5@8.0.3:
3945 + dependencies:
3946 + '@types/hast': 3.0.4
3947 + '@types/unist': 3.0.3
3948 + devlop: 1.1.0
3949 + hastscript: 9.0.1
3950 + property-information: 7.1.0
3951 + vfile: 6.0.3
3952 + vfile-location: 5.0.3
3953 + web-namespaces: 2.0.1
3954 +
3955 + hast-util-is-element@3.0.0:
3956 + dependencies:
3957 + '@types/hast': 3.0.4
3958 +
3959 + hast-util-parse-selector@4.0.0:
3960 + dependencies:
3961 + '@types/hast': 3.0.4
3962 +
3963 + hast-util-raw@9.1.0:
3964 + dependencies:
3965 + '@types/hast': 3.0.4
3966 + '@types/unist': 3.0.3
3967 + '@ungap/structured-clone': 1.3.0
3968 + hast-util-from-parse5: 8.0.3
3969 + hast-util-to-parse5: 8.0.0
3970 + html-void-elements: 3.0.0
3971 + mdast-util-to-hast: 13.2.0
3972 + parse5: 7.3.0
3973 + unist-util-position: 5.0.0
3974 + unist-util-visit: 5.0.0
3975 + vfile: 6.0.3
3976 + web-namespaces: 2.0.1
3977 + zwitch: 2.0.4
3978 +
3979 + hast-util-to-estree@3.1.3:
3980 + dependencies:
3981 + '@types/estree': 1.0.8
3982 + '@types/estree-jsx': 1.0.5
3983 + '@types/hast': 3.0.4
3984 + comma-separated-tokens: 2.0.3
3985 + devlop: 1.1.0
3986 + estree-util-attach-comments: 3.0.0
3987 + estree-util-is-identifier-name: 3.0.0
3988 + hast-util-whitespace: 3.0.0
3989 + mdast-util-mdx-expression: 2.0.1
3990 + mdast-util-mdx-jsx: 3.2.0
3991 + mdast-util-mdxjs-esm: 2.0.1
3992 + property-information: 7.1.0
3993 + space-separated-tokens: 2.0.2
3994 + style-to-js: 1.1.17
3995 + unist-util-position: 5.0.0
3996 + zwitch: 2.0.4
3997 + transitivePeerDependencies:
3998 + - supports-color
3999 +
4000 + hast-util-to-html@9.0.5:
4001 + dependencies:
4002 + '@types/hast': 3.0.4
4003 + '@types/unist': 3.0.3
4004 + ccount: 2.0.1
4005 + comma-separated-tokens: 2.0.3
4006 + hast-util-whitespace: 3.0.0
4007 + html-void-elements: 3.0.0
4008 + mdast-util-to-hast: 13.2.0
4009 + property-information: 7.1.0
4010 + space-separated-tokens: 2.0.2
4011 + stringify-entities: 4.0.4
4012 + zwitch: 2.0.4
4013 +
4014 + hast-util-to-jsx-runtime@2.3.6:
4015 + dependencies:
4016 + '@types/estree': 1.0.8
4017 + '@types/hast': 3.0.4
4018 + '@types/unist': 3.0.3
4019 + comma-separated-tokens: 2.0.3
4020 + devlop: 1.1.0
4021 + estree-util-is-identifier-name: 3.0.0
4022 + hast-util-whitespace: 3.0.0
4023 + mdast-util-mdx-expression: 2.0.1
4024 + mdast-util-mdx-jsx: 3.2.0
4025 + mdast-util-mdxjs-esm: 2.0.1
4026 + property-information: 7.1.0
4027 + space-separated-tokens: 2.0.2
4028 + style-to-js: 1.1.17
4029 + unist-util-position: 5.0.0
4030 + vfile-message: 4.0.2
4031 + transitivePeerDependencies:
4032 + - supports-color
4033 +
4034 + hast-util-to-parse5@8.0.0:
4035 + dependencies:
4036 + '@types/hast': 3.0.4
4037 + comma-separated-tokens: 2.0.3
4038 + devlop: 1.1.0
4039 + property-information: 6.5.0
4040 + space-separated-tokens: 2.0.2
4041 + web-namespaces: 2.0.1
4042 + zwitch: 2.0.4
4043 +
4044 + hast-util-to-text@4.0.2:
4045 + dependencies:
4046 + '@types/hast': 3.0.4
4047 + '@types/unist': 3.0.3
4048 + hast-util-is-element: 3.0.0
4049 + unist-util-find-after: 5.0.0
4050 +
4051 + hast-util-whitespace@3.0.0:
4052 + dependencies:
4053 + '@types/hast': 3.0.4
4054 +
4055 + hastscript@9.0.1:
4056 + dependencies:
4057 + '@types/hast': 3.0.4
4058 + comma-separated-tokens: 2.0.3
4059 + hast-util-parse-selector: 4.0.0
4060 + property-information: 7.1.0
4061 + space-separated-tokens: 2.0.2
4062 +
4063 + html-escaper@3.0.3: {}
4064 +
4065 + html-void-elements@3.0.0: {}
4066 +
4067 + http-cache-semantics@4.2.0: {}
4068 +
4069 + ignore@5.3.2: {}
4070 +
4071 + ignore@7.0.5: {}
4072 +
4073 + import-fresh@3.3.1:
4074 + dependencies:
4075 + parent-module: 1.0.1
4076 + resolve-from: 4.0.0
4077 +
4078 + import-meta-resolve@4.2.0: {}
4079 +
4080 + imurmurhash@0.1.4: {}
4081 +
4082 + inline-style-parser@0.2.4: {}
4083 +
4084 + iron-webcrypto@1.2.1: {}
4085 +
4086 + is-alphabetical@2.0.1: {}
4087 +
4088 + is-alphanumerical@2.0.1:
4089 + dependencies:
4090 + is-alphabetical: 2.0.1
4091 + is-decimal: 2.0.1
4092 +
4093 + is-arrayish@0.3.2: {}
4094 +
4095 + is-decimal@2.0.1: {}
4096 +
4097 + is-docker@3.0.0: {}
4098 +
4099 + is-extglob@2.1.1: {}
4100 +
4101 + is-fullwidth-code-point@3.0.0: {}
4102 +
4103 + is-glob@4.0.3:
4104 + dependencies:
4105 + is-extglob: 2.1.1
4106 +
4107 + is-hexadecimal@2.0.1: {}
4108 +
4109 + is-inside-container@1.0.0:
4110 + dependencies:
4111 + is-docker: 3.0.0
4112 +
4113 + is-number@7.0.0: {}
4114 +
4115 + is-plain-obj@4.1.0: {}
4116 +
4117 + is-wsl@3.1.0:
4118 + dependencies:
4119 + is-inside-container: 1.0.0
4120 +
4121 + isexe@2.0.0: {}
4122 +
4123 + jiti@2.6.0: {}
4124 +
4125 + js-yaml@4.1.0:
4126 + dependencies:
4127 + argparse: 2.0.1
4128 +
4129 + json-buffer@3.0.1: {}
4130 +
4131 + json-schema-traverse@0.4.1: {}
4132 +
4133 + json-stable-stringify-without-jsonify@1.0.1: {}
4134 +
4135 + katex@0.16.22:
4136 + dependencies:
4137 + commander: 8.3.0
4138 +
4139 + keyv@4.5.4:
4140 + dependencies:
4141 + json-buffer: 3.0.1
4142 +
4143 + kleur@3.0.3: {}
4144 +
4145 + levn@0.4.1:
4146 + dependencies:
4147 + prelude-ls: 1.2.1
4148 + type-check: 0.4.0
4149 +
4150 + lightningcss-darwin-arm64@1.30.1:
4151 + optional: true
4152 +
4153 + lightningcss-darwin-x64@1.30.1:
4154 + optional: true
4155 +
4156 + lightningcss-freebsd-x64@1.30.1:
4157 + optional: true
4158 +
4159 + lightningcss-linux-arm-gnueabihf@1.30.1:
4160 + optional: true
4161 +
4162 + lightningcss-linux-arm64-gnu@1.30.1:
4163 + optional: true
4164 +
4165 + lightningcss-linux-arm64-musl@1.30.1:
4166 + optional: true
4167 +
4168 + lightningcss-linux-x64-gnu@1.30.1:
4169 + optional: true
4170 +
4171 + lightningcss-linux-x64-musl@1.30.1:
4172 + optional: true
4173 +
4174 + lightningcss-win32-arm64-msvc@1.30.1:
4175 + optional: true
4176 +
4177 + lightningcss-win32-x64-msvc@1.30.1:
4178 + optional: true
4179 +
4180 + lightningcss@1.30.1:
4181 + dependencies:
4182 + detect-libc: 2.0.4
4183 + optionalDependencies:
4184 + lightningcss-darwin-arm64: 1.30.1
4185 + lightningcss-darwin-x64: 1.30.1
4186 + lightningcss-freebsd-x64: 1.30.1
4187 + lightningcss-linux-arm-gnueabihf: 1.30.1
4188 + lightningcss-linux-arm64-gnu: 1.30.1
4189 + lightningcss-linux-arm64-musl: 1.30.1
4190 + lightningcss-linux-x64-gnu: 1.30.1
4191 + lightningcss-linux-x64-musl: 1.30.1
4192 + lightningcss-win32-arm64-msvc: 1.30.1
4193 + lightningcss-win32-x64-msvc: 1.30.1
4194 +
4195 + locate-path@6.0.0:
4196 + dependencies:
4197 + p-locate: 5.0.0
4198 +
4199 + lodash.merge@4.6.2: {}
4200 +
4201 + longest-streak@3.1.0: {}
4202 +
4203 + lru-cache@10.4.3: {}
4204 +
4205 + magic-string@0.30.19:
4206 + dependencies:
4207 + '@jridgewell/sourcemap-codec': 1.5.5
4208 +
4209 + magicast@0.3.5:
4210 + dependencies:
4211 + '@babel/parser': 7.28.0
4212 + '@babel/types': 7.28.0
4213 + source-map-js: 1.2.1
4214 +
4215 + markdown-extensions@2.0.0: {}
4216 +
4217 + markdown-table@3.0.4: {}
4218 +
4219 + mdast-util-definitions@6.0.0:
4220 + dependencies:
4221 + '@types/mdast': 4.0.4
4222 + '@types/unist': 3.0.3
4223 + unist-util-visit: 5.0.0
4224 +
4225 + mdast-util-directive@3.1.0:
4226 + dependencies:
4227 + '@types/mdast': 4.0.4
4228 + '@types/unist': 3.0.3
4229 + ccount: 2.0.1
4230 + devlop: 1.1.0
4231 + mdast-util-from-markdown: 2.0.2
4232 + mdast-util-to-markdown: 2.1.2
4233 + parse-entities: 4.0.2
4234 + stringify-entities: 4.0.4
4235 + unist-util-visit-parents: 6.0.1
4236 + transitivePeerDependencies:
4237 + - supports-color
4238 +
4239 + mdast-util-find-and-replace@3.0.2:
4240 + dependencies:
4241 + '@types/mdast': 4.0.4
4242 + escape-string-regexp: 5.0.0
4243 + unist-util-is: 6.0.0
4244 + unist-util-visit-parents: 6.0.1
4245 +
4246 + mdast-util-from-markdown@2.0.2:
4247 + dependencies:
4248 + '@types/mdast': 4.0.4
4249 + '@types/unist': 3.0.3
4250 + decode-named-character-reference: 1.2.0
4251 + devlop: 1.1.0
4252 + mdast-util-to-string: 4.0.0
4253 + micromark: 4.0.2
4254 + micromark-util-decode-numeric-character-reference: 2.0.2
4255 + micromark-util-decode-string: 2.0.1
4256 + micromark-util-normalize-identifier: 2.0.1
4257 + micromark-util-symbol: 2.0.1
4258 + micromark-util-types: 2.0.2
4259 + unist-util-stringify-position: 4.0.0
4260 + transitivePeerDependencies:
4261 + - supports-color
4262 +
4263 + mdast-util-gfm-autolink-literal@2.0.1:
4264 + dependencies:
4265 + '@types/mdast': 4.0.4
4266 + ccount: 2.0.1
4267 + devlop: 1.1.0
4268 + mdast-util-find-and-replace: 3.0.2
4269 + micromark-util-character: 2.1.1
4270 +
4271 + mdast-util-gfm-footnote@2.1.0:
4272 + dependencies:
4273 + '@types/mdast': 4.0.4
4274 + devlop: 1.1.0
4275 + mdast-util-from-markdown: 2.0.2
4276 + mdast-util-to-markdown: 2.1.2
4277 + micromark-util-normalize-identifier: 2.0.1
4278 + transitivePeerDependencies:
4279 + - supports-color
4280 +
4281 + mdast-util-gfm-strikethrough@2.0.0:
4282 + dependencies:
4283 + '@types/mdast': 4.0.4
4284 + mdast-util-from-markdown: 2.0.2
4285 + mdast-util-to-markdown: 2.1.2
4286 + transitivePeerDependencies:
4287 + - supports-color
4288 +
4289 + mdast-util-gfm-table@2.0.0:
4290 + dependencies:
4291 + '@types/mdast': 4.0.4
4292 + devlop: 1.1.0
4293 + markdown-table: 3.0.4
4294 + mdast-util-from-markdown: 2.0.2
4295 + mdast-util-to-markdown: 2.1.2
4296 + transitivePeerDependencies:
4297 + - supports-color
4298 +
4299 + mdast-util-gfm-task-list-item@2.0.0:
4300 + dependencies:
4301 + '@types/mdast': 4.0.4
4302 + devlop: 1.1.0
4303 + mdast-util-from-markdown: 2.0.2
4304 + mdast-util-to-markdown: 2.1.2
4305 + transitivePeerDependencies:
4306 + - supports-color
4307 +
4308 + mdast-util-gfm@3.1.0:
4309 + dependencies:
4310 + mdast-util-from-markdown: 2.0.2
4311 + mdast-util-gfm-autolink-literal: 2.0.1
4312 + mdast-util-gfm-footnote: 2.1.0
4313 + mdast-util-gfm-strikethrough: 2.0.0
4314 + mdast-util-gfm-table: 2.0.0
4315 + mdast-util-gfm-task-list-item: 2.0.0
4316 + mdast-util-to-markdown: 2.1.2
4317 + transitivePeerDependencies:
4318 + - supports-color
4319 +
4320 + mdast-util-math@3.0.0:
4321 + dependencies:
4322 + '@types/hast': 3.0.4
4323 + '@types/mdast': 4.0.4
4324 + devlop: 1.1.0
4325 + longest-streak: 3.1.0
4326 + mdast-util-from-markdown: 2.0.2
4327 + mdast-util-to-markdown: 2.1.2
4328 + unist-util-remove-position: 5.0.0
4329 + transitivePeerDependencies:
4330 + - supports-color
4331 +
4332 + mdast-util-mdx-expression@2.0.1:
4333 + dependencies:
4334 + '@types/estree-jsx': 1.0.5
4335 + '@types/hast': 3.0.4
4336 + '@types/mdast': 4.0.4
4337 + devlop: 1.1.0
4338 + mdast-util-from-markdown: 2.0.2
4339 + mdast-util-to-markdown: 2.1.2
4340 + transitivePeerDependencies:
4341 + - supports-color
4342 +
4343 + mdast-util-mdx-jsx@3.2.0:
4344 + dependencies:
4345 + '@types/estree-jsx': 1.0.5
4346 + '@types/hast': 3.0.4
4347 + '@types/mdast': 4.0.4
4348 + '@types/unist': 3.0.3
4349 + ccount: 2.0.1
4350 + devlop: 1.1.0
4351 + mdast-util-from-markdown: 2.0.2
4352 + mdast-util-to-markdown: 2.1.2
4353 + parse-entities: 4.0.2
4354 + stringify-entities: 4.0.4
4355 + unist-util-stringify-position: 4.0.0
4356 + vfile-message: 4.0.2
4357 + transitivePeerDependencies:
4358 + - supports-color
4359 +
4360 + mdast-util-mdx@3.0.0:
4361 + dependencies:
4362 + mdast-util-from-markdown: 2.0.2
4363 + mdast-util-mdx-expression: 2.0.1
4364 + mdast-util-mdx-jsx: 3.2.0
4365 + mdast-util-mdxjs-esm: 2.0.1
4366 + mdast-util-to-markdown: 2.1.2
4367 + transitivePeerDependencies:
4368 + - supports-color
4369 +
4370 + mdast-util-mdxjs-esm@2.0.1:
4371 + dependencies:
4372 + '@types/estree-jsx': 1.0.5
4373 + '@types/hast': 3.0.4
4374 + '@types/mdast': 4.0.4
4375 + devlop: 1.1.0
4376 + mdast-util-from-markdown: 2.0.2
4377 + mdast-util-to-markdown: 2.1.2
4378 + transitivePeerDependencies:
4379 + - supports-color
4380 +
4381 + mdast-util-phrasing@4.1.0:
4382 + dependencies:
4383 + '@types/mdast': 4.0.4
4384 + unist-util-is: 6.0.0
4385 +
4386 + mdast-util-to-hast@13.2.0:
4387 + dependencies:
4388 + '@types/hast': 3.0.4
4389 + '@types/mdast': 4.0.4
4390 + '@ungap/structured-clone': 1.3.0
4391 + devlop: 1.1.0
4392 + micromark-util-sanitize-uri: 2.0.1
4393 + trim-lines: 3.0.1
4394 + unist-util-position: 5.0.0
4395 + unist-util-visit: 5.0.0
4396 + vfile: 6.0.3
4397 +
4398 + mdast-util-to-markdown@2.1.2:
4399 + dependencies:
4400 + '@types/mdast': 4.0.4
4401 + '@types/unist': 3.0.3
4402 + longest-streak: 3.1.0
4403 + mdast-util-phrasing: 4.1.0
4404 + mdast-util-to-string: 4.0.0
4405 + micromark-util-classify-character: 2.0.1
4406 + micromark-util-decode-string: 2.0.1
4407 + unist-util-visit: 5.0.0
4408 + zwitch: 2.0.4
4409 +
4410 + mdast-util-to-string@4.0.0:
4411 + dependencies:
4412 + '@types/mdast': 4.0.4
4413 +
4414 + mdn-data@2.12.2: {}
4415 +
4416 + merge2@1.4.1: {}
4417 +
4418 + micromark-core-commonmark@2.0.3:
4419 + dependencies:
4420 + decode-named-character-reference: 1.2.0
4421 + devlop: 1.1.0
4422 + micromark-factory-destination: 2.0.1
4423 + micromark-factory-label: 2.0.1
4424 + micromark-factory-space: 2.0.1
4425 + micromark-factory-title: 2.0.1
4426 + micromark-factory-whitespace: 2.0.1
4427 + micromark-util-character: 2.1.1
4428 + micromark-util-chunked: 2.0.1
4429 + micromark-util-classify-character: 2.0.1
4430 + micromark-util-html-tag-name: 2.0.1
4431 + micromark-util-normalize-identifier: 2.0.1
4432 + micromark-util-resolve-all: 2.0.1
4433 + micromark-util-subtokenize: 2.1.0
4434 + micromark-util-symbol: 2.0.1
4435 + micromark-util-types: 2.0.2
4436 +
4437 + micromark-extension-directive@4.0.0:
4438 + dependencies:
4439 + devlop: 1.1.0
4440 + micromark-factory-space: 2.0.1
4441 + micromark-factory-whitespace: 2.0.1
4442 + micromark-util-character: 2.1.1
4443 + micromark-util-symbol: 2.0.1
4444 + micromark-util-types: 2.0.2
4445 + parse-entities: 4.0.2
4446 +
4447 + micromark-extension-gfm-autolink-literal@2.1.0:
4448 + dependencies:
4449 + micromark-util-character: 2.1.1
4450 + micromark-util-sanitize-uri: 2.0.1
4451 + micromark-util-symbol: 2.0.1
4452 + micromark-util-types: 2.0.2
4453 +
4454 + micromark-extension-gfm-footnote@2.1.0:
4455 + dependencies:
4456 + devlop: 1.1.0
4457 + micromark-core-commonmark: 2.0.3
4458 + micromark-factory-space: 2.0.1
4459 + micromark-util-character: 2.1.1
4460 + micromark-util-normalize-identifier: 2.0.1
4461 + micromark-util-sanitize-uri: 2.0.1
4462 + micromark-util-symbol: 2.0.1
4463 + micromark-util-types: 2.0.2
4464 +
4465 + micromark-extension-gfm-strikethrough@2.1.0:
4466 + dependencies:
4467 + devlop: 1.1.0
4468 + micromark-util-chunked: 2.0.1
4469 + micromark-util-classify-character: 2.0.1
4470 + micromark-util-resolve-all: 2.0.1
4471 + micromark-util-symbol: 2.0.1
4472 + micromark-util-types: 2.0.2
4473 +
4474 + micromark-extension-gfm-table@2.1.1:
4475 + dependencies:
4476 + devlop: 1.1.0
4477 + micromark-factory-space: 2.0.1
4478 + micromark-util-character: 2.1.1
4479 + micromark-util-symbol: 2.0.1
4480 + micromark-util-types: 2.0.2
4481 +
4482 + micromark-extension-gfm-tagfilter@2.0.0:
4483 + dependencies:
4484 + micromark-util-types: 2.0.2
4485 +
4486 + micromark-extension-gfm-task-list-item@2.1.0:
4487 + dependencies:
4488 + devlop: 1.1.0
4489 + micromark-factory-space: 2.0.1
4490 + micromark-util-character: 2.1.1
4491 + micromark-util-symbol: 2.0.1
4492 + micromark-util-types: 2.0.2
4493 +
4494 + micromark-extension-gfm@3.0.0:
4495 + dependencies:
4496 + micromark-extension-gfm-autolink-literal: 2.1.0
4497 + micromark-extension-gfm-footnote: 2.1.0
4498 + micromark-extension-gfm-strikethrough: 2.1.0
4499 + micromark-extension-gfm-table: 2.1.1
4500 + micromark-extension-gfm-tagfilter: 2.0.0
4501 + micromark-extension-gfm-task-list-item: 2.1.0
4502 + micromark-util-combine-extensions: 2.0.1
4503 + micromark-util-types: 2.0.2
4504 +
4505 + micromark-extension-math@3.1.0:
4506 + dependencies:
4507 + '@types/katex': 0.16.7
4508 + devlop: 1.1.0
4509 + katex: 0.16.22
4510 + micromark-factory-space: 2.0.1
4511 + micromark-util-character: 2.1.1
4512 + micromark-util-symbol: 2.0.1
4513 + micromark-util-types: 2.0.2
4514 +
4515 + micromark-extension-mdx-expression@3.0.1:
4516 + dependencies:
4517 + '@types/estree': 1.0.8
4518 + devlop: 1.1.0
4519 + micromark-factory-mdx-expression: 2.0.3
4520 + micromark-factory-space: 2.0.1
4521 + micromark-util-character: 2.1.1
4522 + micromark-util-events-to-acorn: 2.0.3
4523 + micromark-util-symbol: 2.0.1
4524 + micromark-util-types: 2.0.2
4525 +
4526 + micromark-extension-mdx-jsx@3.0.2:
4527 + dependencies:
4528 + '@types/estree': 1.0.8
4529 + devlop: 1.1.0
4530 + estree-util-is-identifier-name: 3.0.0
4531 + micromark-factory-mdx-expression: 2.0.3
4532 + micromark-factory-space: 2.0.1
4533 + micromark-util-character: 2.1.1
4534 + micromark-util-events-to-acorn: 2.0.3
4535 + micromark-util-symbol: 2.0.1
4536 + micromark-util-types: 2.0.2
4537 + vfile-message: 4.0.2
4538 +
4539 + micromark-extension-mdx-md@2.0.0:
4540 + dependencies:
4541 + micromark-util-types: 2.0.2
4542 +
4543 + micromark-extension-mdxjs-esm@3.0.0:
4544 + dependencies:
4545 + '@types/estree': 1.0.8
4546 + devlop: 1.1.0
4547 + micromark-core-commonmark: 2.0.3
4548 + micromark-util-character: 2.1.1
4549 + micromark-util-events-to-acorn: 2.0.3
4550 + micromark-util-symbol: 2.0.1
4551 + micromark-util-types: 2.0.2
4552 + unist-util-position-from-estree: 2.0.0
4553 + vfile-message: 4.0.2
4554 +
4555 + micromark-extension-mdxjs@3.0.0:
4556 + dependencies:
4557 + acorn: 8.15.0
4558 + acorn-jsx: 5.3.2(acorn@8.15.0)
4559 + micromark-extension-mdx-expression: 3.0.1
4560 + micromark-extension-mdx-jsx: 3.0.2
4561 + micromark-extension-mdx-md: 2.0.0
4562 + micromark-extension-mdxjs-esm: 3.0.0
4563 + micromark-util-combine-extensions: 2.0.1
4564 + micromark-util-types: 2.0.2
4565 +
4566 + micromark-factory-destination@2.0.1:
4567 + dependencies:
4568 + micromark-util-character: 2.1.1
4569 + micromark-util-symbol: 2.0.1
4570 + micromark-util-types: 2.0.2
4571 +
4572 + micromark-factory-label@2.0.1:
4573 + dependencies:
4574 + devlop: 1.1.0
4575 + micromark-util-character: 2.1.1
4576 + micromark-util-symbol: 2.0.1
4577 + micromark-util-types: 2.0.2
4578 +
4579 + micromark-factory-mdx-expression@2.0.3:
4580 + dependencies:
4581 + '@types/estree': 1.0.8
4582 + devlop: 1.1.0
4583 + micromark-factory-space: 2.0.1
4584 + micromark-util-character: 2.1.1
4585 + micromark-util-events-to-acorn: 2.0.3
4586 + micromark-util-symbol: 2.0.1
4587 + micromark-util-types: 2.0.2
4588 + unist-util-position-from-estree: 2.0.0
4589 + vfile-message: 4.0.2
4590 +
4591 + micromark-factory-space@2.0.1:
4592 + dependencies:
4593 + micromark-util-character: 2.1.1
4594 + micromark-util-types: 2.0.2
4595 +
4596 + micromark-factory-title@2.0.1:
4597 + dependencies:
4598 + micromark-factory-space: 2.0.1
4599 + micromark-util-character: 2.1.1
4600 + micromark-util-symbol: 2.0.1
4601 + micromark-util-types: 2.0.2
4602 +
4603 + micromark-factory-whitespace@2.0.1:
4604 + dependencies:
4605 + micromark-factory-space: 2.0.1
4606 + micromark-util-character: 2.1.1
4607 + micromark-util-symbol: 2.0.1
4608 + micromark-util-types: 2.0.2
4609 +
4610 + micromark-util-character@2.1.1:
4611 + dependencies:
4612 + micromark-util-symbol: 2.0.1
4613 + micromark-util-types: 2.0.2
4614 +
4615 + micromark-util-chunked@2.0.1:
4616 + dependencies:
4617 + micromark-util-symbol: 2.0.1
4618 +
4619 + micromark-util-classify-character@2.0.1:
4620 + dependencies:
4621 + micromark-util-character: 2.1.1
4622 + micromark-util-symbol: 2.0.1
4623 + micromark-util-types: 2.0.2
4624 +
4625 + micromark-util-combine-extensions@2.0.1:
4626 + dependencies:
4627 + micromark-util-chunked: 2.0.1
4628 + micromark-util-types: 2.0.2
4629 +
4630 + micromark-util-decode-numeric-character-reference@2.0.2:
4631 + dependencies:
4632 + micromark-util-symbol: 2.0.1
4633 +
4634 + micromark-util-decode-string@2.0.1:
4635 + dependencies:
4636 + decode-named-character-reference: 1.2.0
4637 + micromark-util-character: 2.1.1
4638 + micromark-util-decode-numeric-character-reference: 2.0.2
4639 + micromark-util-symbol: 2.0.1
4640 +
4641 + micromark-util-encode@2.0.1: {}
4642 +
4643 + micromark-util-events-to-acorn@2.0.3:
4644 + dependencies:
4645 + '@types/estree': 1.0.8
4646 + '@types/unist': 3.0.3
4647 + devlop: 1.1.0
4648 + estree-util-visit: 2.0.0
4649 + micromark-util-symbol: 2.0.1
4650 + micromark-util-types: 2.0.2
4651 + vfile-message: 4.0.2
4652 +
4653 + micromark-util-html-tag-name@2.0.1: {}
4654 +
4655 + micromark-util-normalize-identifier@2.0.1:
4656 + dependencies:
4657 + micromark-util-symbol: 2.0.1
4658 +
4659 + micromark-util-resolve-all@2.0.1:
4660 + dependencies:
4661 + micromark-util-types: 2.0.2
4662 +
4663 + micromark-util-sanitize-uri@2.0.1:
4664 + dependencies:
4665 + micromark-util-character: 2.1.1
4666 + micromark-util-encode: 2.0.1
4667 + micromark-util-symbol: 2.0.1
4668 +
4669 + micromark-util-subtokenize@2.1.0:
4670 + dependencies:
4671 + devlop: 1.1.0
4672 + micromark-util-chunked: 2.0.1
4673 + micromark-util-symbol: 2.0.1
4674 + micromark-util-types: 2.0.2
4675 +
4676 + micromark-util-symbol@2.0.1: {}
4677 +
4678 + micromark-util-types@2.0.2: {}
4679 +
4680 + micromark@4.0.2:
4681 + dependencies:
4682 + '@types/debug': 4.1.12
4683 + debug: 4.4.1
4684 + decode-named-character-reference: 1.2.0
4685 + devlop: 1.1.0
4686 + micromark-core-commonmark: 2.0.3
4687 + micromark-factory-space: 2.0.1
4688 + micromark-util-character: 2.1.1
4689 + micromark-util-chunked: 2.0.1
4690 + micromark-util-combine-extensions: 2.0.1
4691 + micromark-util-decode-numeric-character-reference: 2.0.2
4692 + micromark-util-encode: 2.0.1
4693 + micromark-util-normalize-identifier: 2.0.1
4694 + micromark-util-resolve-all: 2.0.1
4695 + micromark-util-sanitize-uri: 2.0.1
4696 + micromark-util-subtokenize: 2.1.0
4697 + micromark-util-symbol: 2.0.1
4698 + micromark-util-types: 2.0.2
4699 + transitivePeerDependencies:
4700 + - supports-color
4701 +
4702 + micromatch@4.0.8:
4703 + dependencies:
4704 + braces: 3.0.3
4705 + picomatch: 2.3.1
4706 +
4707 + minimatch@3.1.2:
4708 + dependencies:
4709 + brace-expansion: 1.1.12
4710 +
4711 + minimatch@9.0.5:
4712 + dependencies:
4713 + brace-expansion: 2.0.2
4714 +
4715 + minipass@7.1.2: {}
4716 +
4717 + minizlib@3.1.0:
4718 + dependencies:
4719 + minipass: 7.1.2
4720 +
4721 + mrmime@2.0.1: {}
4722 +
4723 + ms@2.1.3: {}
4724 +
4725 + nanoid@3.3.11: {}
4726 +
4727 + natural-compare@1.4.0: {}
4728 +
4729 + neotraverse@0.6.18: {}
4730 +
4731 + nlcst-to-string@4.0.0:
4732 + dependencies:
4733 + '@types/nlcst': 2.0.3
4734 +
4735 + node-fetch-native@1.6.6: {}
4736 +
4737 + node-fetch-native@1.6.7: {}
4738 +
4739 + node-mock-http@1.0.3: {}
4740 +
4741 + normalize-path@3.0.0: {}
4742 +
4743 + ofetch@1.4.1:
4744 + dependencies:
4745 + destr: 2.0.5
4746 + node-fetch-native: 1.6.6
4747 + ufo: 1.6.1
4748 +
4749 + ofetch@1.5.1:
4750 + dependencies:
4751 + destr: 2.0.5
4752 + node-fetch-native: 1.6.7
4753 + ufo: 1.6.1
4754 +
4755 + ohash@2.0.11: {}
4756 +
4757 + oniguruma-parser@0.12.1: {}
4758 +
4759 + oniguruma-to-es@4.3.3:
4760 + dependencies:
4761 + oniguruma-parser: 0.12.1
4762 + regex: 6.0.1
4763 + regex-recursion: 6.0.2
4764 +
4765 + optionator@0.9.4:
4766 + dependencies:
4767 + deep-is: 0.1.4
4768 + fast-levenshtein: 2.0.6
4769 + levn: 0.4.1
4770 + prelude-ls: 1.2.1
4771 + type-check: 0.4.0
4772 + word-wrap: 1.2.5
4773 +
4774 + p-limit@3.1.0:
4775 + dependencies:
4776 + yocto-queue: 0.1.0
4777 +
4778 + p-limit@6.2.0:
4779 + dependencies:
4780 + yocto-queue: 1.2.1
4781 +
4782 + p-locate@5.0.0:
4783 + dependencies:
4784 + p-limit: 3.1.0
4785 +
4786 + p-queue@8.1.0:
4787 + dependencies:
4788 + eventemitter3: 5.0.1
4789 + p-timeout: 6.1.4
4790 +
4791 + p-timeout@6.1.4: {}
4792 +
4793 + package-manager-detector@1.3.0: {}
4794 +
4795 + pako@0.2.9: {}
4796 +
4797 + parent-module@1.0.1:
4798 + dependencies:
4799 + callsites: 3.1.0
4800 +
4801 + parse-entities@4.0.2:
4802 + dependencies:
4803 + '@types/unist': 2.0.11
4804 + character-entities-legacy: 3.0.0
4805 + character-reference-invalid: 2.0.1
4806 + decode-named-character-reference: 1.2.0
4807 + is-alphanumerical: 2.0.1
4808 + is-decimal: 2.0.1
4809 + is-hexadecimal: 2.0.1
4810 +
4811 + parse-latin@7.0.0:
4812 + dependencies:
4813 + '@types/nlcst': 2.0.3
4814 + '@types/unist': 3.0.3
4815 + nlcst-to-string: 4.0.0
4816 + unist-util-modify-children: 4.0.0
4817 + unist-util-visit-children: 3.0.0
4818 + vfile: 6.0.3
4819 +
4820 + parse5@7.3.0:
4821 + dependencies:
4822 + entities: 6.0.1
4823 +
4824 + path-exists@4.0.0: {}
4825 +
4826 + path-key@3.1.1: {}
4827 +
4828 + picocolors@1.1.1: {}
4829 +
4830 + picomatch@2.3.1: {}
4831 +
4832 + picomatch@4.0.3: {}
4833 +
4834 + postcss-selector-parser@7.1.0:
4835 + dependencies:
4836 + cssesc: 3.0.0
4837 + util-deprecate: 1.0.2
4838 +
4839 + postcss@8.5.6:
4840 + dependencies:
4841 + nanoid: 3.3.11
4842 + picocolors: 1.1.1
4843 + source-map-js: 1.2.1
4844 +
4845 + prelude-ls@1.2.1: {}
4846 +
4847 + prettier-plugin-astro@0.14.1:
4848 + dependencies:
4849 + '@astrojs/compiler': 2.12.2
4850 + prettier: 3.6.2
4851 + sass-formatter: 0.7.9
4852 +
4853 + prettier@3.6.2: {}
4854 +
4855 + prismjs@1.30.0: {}
4856 +
4857 + prompts@2.4.2:
4858 + dependencies:
4859 + kleur: 3.0.3
4860 + sisteransi: 1.0.5
4861 +
4862 + property-information@6.5.0: {}
4863 +
4864 + property-information@7.1.0: {}
4865 +
4866 + punycode@2.3.1: {}
4867 +
4868 + queue-microtask@1.2.3: {}
4869 +
4870 + radix3@1.1.2: {}
4871 +
4872 + readdirp@4.1.2: {}
4873 +
4874 + reading-time@1.5.0: {}
4875 +
4876 + recma-build-jsx@1.0.0:
4877 + dependencies:
4878 + '@types/estree': 1.0.8
4879 + estree-util-build-jsx: 3.0.1
4880 + vfile: 6.0.3
4881 +
4882 + recma-jsx@1.0.0(acorn@8.15.0):
4883 + dependencies:
4884 + acorn-jsx: 5.3.2(acorn@8.15.0)
4885 + estree-util-to-js: 2.0.0
4886 + recma-parse: 1.0.0
4887 + recma-stringify: 1.0.0
4888 + unified: 11.0.5
4889 + transitivePeerDependencies:
4890 + - acorn
4891 +
4892 + recma-parse@1.0.0:
4893 + dependencies:
4894 + '@types/estree': 1.0.8
4895 + esast-util-from-js: 2.0.1
4896 + unified: 11.0.5
4897 + vfile: 6.0.3
4898 +
4899 + recma-stringify@1.0.0:
4900 + dependencies:
4901 + '@types/estree': 1.0.8
4902 + estree-util-to-js: 2.0.0
4903 + unified: 11.0.5
4904 + vfile: 6.0.3
4905 +
4906 + regex-recursion@6.0.2:
4907 + dependencies:
4908 + regex-utilities: 2.3.0
4909 +
4910 + regex-utilities@2.3.0: {}
4911 +
4912 + regex@6.0.1:
4913 + dependencies:
4914 + regex-utilities: 2.3.0
4915 +
4916 + rehype-katex@7.0.1:
4917 + dependencies:
4918 + '@types/hast': 3.0.4
4919 + '@types/katex': 0.16.7
4920 + hast-util-from-html-isomorphic: 2.0.0
4921 + hast-util-to-text: 4.0.2
4922 + katex: 0.16.22
4923 + unist-util-visit-parents: 6.0.1
4924 + vfile: 6.0.3
4925 +
4926 + rehype-parse@9.0.1:
4927 + dependencies:
4928 + '@types/hast': 3.0.4
4929 + hast-util-from-html: 2.0.3
4930 + unified: 11.0.5
4931 +
4932 + rehype-raw@7.0.0:
4933 + dependencies:
4934 + '@types/hast': 3.0.4
4935 + hast-util-raw: 9.1.0
4936 + vfile: 6.0.3
4937 +
4938 + rehype-recma@1.0.0:
4939 + dependencies:
4940 + '@types/estree': 1.0.8
4941 + '@types/hast': 3.0.4
4942 + hast-util-to-estree: 3.1.3
4943 + transitivePeerDependencies:
4944 + - supports-color
4945 +
4946 + rehype-stringify@10.0.1:
4947 + dependencies:
4948 + '@types/hast': 3.0.4
4949 + hast-util-to-html: 9.0.5
4950 + unified: 11.0.5
4951 +
4952 + rehype@13.0.2:
4953 + dependencies:
4954 + '@types/hast': 3.0.4
4955 + rehype-parse: 9.0.1
4956 + rehype-stringify: 10.0.1
4957 + unified: 11.0.5
4958 +
4959 + remark-directive@4.0.0:
4960 + dependencies:
4961 + '@types/mdast': 4.0.4
4962 + mdast-util-directive: 3.1.0
4963 + micromark-extension-directive: 4.0.0
4964 + unified: 11.0.5
4965 + transitivePeerDependencies:
4966 + - supports-color
4967 +
4968 + remark-gfm@4.0.1:
4969 + dependencies:
4970 + '@types/mdast': 4.0.4
4971 + mdast-util-gfm: 3.1.0
4972 + micromark-extension-gfm: 3.0.0
4973 + remark-parse: 11.0.0
4974 + remark-stringify: 11.0.0
4975 + unified: 11.0.5
4976 + transitivePeerDependencies:
4977 + - supports-color
4978 +
4979 + remark-math@6.0.0:
4980 + dependencies:
4981 + '@types/mdast': 4.0.4
4982 + mdast-util-math: 3.0.0
4983 + micromark-extension-math: 3.1.0
4984 + unified: 11.0.5
4985 + transitivePeerDependencies:
4986 + - supports-color
4987 +
4988 + remark-mdx@3.1.0:
4989 + dependencies:
4990 + mdast-util-mdx: 3.0.0
4991 + micromark-extension-mdxjs: 3.0.0
4992 + transitivePeerDependencies:
4993 + - supports-color
4994 +
4995 + remark-parse@11.0.0:
4996 + dependencies:
4997 + '@types/mdast': 4.0.4
4998 + mdast-util-from-markdown: 2.0.2
4999 + micromark-util-types: 2.0.2

This file is too large to show in full.

pnpm-workspace.yaml new
+4
@@ -0,0 +1,4 @@
1 +onlyBuiltDependencies:
2 + - '@tailwindcss/oxide'
3 + - esbuild
4 + - sharp
public/app-ads.txt new
+1
@@ -0,0 +1 @@
1 +google.com, pub-8869993014420242, DIRECT, f08c47fec0942fa0
public/favicon/android-chrome-192x192.png
Binary files /dev/null and b/public/favicon/android-chrome-192x192.png differ
public/favicon/android-chrome-512x512.png
Binary files /dev/null and b/public/favicon/android-chrome-512x512.png differ
public/favicon/apple-touch-icon.png
Binary files /dev/null and b/public/favicon/apple-touch-icon.png differ
public/favicon/favicon-16x16.png
Binary files /dev/null and b/public/favicon/favicon-16x16.png differ
public/favicon/favicon-32x32.png
Binary files /dev/null and b/public/favicon/favicon-32x32.png differ
public/favicon/favicon.ico
Binary files /dev/null and b/public/favicon/favicon.ico differ
public/favicon/site.webmanifest new
+1
@@ -0,0 +1 @@
1 +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
public/fonts/Besley-Italic.woff2
Binary files /dev/null and b/public/fonts/Besley-Italic.woff2 differ
public/fonts/Inter.woff2
Binary files /dev/null and b/public/fonts/Inter.woff2 differ
public/images/1f3f5-fe0f.png
Binary files /dev/null and b/public/images/1f3f5-fe0f.png differ
public/images/Download_on_the_App_Store_Badge_US-UK_RGB_blk_092917.svg new
+46
@@ -0,0 +1,46 @@
1 +<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="119.66407" height="40" viewBox="0 0 119.66407 40">
2 + <title>Download_on_the_App_Store_Badge_US-UK_RGB_blk_4SVG_092917</title>
3 + <g>
4 + <g>
5 + <g>
6 + <path d="M110.13477,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.43779,6.43779,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01515.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27445,6.27445,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H110.13477c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/>
7 + <path d="M8.44483,39.125c-.30468,0-.602-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72186,5.72186,0,0,1-.543-1.6572,12.41351,12.41351,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37039,12.37039,0,0,1,.16553-1.87207,5.7555,5.7555,0,0,1,.54346-1.6621A5.37349,5.37349,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875H111.21387l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73126,12.73126,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/>
8 + </g>
9 + <g id="_Group_" data-name="&lt;Group&gt;">
10 + <g id="_Group_2" data-name="&lt;Group&gt;">
11 + <g id="_Group_3" data-name="&lt;Group&gt;">
12 + <path id="_Path_" data-name="&lt;Path&gt;" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/>
13 + <path id="_Path_2" data-name="&lt;Path&gt;" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/>
14 + </g>
15 + </g>
16 + <g>
17 + <path d="M42.30227,27.13965h-4.7334l-1.13672,3.35645H34.42727l4.4834-12.418h2.083l4.4834,12.418H43.438ZM38.0591,25.59082h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/>
18 + <path d="M55.15969,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H48.4302v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C53.645,21.34766,55.15969,23.16406,55.15969,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C52.30227,29.01563,53.24953,27.81934,53.24953,25.96973Z" style="fill: #fff"/>
19 + <path d="M65.12453,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H58.395v1.50586h.03418A3.21162,3.21162,0,0,1,61.312,21.34766C63.60988,21.34766,65.12453,23.16406,65.12453,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C62.26711,29.01563,63.21438,27.81934,63.21438,25.96973Z" style="fill: #fff"/>
20 + <path d="M71.71047,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52148.75684-2.52148,1.8584c0,.87793.6543,1.39453,2.25488,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/>
21 + <path d="M83.34621,19.2998v2.14258h1.72168v1.47168H83.34621v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406H80.16262V21.44238H81.479V19.2998Z" style="fill: #fff"/>
22 + <path d="M86.065,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C87.72609,30.6084,86.065,28.82617,86.065,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40039,1.16211-2.40039,3.10742c0,1.96191.89453,3.10645,2.40039,3.10645S92.76027,27.93164,92.76027,25.96973Z" style="fill: #fff"/>
23 + <path d="M96.18606,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.59794,2.59794,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93652,2.083v5.37012h-1.8584Z" style="fill: #fff"/>
24 + <path d="M109.3843,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,103.10207,25.13477Z" style="fill: #fff"/>
25 + </g>
26 + </g>
27 + </g>
28 + <g id="_Group_4" data-name="&lt;Group&gt;">
29 + <g>
30 + <path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/>
31 + <path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57522,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/>
32 + <path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/>
33 + <path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
34 + <path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/>
35 + <path d="M61.21779,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/>
36 + <path d="M66.4009,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.4009,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29543,13.03955Z" style="fill: #fff"/>
37 + <path d="M71.34816,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.0718,14.772,71.34816,13.87061,71.34816,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72121,10.91846,72.26613,11.49707,72.26613,12.44434Z" style="fill: #fff"/>
38 + <path d="M79.23,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.12453,13.99463,82.563,13.42432,82.563,12.44434Z" style="fill: #fff"/>
39 + <path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
40 + <path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/>
41 + <path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/>
42 + <path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/>
43 + </g>
44 + </g>
45 + </g>
46 +</svg>
public/images/GetItOnGooglePlay_Badge_Web_color_English.png
Binary files /dev/null and b/public/images/GetItOnGooglePlay_Badge_Web_color_English.png differ
public/images/screenshot-dark.png
Binary files /dev/null and b/public/images/screenshot-dark.png differ
public/images/screenshot-light.png
Binary files /dev/null and b/public/images/screenshot-light.png differ
scripts/new-post.ts new
+55
@@ -0,0 +1,55 @@
1 +/**
2 + * Create a new post with frontmatter
3 + * Usage: pnpm new <title>
4 + */
5 +
6 +import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
7 +import { dirname, join } from 'node:path'
8 +import process from 'node:process'
9 +
10 +// Process title from all arguments
11 +const titleArgs: string[] = process.argv.slice(2)
12 +const rawTitle: string = titleArgs.length > 0 ? titleArgs.join(' ') : 'new-post'
13 +
14 +// Check if title starts with underscore (draft post)
15 +const isDraft: boolean = rawTitle.startsWith('_')
16 +const displayTitle: string = isDraft ? rawTitle.slice(1) : rawTitle
17 +
18 +const fileName: string = rawTitle
19 + .toLowerCase()
20 + .replace(/[^a-z0-9\s-_]/g, '') // Remove special characters but keep underscore and hyphen
21 + .replace(/\s+/g, '-') // Replace spaces with hyphens
22 + .replace(/-+/g, '-') // Replace multiple hyphens with single
23 + .replace(/^-|-$/g, '') // Remove leading/trailing hyphens
24 +const targetFile: string = `${fileName}.md`
25 +const fullPath: string = join('src/content/posts', targetFile)
26 +
27 +// Check if the target file already exists
28 +if (existsSync(fullPath)) {
29 + console.error(`😇 File already exists: ${fullPath}`)
30 + process.exit(1)
31 +}
32 +
33 +// Ensure the directory structure exists
34 +mkdirSync(dirname(fullPath), { recursive: true })
35 +
36 +// Generate frontmatter with current date
37 +const content: string = `---
38 +title: ${displayTitle}
39 +pubDate: '${new Date().toISOString().split('T')[0]}'
40 +---
41 +
42 +`
43 +
44 +// Write the new post file
45 +try {
46 + writeFileSync(fullPath, content)
47 + if (isDraft) {
48 + console.log(`📝 Draft created: ${fullPath}`)
49 + } else {
50 + console.log(`✅ Post created: ${fullPath}`)
51 + }
52 +} catch (error) {
53 + console.error('⚠️ Failed to create post:', error)
54 + process.exit(1)
55 +}
scripts/update-theme.ts new
+46
@@ -0,0 +1,46 @@
1 +#!/usr/bin/env tsx
2 +
3 +/**
4 + * Update theme from upstream repository
5 + * Usage: pnpm update-theme
6 + */
7 +
8 +import { execSync } from 'node:child_process'
9 +import fs from 'node:fs'
10 +import path from 'node:path'
11 +import process from 'node:process'
12 +
13 +// Check and set up the upstream remote repository
14 +try {
15 + execSync('git remote get-url upstream', { stdio: 'ignore' })
16 +} catch {
17 + execSync('git remote add upstream https://github.com/the3ash/astro-chiri.git', {
18 + stdio: 'inherit'
19 + })
20 +}
21 +
22 +// Update theme from upstream repository
23 +try {
24 + execSync('git fetch upstream', { stdio: 'inherit' })
25 +
26 + const currentCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim()
27 + execSync('git merge upstream/main --allow-unrelated-histories', { stdio: 'inherit' })
28 + const newCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim()
29 +
30 + if (currentCommit === newCommit) {
31 + console.log('🤗 No updates available, already up to date')
32 + } else {
33 + console.log('✅ Theme updated')
34 + }
35 +} catch (error) {
36 + // Check if there's a merge conflict
37 + const gitDirectory = execSync('git rev-parse --git-dir', { encoding: 'utf8' }).trim()
38 + const mergeHeadFile = path.join(gitDirectory, 'MERGE_HEAD')
39 +
40 + if (fs.existsSync(mergeHeadFile)) {
41 + console.log('⚠️ Update fetched with merge conflicts. Please resolve manually')
42 + } else {
43 + console.error('❌ Update failed:', error)
44 + process.exit(1)
45 + }
46 +}
src/components/examples/Callout.astro new
+53
@@ -0,0 +1,53 @@
1 +<div class="callout-card">
2 + <div class="callout-container">
3 + <div class="callout">
4 + <span class="callout-icon">🙊</span>
5 + <span class="callout-text">Ape shall never kill ape.</span>
6 + </div>
7 + </div>
8 +</div>
9 +
10 +<style>
11 + .callout-card {
12 + border: 1px solid var(--border);
13 + width: 100%;
14 + height: 12rem;
15 + display: flex;
16 + align-items: center;
17 + justify-content: center;
18 + border-radius: 10px;
19 + }
20 +
21 + .callout-container {
22 + display: flex;
23 + justify-content: center;
24 + align-items: center;
25 + width: 100%;
26 + padding: 0 4rem;
27 + }
28 +
29 + .callout {
30 + background-color: var(--astro-code-background);
31 + border: 1px solid var(--code-bg);
32 + border-radius: 10px;
33 + padding: 1rem;
34 + display: flex;
35 + align-items: center;
36 + gap: 0.5rem;
37 + width: 100%;
38 + min-width: 13rem;
39 + }
40 +
41 + .callout-icon {
42 + padding-right: 0.5rem;
43 + font-size: 1.25rem;
44 + line-height: 1;
45 + display: flex;
46 + align-items: center;
47 + }
48 +
49 + .callout-text {
50 + color: var(--text-primary);
51 + line-height: 1.5;
52 + }
53 +</style>
src/components/examples/CounterButton.astro new
+55
@@ -0,0 +1,55 @@
1 +<div class="counter-card">
2 + <div class="counter-container">
3 + <button id="counter-btn" class="counter-button">
4 + Click me (<span id="counter-value">0</span>)
5 + </button>
6 + </div>
7 +</div>
8 +
9 +<style>
10 + .counter-card {
11 + border: 1px solid var(--border);
12 + width: 100%;
13 + height: 12rem;
14 + display: flex;
15 + align-items: center;
16 + justify-content: center;
17 + border-radius: 10px;
18 + }
19 +
20 + .counter-container {
21 + display: flex;
22 + justify-content: center;
23 + align-items: center;
24 + }
25 +
26 + .counter-button {
27 + background-color: var(--text-primary);
28 + color: var(--bg);
29 + border: none;
30 + font-family: var(--font-mono);
31 + font-size: var(--font-size-s);
32 + border-radius: 12px;
33 + cursor: pointer;
34 + width: 160px;
35 + height: 44px;
36 + transition: all 0.15s ease-in-out;
37 + }
38 +
39 + .counter-button:hover {
40 + opacity: 0.9;
41 + }
42 +</style>
43 +
44 +<script>
45 + let count = 0
46 + const button = document.getElementById('counter-btn')
47 + const valueSpan = document.getElementById('counter-value')
48 +
49 + if (button && valueSpan) {
50 + button.addEventListener('click', () => {
51 + count++
52 + valueSpan.textContent = count.toString()
53 + })
54 + }
55 +</script>
src/components/examples/Tag.astro new
+465
@@ -0,0 +1,465 @@
1 +<div class="tag-card">
2 + <div class="tag-container">
3 + <div id="tag-component" class="tag-component">
4 + <button id="add-button" class="add-button">
5 + <svg
6 + class="add-icon"
7 + xmlns="http://www.w3.org/2000/svg"
8 + viewBox="0 0 16 16"
9 + width="16"
10 + height="16"
11 + >
12 + <path
13 + d="M7.75 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.5v4.25a.75.75 0 0 1-1.5 0V8.5H2.75a.75.75 0 0 1 0-1.5H7V2.75A.75.75 0 0 1 7.75 2Z"
14 + ></path>
15 + </svg>
16 + </button>
17 +
18 + <div id="input-state" class="input-state">
19 + <input id="tag-input" type="text" placeholder="Tag Name" class="tag-input" />
20 + <button id="confirm-button" class="confirm-button disabled">
21 + <svg
22 + class="confirm-icon"
23 + xmlns="http://www.w3.org/2000/svg"
24 + viewBox="0 0 16 16"
25 + width="16"
26 + height="16"
27 + >
28 + <path
29 + d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
30 + ></path>
31 + </svg>
32 + </button>
33 + <button id="cancel-button" class="cancel-button">
34 + <svg
35 + class="cancel-icon"
36 + xmlns="http://www.w3.org/2000/svg"
37 + viewBox="0 0 16 16"
38 + width="16"
39 + height="16"
40 + >
41 + <path
42 + d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"
43 + ></path>
44 + </svg>
45 + </button>
46 + </div>
47 +
48 + <div id="tag-display" class="tag-display">
49 + <span id="tag-text" class="tag-text"></span>
50 + <button id="delete-button" class="delete-button">
51 + <svg
52 + class="delete-icon"
53 + xmlns="http://www.w3.org/2000/svg"
54 + viewBox="0 0 16 16"
55 + width="16"
56 + height="16"
57 + >
58 + <path
59 + d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"
60 + ></path>
61 + </svg>
62 + </button>
63 + </div>
64 + </div>
65 + </div>
66 +</div>
67 +
68 +<script>
69 + let currentState = 'add' // 'add', 'input', 'display'
70 + let tagValue = ''
71 +
72 + const addButton = document.getElementById('add-button') as HTMLButtonElement
73 + const inputState = document.getElementById('input-state') as HTMLDivElement
74 + const tagDisplay = document.getElementById('tag-display') as HTMLDivElement
75 + const tagInput = document.getElementById('tag-input') as HTMLInputElement
76 + const confirmButton = document.getElementById('confirm-button') as HTMLButtonElement
77 + const cancelButton = document.getElementById('cancel-button') as HTMLButtonElement
78 + const deleteButton = document.getElementById('delete-button') as HTMLButtonElement
79 + const tagText = document.getElementById('tag-text') as HTMLSpanElement
80 +
81 + // Switch to input state
82 + function switchToInput() {
83 + currentState = 'input'
84 + addButton?.classList.add('hidden')
85 +
86 + setTimeout(() => {
87 + inputState?.classList.add('active')
88 + tagInput?.focus()
89 + }, 100)
90 + }
91 +
92 + // Switch to display state
93 + function switchToDisplay() {
94 + currentState = 'display'
95 +
96 + inputState?.classList.remove('active')
97 +
98 + setTimeout(() => {
99 + tagDisplay?.classList.add('active')
100 + if (tagText) tagText.textContent = truncateText(tagValue)
101 + }, 300)
102 + }
103 +
104 + // Return to add state
105 + function switchToAdd() {
106 + if (currentState === 'display') {
107 + tagDisplay?.classList.remove('active')
108 + } else if (currentState === 'input') {
109 + inputState?.classList.remove('active')
110 + }
111 +
112 + currentState = 'add'
113 +
114 + setTimeout(() => {
115 + addButton?.classList.remove('hidden')
116 + tagValue = ''
117 + if (tagInput) tagInput.value = ''
118 + updateConfirmButton()
119 + }, 250)
120 + }
121 +
122 + // Update confirm button state
123 + function updateConfirmButton() {
124 + if (tagInput?.value.trim()) {
125 + confirmButton?.classList.remove('disabled')
126 + } else {
127 + confirmButton?.classList.add('disabled')
128 + }
129 + }
130 +
131 + // Truncate text to max 24 characters
132 + function truncateText(text: string, maxLength: number = 24): string {
133 + if (text.length <= maxLength) {
134 + return text
135 + }
136 + return text.substring(0, maxLength) + '...'
137 + }
138 +
139 + addButton?.addEventListener('click', switchToInput)
140 +
141 + tagInput?.addEventListener('input', (e) => {
142 + const target = e.target as HTMLInputElement
143 + const inputValue = target.value
144 +
145 + // Limit input to 24 characters
146 + if (inputValue.length > 24) {
147 + target.value = inputValue.substring(0, 24)
148 + tagValue = inputValue // Keep original value for display truncation
149 + } else {
150 + tagValue = inputValue
151 + }
152 +
153 + updateConfirmButton()
154 + })
155 +
156 + tagInput?.addEventListener('keydown', (e) => {
157 + if (e.key === 'Enter' && tagValue.trim()) {
158 + switchToDisplay()
159 + } else if (e.key === 'Escape') {
160 + switchToAdd()
161 + }
162 + })
163 +
164 + confirmButton?.addEventListener('click', () => {
165 + if (tagValue.trim()) {
166 + switchToDisplay()
167 + }
168 + })
169 +
170 + cancelButton?.addEventListener('click', switchToAdd)
171 +
172 + deleteButton?.addEventListener('click', switchToAdd)
173 +</script>
174 +
175 +<style>
176 + .tag-card {
177 + border: 1px solid var(--border);
178 + width: 100%;
179 + height: 12rem;
180 + display: flex;
181 + align-items: center;
182 + justify-content: center;
183 + border-radius: 10px;
184 + }
185 +
186 + .tag-container {
187 + display: flex;
188 + justify-content: center;
189 + align-items: center;
190 + width: 100%;
191 + padding: 0 2rem;
192 + overflow: hidden;
193 + }
194 +
195 + .tag-component {
196 + display: flex;
197 + align-items: center;
198 + justify-content: center;
199 + gap: 0.5rem;
200 + position: relative;
201 + width: 100%;
202 + min-height: 40px;
203 + }
204 +
205 + .add-button {
206 + background-color: var(--text-primary);
207 + color: var(--bg);
208 + border: none;
209 + border-radius: 50%;
210 + width: 36px;
211 + height: 36px;
212 + cursor: pointer;
213 + display: flex;
214 + align-items: center;
215 + justify-content: center;
216 + transition:
217 + all 0.3s ease,
218 + visibility 0s;
219 + position: absolute;
220 + top: 50%;
221 + left: 50%;
222 + transform: translate(-50%, -50%) scale(1);
223 + z-index: 1;
224 + opacity: 1;
225 + visibility: visible;
226 + overflow: visible;
227 + will-change: transform;
228 + -webkit-transform: translate(-50%, -50%) scale(1);
229 + box-sizing: border-box;
230 + padding: 0;
231 + margin: 0;
232 + }
233 +
234 + .add-button.hidden {
235 + opacity: 0;
236 + transform: translate(-50%, -50%) scale(0.8);
237 + pointer-events: none;
238 + visibility: hidden;
239 + transition:
240 + all 0.3s ease,
241 + visibility 0s 0.2s;
242 + }
243 +
244 + .add-icon,
245 + .confirm-icon,
246 + .cancel-icon,
247 + .delete-icon {
248 + fill: currentColor;
249 + width: 1rem;
250 + height: 1rem;
251 + position: relative;
252 + display: block;
253 + transform: translateZ(0);
254 + }
255 +
256 + .add-button:hover {
257 + opacity: 0.9;
258 + transform: translate(-50%, -50%) scale(1);
259 + -webkit-transform: translate(-50%, -50%) scale(1);
260 + }
261 +
262 + .input-state {
263 + display: flex;
264 + align-items: center;
265 + gap: 0.125rem;
266 + background-color: var(--astro-code-background);
267 + border: 1px solid var(--code-bg);
268 + border-radius: 18px;
269 + padding: 0.28125rem 0.375rem;
270 + width: 40px;
271 + max-width: 40px;
272 + opacity: 0;
273 + overflow: hidden;
274 + transition: all 0.3s ease;
275 + position: relative;
276 + z-index: 2;
277 + pointer-events: none;
278 + }
279 +
280 + .input-state.active {
281 + width: 10rem;
282 + max-width: 10rem;
283 + opacity: 1;
284 + pointer-events: all;
285 + }
286 +
287 + .tag-input {
288 + background: transparent;
289 + border: none;
290 + outline: none;
291 + color: var(--text-primary);
292 + font-size: 0.9rem;
293 + font-family: var(--font-mono);
294 + min-width: 4rem;
295 + padding: 0.25rem 0.5rem;
296 + opacity: 0;
297 + transform: translateX(-8px);
298 + transition:
299 + opacity 0.2s ease 0.15s,
300 + transform 0.2s ease 0.15s;
301 + }
302 +
303 + .input-state.active .tag-input {
304 + opacity: 1;
305 + transform: translateX(0);
306 + }
307 +
308 + .tag-input::placeholder {
309 + color: var(--text-tertiary);
310 + }
311 +
312 + .confirm-button,
313 + .cancel-button {
314 + background: none;
315 + border: none;
316 + border-radius: 50%;
317 + width: 24px;
318 + height: 24px;
319 + cursor: pointer;
320 + display: flex;
321 + align-items: center;
322 + justify-content: center;
323 + font-size: 0.8rem;
324 + opacity: 0;
325 + transform: scale(0.8);
326 + transition: all 0.2s ease;
327 + position: relative;
328 + min-width: 24px;
329 + min-height: 24px;
330 + }
331 +
332 + .confirm-button::before,
333 + .cancel-button::before {
334 + content: '';
335 + position: absolute;
336 + top: 50%;
337 + left: 50%;
338 + transform: translate(-50%, -50%);
339 + border-radius: 50%;
340 + background-color: var(--code-bg);
341 + opacity: 0;
342 + transition: opacity 0.2s ease;
343 + z-index: -1;
344 + width: 28px;
345 + height: 28px;
346 + }
347 +
348 + .confirm-button:hover::before,
349 + .cancel-button:hover::before {
350 + opacity: 1;
351 + }
352 +
353 + .input-state.active .confirm-button,
354 + .input-state.active .cancel-button {
355 + transform: scale(1);
356 + }
357 +
358 + .confirm-button {
359 + color: var(--text-primary);
360 + opacity: 0.6;
361 + }
362 +
363 + .confirm-button.disabled {
364 + opacity: 0.3;
365 + cursor: not-allowed;
366 + }
367 +
368 + .confirm-button:not(.disabled):hover {
369 + opacity: 1;
370 + }
371 +
372 + .confirm-button.disabled:hover::before {
373 + opacity: 0;
374 + }
375 +
376 + .cancel-button {
377 + color: var(--text-primary);
378 + opacity: 0.6;
379 + }
380 +
381 + .cancel-button:hover {
382 + opacity: 1;
383 + }
384 +
385 + .tag-display {
386 + display: flex;
387 + align-items: center;
388 + gap: 0.25rem;
389 + background-color: var(--astro-code-background);
390 + border: 1px solid var(--code-bg);
391 + border-radius: 18px;
392 + padding: 0.28125rem 0.325rem 0.28125rem 0.75rem;
393 + position: absolute;
394 + top: 50%;
395 + left: 50%;
396 + transform: translate(-50%, -50%);
397 + z-index: 3;
398 + opacity: 0;
399 + pointer-events: none;
400 + transition: all 0.25s ease-out;
401 + will-change: transform, opacity;
402 + }
403 +
404 + .tag-display > * {
405 + margin-right: 0.125rem;
406 + }
407 +
408 + .tag-display > *:last-child {
409 + margin-right: 0;
410 + }
411 +
412 + .tag-display.active {
413 + opacity: 1;
414 + transform: translate(-50%, -50%);
415 + pointer-events: all;
416 + }
417 +
418 + .tag-text {
419 + color: var(--text-primary);
420 + font-size: 0.9rem;
421 + font-family: var(--font-mono);
422 + }
423 +
424 + .delete-button {
425 + background: none;
426 + border: none;
427 + border-radius: 50%;
428 + width: 24px;
429 + height: 24px;
430 + cursor: pointer;
431 + display: flex;
432 + align-items: center;
433 + justify-content: center;
434 + font-size: 0.8rem;
435 + color: var(--text-primary);
436 + opacity: 0.6;
437 + transition: all 0.2s ease;
438 + position: relative;
439 + min-width: 24px;
440 + min-height: 24px;
441 + }
442 +
443 + .delete-button::before {
444 + content: '';
445 + position: absolute;
446 + top: 50%;
447 + left: 50%;
448 + transform: translate(-50%, -50%);
449 + border-radius: 50%;
450 + background-color: var(--code-bg);
451 + opacity: 0;
452 + transition: opacity 0.2s ease;
453 + z-index: -1;
454 + width: 28px;
455 + height: 28px;
456 + }
457 +
458 + .delete-button:hover {
459 + opacity: 1;
460 + }
461 +
462 + .delete-button:hover::before {
463 + opacity: 1;
464 + }
465 +</style>
src/components/features/FootnoteScroll.astro new
+33
@@ -0,0 +1,33 @@
1 +<script>
2 + function bindFootnoteEvents() {
3 + const footnoteLinks = document.querySelectorAll('[data-footnote-ref], [data-footnote-backref]')
4 +
5 + footnoteLinks.forEach((link) => {
6 + link.addEventListener('click', (e) => {
7 + e.preventDefault()
8 + const href = link.getAttribute('href')
9 + if (!href) return
10 +
11 + const target = document.querySelector(href)
12 + if (!target) return
13 +
14 + // Use fixed offset of 128px
15 + const offset = 128
16 +
17 + const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset
18 +
19 + window.scrollTo({
20 + top: targetPosition
21 + })
22 + })
23 + })
24 + }
25 +
26 + document.addEventListener('astro:page-load', () => {
27 + bindFootnoteEvents()
28 + })
29 +
30 + document.addEventListener('DOMContentLoaded', () => {
31 + bindFootnoteEvents()
32 + })
33 +</script>
src/components/features/FormattedDate.astro new
+29
@@ -0,0 +1,29 @@
1 +---
2 +import { formatDate } from '@/utils/date'
3 +import { SITE } from '@/config'
4 +
5 +interface Props {
6 + date: Date
7 + format?: string
8 +}
9 +
10 +const { date, format } = Astro.props
11 +---
12 +
13 +<time
14 + datetime={date.toISOString()}
15 + class={!SITE.dateOnRight &&
16 + (SITE.dateFormat === 'MONTH DAY YYYY' || SITE.dateFormat === 'DAY MONTH YYYY')
17 + ? 'date-left'
18 + : ''}
19 +>
20 + <Fragment set:html={formatDate(date, format)} />
21 +</time>
22 +
23 +<style>
24 + .date-left {
25 + display: inline-block;
26 + min-width: 86px;
27 + text-align: right;
28 + }
29 +</style>
src/components/features/PostList.astro new
+105
@@ -0,0 +1,105 @@
1 +---
2 +import FormattedDate from '@/components/features/FormattedDate.astro'
3 +import type { CollectionEntry } from 'astro:content'
4 +import { SITE } from '@/config'
5 +
6 +interface Props {
7 + posts: CollectionEntry<'posts'>[]
8 +}
9 +
10 +const { posts } = Astro.props
11 +---
12 +
13 +<ul>
14 + {
15 + posts.map((post) => (
16 + <li>
17 + <a href={`/${post.id}/`}>
18 + <div class={`post-item ${!SITE.dateOnRight ? 'date-left' : ''}`}>
19 + {!SITE.dateOnRight && (
20 + <p class="date font-features">
21 + <FormattedDate date={post.data.pubDate} />
22 + </p>
23 + )}
24 + <p class="title">{post.data.title}</p>
25 + {SITE.dateOnRight && <div class="divider" />}
26 + {SITE.dateOnRight && (
27 + <p class="date font-features">
28 + <FormattedDate date={post.data.pubDate} />
29 + </p>
30 + )}
31 + </div>
32 + </a>
33 + </li>
34 + ))
35 + }
36 +</ul>
37 +<div class="placeholder"></div>
38 +
39 +<style>
40 + ul {
41 + padding: 0;
42 + margin: 0;
43 + list-style-type: none;
44 + display: flex;
45 + flex-direction: column;
46 + gap: 0;
47 + }
48 +
49 + a {
50 + color: var(--text-primary);
51 + display: block;
52 + text-decoration: none;
53 + transition: opacity 0.15s ease-out;
54 + }
55 +
56 + ul:hover a {
57 + opacity: 0.4;
58 + }
59 +
60 + ul:hover a:hover {
61 + opacity: 1;
62 + }
63 +
64 + .post-item {
65 + height: 2.75rem;
66 + display: flex;
67 + justify-content: space-between;
68 + align-items: center;
69 + gap: 1rem;
70 + }
71 +
72 + .post-item.date-left {
73 + justify-content: flex-start;
74 + }
75 +
76 + .post-item.date-left .title {
77 + flex: 1 1 auto;
78 + min-width: 0;
79 + }
80 +
81 + .title {
82 + margin: 0;
83 + white-space: nowrap;
84 + overflow: hidden;
85 + text-overflow: ellipsis;
86 + }
87 +
88 + .date {
89 + margin: 0;
90 + color: var(--text-secondary);
91 + letter-spacing: var(--spacing-s);
92 + flex-shrink: 0;
93 + }
94 +
95 + .divider {
96 + flex: 1;
97 + min-width: 24px;
98 + height: 0.5px;
99 + background-color: var(--border);
100 + }
101 +
102 + .placeholder {
103 + height: 3rem;
104 + }
105 +</style>
src/components/layout/BaseHead.astro new
+97
@@ -0,0 +1,97 @@
1 +---
2 +// Import the global.css file here so that it is included on
3 +// all pages through the use of the <BaseHead /> component.
4 +import { SITE } from '@/config'
5 +import type { BaseHeadProps } from '@/types/component.types'
6 +import 'katex/dist/katex.min.css'
7 +
8 +const canonicalURL = new URL(Astro.url.pathname, Astro.site)
9 +
10 +const { title, description } = Astro.props as BaseHeadProps
11 +---
12 +
13 +<!-- Global Metadata -->
14 +<meta charset="utf-8" />
15 +<meta name="viewport" content="width=device-width,initial-scale=1" />
16 +{SITE.fadeAnimation && <meta name="view-transition" content="same-origin" />}
17 +<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
18 +<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
19 +<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
20 +<link rel="manifest" href="/favicon/site.webmanifest" />
21 +<link rel="preload" href="/fonts/Inter.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
22 +<link
23 + rel="preload"
24 + href="/fonts/Besley-Italic.woff2"
25 + as="font"
26 + type="font/woff2"
27 + crossorigin="anonymous"
28 +/>
29 +<link rel="sitemap" href="/sitemap-index.xml" />
30 +<link
31 + rel="alternate"
32 + type="application/rss+xml"
33 + title={SITE.title}
34 + href={new URL('rss.xml', Astro.site)}
35 +/>
36 +<meta name="generator" content={Astro.generator} />
37 +
38 +<!-- Canonical URL -->
39 +<link rel="canonical" href={canonicalURL} />
40 +
41 +<!-- Primary Meta Tags -->
42 +<title>
43 + {title || SITE.title}
44 +</title>
45 +<meta name="title" content={title} />
46 +<meta name="description" content={description} />
47 +
48 +<!-- Open Graph / Facebook -->
49 +<meta property="og:type" content="website" />
50 +<meta property="og:url" content={Astro.url} />
51 +<meta property="og:title" content={title} />
52 +<meta property="og:description" content={description} />
53 +<meta property="og:image" content={new URL('/chiri-og.png', Astro.url)} />
54 +
55 +<!-- Twitter -->
56 +<meta property="twitter:card" content="summary_large_image" />
57 +<meta property="twitter:url" content={Astro.url} />
58 +<meta property="twitter:title" content={title} />
59 +<meta property="twitter:description" content={description} />
60 +<meta property="twitter:image" content={new URL('/chiri-og.png', Astro.url)} />
61 +
62 +<!-- Transitions Initialization -->
63 +<script is:inline define:vars={{ fadeAnimation: SITE.fadeAnimation }}>
64 + function initMotionPref(doc = document) {
65 + const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
66 + const supportsViewTransitions = 'startViewTransition' in document
67 +
68 + doc.documentElement.classList.toggle('reduce-motion', prefersReducedMotion)
69 +
70 + doc.documentElement.classList.toggle(
71 + 'disable-transitions',
72 + !fadeAnimation || !supportsViewTransitions
73 + )
74 +
75 + doc.documentElement.classList.add('js')
76 + }
77 +
78 + initMotionPref()
79 +
80 + document.addEventListener('astro:before-swap', ({ newDocument }) => {
81 + initMotionPref(newDocument)
82 + })
83 +
84 + document.addEventListener('astro:page-load', () => {
85 + initMotionPref()
86 + })
87 +
88 + document.addEventListener('visibilitychange', () => {
89 + if (document.visibilityState === 'visible') {
90 + initMotionPref()
91 + }
92 + })
93 +
94 + window.addEventListener('pageshow', () => {
95 + initMotionPref()
96 + })
97 +</script>
src/components/layout/Footer.astro new
+111
@@ -0,0 +1,111 @@
1 +---
2 +import { SITE } from '@/config'
3 +const today = new Date()
4 +---
5 +
6 +<footer>
7 + <div class="footer-content">
8 + <div class="footer-links">
9 + <nav class="footer-nav">
10 + <a href="/contact">Contact</a>
11 + <a href="/privacy-policy">Privacy Policy</a>
12 + <a href="/terms-of-use">Terms of Use</a>
13 + </nav>
14 + </div>
15 + <div class="footer-bottom">
16 + <div class="copyright">
17 + <span class="date">
18 + &copy;
19 + {today.getFullYear()}
20 + </span>
21 + {SITE.author}
22 + </div>
23 + <div class="powered-by">
24 + Powered by{' '}
25 + <a href="https://smbcloud.xyz" target="__blank">smbCloud</a>
26 + </div>
27 + </div>
28 + </div>
29 +</footer>
30 +<style>
31 + footer {
32 + font-size: var(--font-size-s);
33 + font-weight: var(--font-weight-light);
34 + line-height: 1.75;
35 + color: var(--text-secondary);
36 + margin-top: 4rem;
37 + }
38 +
39 + .footer-content {
40 + display: flex;
41 + flex-direction: column;
42 + gap: 1.5rem;
43 + width: 100%;
44 + }
45 +
46 + .footer-links {
47 + padding-bottom: 1rem;
48 + border-bottom: 1px solid var(--border);
49 + }
50 +
51 + .footer-nav {
52 + display: flex;
53 + gap: 1.5rem;
54 + justify-content: center;
55 + flex-wrap: wrap;
56 + }
57 +
58 + .footer-nav a {
59 + color: var(--text-secondary);
60 + text-decoration: none;
61 + padding: 0.25rem 0.5rem;
62 + border-radius: 0.25rem;
63 + transition: all 0.2s ease-out;
64 + }
65 +
66 + .footer-nav a:hover {
67 + color: var(--text-primary);
68 + background-color: var(--code-bg);
69 + }
70 +
71 + .footer-bottom {
72 + display: flex;
73 + justify-content: space-between;
74 + align-items: center;
75 + flex-direction: row;
76 + flex-wrap: nowrap;
77 + width: 100%;
78 + }
79 +
80 + .copyright,
81 + .powered-by {
82 + white-space: nowrap;
83 + }
84 +
85 + .powered-by a {
86 + color: var(--text-secondary);
87 + text-decoration: none;
88 + transition: color 0.2s ease-out;
89 + }
90 +
91 + .powered-by a:hover {
92 + color: var(--text-primary);
93 + }
94 +
95 + @media (max-width: 768px) {
96 + .footer-nav {
97 + gap: 1rem;
98 + }
99 +
100 + .footer-bottom {
101 + flex-direction: column;
102 + gap: 0.75rem;
103 + text-align: center;
104 + }
105 +
106 + .copyright,
107 + .powered-by {
108 + white-space: normal;
109 + }
110 + }
111 +</style>
src/components/layout/Header.astro new
+98
@@ -0,0 +1,98 @@
1 +---
2 +import { SITE } from '@/config'
3 +import ThemeToggle from '@/components/ui/ThemeToggle.astro'
4 +---
5 +
6 +<header>
7 + <nav>
8 + <div class="logo-container">
9 + {SITE.favicon && <img src="/favicon.svg" alt="favicon" class="favicon" />}
10 + <a href="/">{SITE.title}</a>
11 + </div>
12 + <div class="header-right">
13 + <a href="/#join-us" class="download-link">Join Us</a>
14 + <ThemeToggle />
15 + </div>
16 + </nav>
17 +</header>
18 +<style>
19 + header {
20 + margin: 0 0 1.75rem 0;
21 + }
22 +
23 + nav {
24 + display: flex;
25 + justify-content: space-between;
26 + align-items: center;
27 + gap: 1rem;
28 + flex-wrap: wrap;
29 + }
30 +
31 + header a {
32 + font-weight: var(--font-weight-bold);
33 + color: var(--text-primary);
34 + text-decoration: none;
35 + min-width: 3rem;
36 + display: inline-block;
37 + }
38 +
39 + .logo-container {
40 + position: relative;
41 + }
42 +
43 + .header-right {
44 + display: flex;
45 + align-items: center;
46 + gap: 1rem;
47 + flex-wrap: wrap;
48 + }
49 +
50 + .download-link {
51 + padding: 0.5rem 1rem;
52 + background-color: var(--accent);
53 + color: white;
54 + border-radius: 0.5rem;
55 + font-size: 0.95rem;
56 + transition: all 0.2s ease;
57 + }
58 +
59 + .download-link:hover {
60 + background-color: var(--accent-dark);
61 + transform: translateY(-2px);
62 + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
63 + }
64 +
65 + .download-link:active {
66 + transform: translateY(0);
67 + }
68 +
69 + .favicon {
70 + position: absolute;
71 + width: 1.125rem;
72 + height: 1.125rem;
73 + bottom: calc(100% + 3.5rem);
74 + left: 0;
75 + }
76 +
77 + @media (max-width: 480px) {
78 + nav {
79 + justify-content: center;
80 + }
81 +
82 + .logo-container {
83 + width: 100%;
84 + text-align: center;
85 + margin-bottom: 0.5rem;
86 + }
87 +
88 + .header-right {
89 + width: 100%;
90 + justify-content: center;
91 + }
92 +
93 + .download-link {
94 + font-size: 0.9rem;
95 + padding: 0.45rem 0.85rem;
96 + }
97 + }
98 +</style>
src/components/layout/TransitionWrapper.astro new
+89
@@ -0,0 +1,89 @@
1 +---
2 +import { SITE } from '@/config'
3 +import type { TransitionProps } from '@/types'
4 +
5 +type Props = TransitionProps
6 +
7 +const { type, class: className = '' } = Astro.props
8 +const transitionName = type === 'post' ? 'post-content' : 'page-content'
9 +---
10 +
11 +{
12 + SITE.fadeAnimation ? (
13 + <div transition:name={transitionName} transition:animate="initial" class={className}>
14 + <slot />
15 + </div>
16 + ) : (
17 + <div class={className}>
18 + <slot />
19 + </div>
20 + )
21 +}
22 +
23 +<style is:global>
24 + @supports (view-transition-name: none) {
25 + @media not (prefers-reduced-motion: reduce) {
26 + ::view-transition-old(post-content),
27 + ::view-transition-old(page-content) {
28 + animation: fade-out 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
29 + }
30 +
31 + ::view-transition-new(post-content),
32 + ::view-transition-new(page-content) {
33 + opacity: 0;
34 + animation: fade-in 0.4s ease 0.2s forwards;
35 + }
36 + }
37 + }
38 +
39 + @keyframes fade-out {
40 + 0% {
41 + opacity: 1;
42 + }
43 + 100% {
44 + opacity: 0;
45 + }
46 + }
47 +
48 + @keyframes fade-in {
49 + 0% {
50 + opacity: 0;
51 + filter: blur(8px);
52 + }
53 + 30% {
54 + opacity: 0.5;
55 + filter: blur(4px);
56 + }
57 + 100% {
58 + opacity: 1;
59 + filter: blur(0);
60 + }
61 + }
62 +
63 + .no-fade ::view-transition-old(post-content),
64 + .no-fade ::view-transition-new(post-content),
65 + .no-fade ::view-transition-old(page-content),
66 + .no-fade ::view-transition-new(page-content),
67 + .disable-transitions ::view-transition-old(post-content),
68 + .disable-transitions ::view-transition-new(post-content),
69 + .disable-transitions ::view-transition-old(page-content),
70 + .disable-transitions ::view-transition-new(page-content) {
71 + animation: none !important;
72 + }
73 +
74 + .reduce-motion ::view-transition-old(post-content),
75 + .reduce-motion ::view-transition-new(post-content),
76 + .reduce-motion ::view-transition-old(page-content),
77 + .reduce-motion ::view-transition-new(page-content) {
78 + animation: none !important;
79 + }
80 +
81 + @media (prefers-reduced-motion: reduce) {
82 + * {
83 + animation-duration: 0.01ms !important;
84 + transition-duration: 0.01ms !important;
85 + animation-iteration-count: 1 !important;
86 + scroll-behavior: auto !important;
87 + }
88 + }
89 +</style>
src/components/pages/About.astro new
+120
@@ -0,0 +1,120 @@
1 +---
2 +import { getEntry } from 'astro:content'
3 +import { render } from 'astro:content'
4 +import { Image } from 'astro:assets'
5 +
6 +const aboutEntry = await getEntry('about', 'about')
7 +// Check if there is actual content (excluding comments)
8 +const hasContent = aboutEntry?.body
9 + ? aboutEntry.body.replace(/<!--[\s\S]*?-->/g, '').trim().length > 0
10 + : false
11 +const { Content } = hasContent && aboutEntry ? await render(aboutEntry) : { Content: null }
12 +---
13 +
14 +{
15 + hasContent && Content && (
16 + <div class="about prose">
17 + <div class="app-header">
18 + <Image
19 + src="/images/1f3f5-fe0f.png"
20 + alt="SuperTeam Stockholm App Icon"
21 + width="120"
22 + height="120"
23 + class="app-icon"
24 + />
25 + </div>
26 + <Content />
27 + <div id="join-us" class="download-badges">
28 + <h2>Join Us</h2>
29 + <div class="badge-container">
30 + <a
31 + href="https://t.me/+H5UTU3562KoyYTA8"
32 + target="_blank"
33 + class="store-badge"
34 + aria-label="Join our Telegram channel"
35 + >
36 + <img
37 + src="https://upload.wikimedia.org/wikipedia/commons/8/82/Telegram_logo.svg"
38 + alt="Join our Telegram channel"
39 + class="badge-image"
40 + />
41 + </a>
42 + </div>
43 + </div>
44 + </div>
45 + )
46 +}
47 +
48 +<style>
49 + .about:not(:empty) {
50 + margin-bottom: 1.25rem;
51 + }
52 +
53 + .app-header {
54 + text-align: center;
55 + margin-bottom: 2rem;
56 + }
57 +
58 + .app-icon {
59 + border-radius: 22%;
60 + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
61 + }
62 +
63 + .download-badges {
64 + margin-top: 3rem;
65 + padding-top: 2rem;
66 + border-top: 1px solid var(--border-color, #e5e7eb);
67 + text-align: center;
68 + scroll-margin-top: 2rem;
69 + }
70 +
71 + .download-badges h2 {
72 + margin-bottom: 1.5rem;
73 + font-size: 1.5rem;
74 + }
75 +
76 + .badge-container {
77 + display: flex;
78 + justify-content: center;
79 + align-items: center;
80 + gap: 1rem;
81 + flex-wrap: wrap;
82 + margin-bottom: 1rem;
83 + }
84 +
85 + .store-badge {
86 + display: inline-block;
87 + transition:
88 + transform 0.2s ease,
89 + opacity 0.2s ease;
90 + }
91 +
92 + .store-badge:hover {
93 + transform: scale(1.05);
94 + opacity: 0.9;
95 + }
96 +
97 + .badge-image {
98 + height: 50px;
99 + width: auto;
100 + display: block;
101 + }
102 +
103 + .coming-soon {
104 + font-size: 0.9rem;
105 + color: var(--text-secondary, #6b7280);
106 + font-style: italic;
107 + margin-top: 0.5rem;
108 + }
109 +
110 + @media (max-width: 640px) {
111 + .badge-container {
112 + flex-direction: column;
113 + gap: 0.75rem;
114 + }
115 +
116 + .badge-image {
117 + height: 45px;
118 + }
119 + }
120 +</style>
src/components/ui/BackButton.astro new
+111
@@ -0,0 +1,111 @@
1 +---
2 +import { SITE } from '@/config'
3 +---
4 +
5 +<a href="/" class="back-button">
6 + <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
7 + <path
8 + d="M2.5 6.5H9.5C11.1569 6.5 12.5 7.84315 12.5 9.5V9.5C12.5 11.1569 11.1569 12.5 9.5 12.5H7.5M2.5 6.5L5.5 9.5M2.5 6.5L5.5 3.5"
9 + stroke="currentColor"
10 + stroke-width="1.25"
11 + stroke-linecap="round"
12 + stroke-linejoin="round"></path>
13 + </svg>
14 + index
15 +</a>
16 +
17 +<script
18 + is:inline
19 + define:vars={{
20 + contentWidth: SITE.contentWidth,
21 + centeredLayout: SITE.centeredLayout,
22 + toc: SITE.toc
23 + }}
24 +>
25 + ;(function () {
26 + // Adjust back button position based on layout and screen size
27 + function adjustBackButtonPosition() {
28 + const button = document.querySelector('.back-button')
29 + if (!button) return
30 +
31 + // If not using centered layout, remove fixed positioning
32 + if (!centeredLayout) {
33 + button.classList.remove('fixed-position')
34 + button.style.left = ''
35 + return
36 + }
37 +
38 + // Calculate available margin space for positioning
39 + const pageWidth = window.innerWidth
40 + const contentWidthValue = parseFloat(contentWidth)
41 + const margin = (pageWidth - contentWidthValue * 16) / 2
42 + const baseMinSpace = 11 * 16 // Base minimum space needed
43 + // If toc is enabled, need additional 2.5rem (40px) space
44 + const minSpace = toc ? baseMinSpace + 40 : baseMinSpace
45 +
46 + // Position button fixed on the left if there's enough space
47 + if (margin >= minSpace) {
48 + button.classList.add('fixed-position')
49 + const basePosition = margin - baseMinSpace
50 + // If toc is enabled, move 2.5rem (40px) further left
51 + const leftPosition = toc ? basePosition - 40 : basePosition
52 + button.style.left = `${leftPosition}px`
53 + } else {
54 + button.classList.remove('fixed-position')
55 + button.style.left = ''
56 + }
57 + }
58 +
59 + adjustBackButtonPosition()
60 +
61 + document.addEventListener('astro:page-load', () => {
62 + adjustBackButtonPosition()
63 + })
64 + document.addEventListener('DOMContentLoaded', () => {
65 + adjustBackButtonPosition()
66 + })
67 + window.addEventListener('resize', adjustBackButtonPosition)
68 + })()
69 +</script>
70 +
71 +<style>
72 + .back-button {
73 + width: 8rem;
74 + display: inline-flex;
75 + align-items: center;
76 + gap: 0.375rem;
77 + font-family: var(--font-serif);
78 + font-size: var(--font-size-m);
79 + font-style: italic;
80 + letter-spacing: 0;
81 + line-height: 1.75;
82 + color: var(--text-secondary);
83 + cursor: pointer;
84 + border: none;
85 + background-color: transparent;
86 + position: relative;
87 + margin-bottom: 2.5em;
88 + padding: 0;
89 + left: -0.175em;
90 + transition: color 0.2s ease-out;
91 + text-decoration: none;
92 + }
93 +
94 + .back-button:hover {
95 + color: var(--text-primary);
96 + }
97 +
98 + .back-button svg {
99 + width: 0.8rem;
100 + height: 0.8rem;
101 + flex-shrink: 0;
102 + }
103 +
104 + .back-button.fixed-position {
105 + position: fixed;
106 + top: 6rem;
107 + margin-bottom: 0;
108 + padding-left: 1rem;
109 + z-index: 10;
110 + }
111 +</style>
src/components/ui/CopyCode.astro new
+179
@@ -0,0 +1,179 @@
1 +---
2 +import { SITE } from '@/config'
3 +---
4 +
5 +<script define:vars={{ copyCode: SITE.copyCode }}>
6 + function initCopyCode() {
7 + const copyIcon = `
8 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="14" height="14" fill="currentColor">
9 + <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path>
10 + <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
11 + </svg>
12 + `
13 +
14 + const copiedIcon = `
15 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
16 + <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
17 + </svg>
18 + `
19 +
20 + document.documentElement.setAttribute('data-copy-code', copyCode ? 'enabled' : 'disabled')
21 +
22 + if (!copyCode) {
23 + return
24 + }
25 +
26 + const copyButtons = document.querySelectorAll('.copy-button')
27 +
28 + copyButtons.forEach((button) => {
29 + const preElement = button.closest('.copy-code-block')
30 + if (!preElement) return
31 +
32 + const codeElement = preElement.querySelector('code')
33 + if (!codeElement) return
34 +
35 + if (!button.querySelector('svg')) {
36 + button.innerHTML = copyIcon
37 + }
38 +
39 + button.style.opacity = '0'
40 + button.style.pointerEvents = 'none'
41 +
42 + preElement.addEventListener('mouseenter', () => {
43 + button.style.opacity = '1'
44 + button.style.pointerEvents = 'auto'
45 + })
46 +
47 + preElement.addEventListener('mouseleave', () => {
48 + if (!button.hasAttribute('data-copying')) {
49 + button.style.opacity = '0'
50 + button.style.pointerEvents = 'none'
51 + }
52 + })
53 +
54 + button.addEventListener('click', async () => {
55 + const codeText = codeElement.textContent || ''
56 +
57 + try {
58 + // Primary method: use modern clipboard API
59 + await navigator.clipboard.writeText(codeText)
60 + button.setAttribute('data-copying', 'true')
61 + button.innerHTML = copiedIcon
62 +
63 + setTimeout(() => {
64 + if (!preElement.matches(':hover')) {
65 + button.style.opacity = '0'
66 + button.style.pointerEvents = 'none'
67 + }
68 + button.removeAttribute('data-copying')
69 +
70 + setTimeout(() => {
71 + button.innerHTML = copyIcon
72 + }, 500)
73 + }, 1500)
74 + } catch (err) {
75 + console.error('Failed to copy code:', err)
76 +
77 + // Fallback method: create temporary textarea for older browsers
78 + try {
79 + const textArea = document.createElement('textarea')
80 + textArea.value = codeText
81 + textArea.style.position = 'fixed'
82 + textArea.style.opacity = '0'
83 + document.body.appendChild(textArea)
84 + textArea.focus()
85 + textArea.select()
86 +
87 + navigator.clipboard
88 + .writeText(codeText)
89 + .then(() => {
90 + document.body.removeChild(textArea)
91 + })
92 + .catch(() => {
93 + console.error('Both clipboard methods failed')
94 + document.body.removeChild(textArea)
95 + })
96 + } catch (fallbackErr) {
97 + console.error('All clipboard methods failed:', fallbackErr)
98 + }
99 +
100 + button.setAttribute('data-copying', 'true')
101 + button.innerHTML = copiedIcon
102 +
103 + setTimeout(() => {
104 + if (!preElement.matches(':hover')) {
105 + button.style.opacity = '0'
106 + button.style.pointerEvents = 'none'
107 + }
108 + button.removeAttribute('data-copying')
109 +
110 + setTimeout(() => {
111 + button.innerHTML = copyIcon
112 + }, 500)
113 + }, 1500)
114 + }
115 + })
116 + })
117 + }
118 +
119 + document.addEventListener('astro:page-load', initCopyCode)
120 + document.addEventListener('DOMContentLoaded', initCopyCode)
121 +</script>
122 +
123 +<style is:global>
124 + .copy-code-block {
125 + position: relative !important;
126 + }
127 +
128 + .copy-button {
129 + position: absolute;
130 + top: 0.5rem;
131 + right: 0.5rem;
132 + width: 2rem;
133 + height: 2rem;
134 + z-index: 10;
135 + background: var(--bg);
136 + border-radius: 0.375rem;
137 + font-size: 0.75rem;
138 + color: var(--text-secondary);
139 + cursor: pointer;
140 + transition: all 0.15s ease-out;
141 + display: flex;
142 + align-items: center;
143 + justify-content: center;
144 + border: 1px solid var(--border);
145 + backdrop-filter: blur(48px);
146 + }
147 +
148 + [data-copy-code='disabled'] .copy-button {
149 + display: none !important;
150 + }
151 +
152 + .copy-button::before {
153 + content: '';
154 + position: absolute;
155 + top: 0;
156 + left: 0;
157 + right: 0;
158 + bottom: 0;
159 + background: var(--code-bg);
160 + border-radius: 0.325rem;
161 + opacity: 0;
162 + transition: opacity 0.15s ease-out;
163 + pointer-events: none;
164 + }
165 +
166 + .copy-button:hover::before {
167 + opacity: 1;
168 + }
169 +
170 + .copy-button:hover {
171 + color: var(--text-primary);
172 + }
173 +
174 + .copy-button svg {
175 + flex-shrink: 0;
176 + position: relative;
177 + z-index: 1;
178 + }
179 +</style>
src/components/ui/GitHubCard.astro new
+259
@@ -0,0 +1,259 @@
1 +<script>
2 + let githubCardsObserver: IntersectionObserver | null = null
3 +
4 + interface GitHubRepoData {
5 + owner?: {
6 + avatar_url: string
7 + }
8 + description?: string
9 + stargazers_count?: number
10 + forks_count?: number
11 + license?: {
12 + spdx_id: string
13 + }
14 + }
15 +
16 + interface CachedRepoData {
17 + data: GitHubRepoData
18 + timestamp: number
19 + }
20 +
21 + // Retrieve cached GitHub repository data from localStorage with expiration check
22 + function getCachedData(repo: string): GitHubRepoData | null {
23 + try {
24 + const cacheKey = `github-repo-${repo}`
25 + const cached = localStorage.getItem(cacheKey)
26 +
27 + if (!cached) {
28 + return null
29 + }
30 +
31 + const parsedCache: CachedRepoData = JSON.parse(cached)
32 + const now = Date.now()
33 + const oneHour = 60 * 60 * 1000 // 1 hour in milliseconds
34 +
35 + // Check if cache is expired (older than 1 hour)
36 + if (now - parsedCache.timestamp > oneHour) {
37 + localStorage.removeItem(cacheKey)
38 + return null
39 + }
40 +
41 + return parsedCache.data
42 + } catch (error) {
43 + console.warn('Failed to read from cache:', error)
44 + return null
45 + }
46 + }
47 +
48 + // Store GitHub repository data in localStorage with timestamp for cache expiration
49 + function setCachedData(repo: string, data: GitHubRepoData): void {
50 + try {
51 + const cacheKey = `github-repo-${repo}`
52 + const cacheData: CachedRepoData = {
53 + data,
54 + timestamp: Date.now()
55 + }
56 + localStorage.setItem(cacheKey, JSON.stringify(cacheData))
57 + } catch (error) {
58 + console.warn('Failed to save to cache:', error)
59 + }
60 + }
61 +
62 + interface CardElements {
63 + avatar: HTMLElement | null
64 + desc: HTMLElement | null
65 + stars: HTMLElement | null
66 + forks: HTMLElement | null
67 + license: HTMLElement | null
68 + }
69 +
70 + // Update the GitHub card UI elements with fetched repository data
71 + function updateCardUI(el: CardElements, data: GitHubRepoData) {
72 + const numberFormat = new Intl.NumberFormat('en', {
73 + notation: 'compact',
74 + maximumFractionDigits: 1
75 + })
76 +
77 + if (el.avatar && data.owner?.avatar_url) {
78 + el.avatar.style.backgroundImage = `url(${data.owner.avatar_url})`
79 + }
80 +
81 + if (el.desc) {
82 + el.desc.textContent = data.description ?? 'No description'
83 + }
84 +
85 + if (el.stars) {
86 + el.stars.textContent = numberFormat.format(data.stargazers_count ?? 0)
87 + }
88 +
89 + if (el.forks) {
90 + el.forks.textContent = numberFormat.format(data.forks_count ?? 0)
91 + }
92 +
93 + if (el.license) {
94 + el.license.textContent = data.license?.spdx_id ?? 'No License'
95 + }
96 + }
97 +
98 + // Load GitHub repository data for a card, using cache if available or fetching from API
99 + async function loadCardData(card: HTMLElement) {
100 + const repo = card.dataset.repo
101 + if (!repo) {
102 + return
103 + }
104 +
105 + const el = {
106 + avatar: card.querySelector('.gc-owner-avatar') as HTMLElement,
107 + desc: card.querySelector('.gc-repo-description') as HTMLElement,
108 + stars: card.querySelector('.gc-stars-count') as HTMLElement,
109 + forks: card.querySelector('.gc-forks-count') as HTMLElement,
110 + license: card.querySelector('.gc-license-info') as HTMLElement
111 + } as const
112 +
113 + // Try to get cached data first
114 + const cachedData = getCachedData(repo)
115 + if (cachedData) {
116 + updateCardUI(el, cachedData)
117 + return
118 + }
119 +
120 + // If no cache, fetch from API
121 + try {
122 + const response = await fetch(`https://api.github.com/repos/${repo}`)
123 +
124 + if (!response.ok) {
125 + if (el.desc) {
126 + el.desc.textContent = '⚠ Loading failed'
127 + }
128 + return
129 + }
130 +
131 + const data = await response.json()
132 +
133 + setCachedData(repo, data)
134 +
135 + updateCardUI(el, data)
136 + } catch (error) {
137 + console.error(`Failed to fetch ${repo}:`, error)
138 + if (el.desc) {
139 + el.desc.textContent = '⚠ Loading failed'
140 + }
141 + }
142 + }
143 +
144 + // Set up intersection observer for lazy loading GitHub cards when they enter viewport
145 + function lazySetupGithubCards() {
146 + githubCardsObserver?.disconnect()
147 +
148 + const githubCards = document.getElementsByClassName('gc-container')
149 + if (githubCards.length === 0) {
150 + return
151 + }
152 +
153 + // Create an intersection observer to lazy load GitHub repo data when cards enter viewport
154 + githubCardsObserver = new IntersectionObserver(
155 + (entries) => {
156 + entries.forEach((entry) => {
157 + if (entry.isIntersecting) {
158 + loadCardData(entry.target as HTMLElement)
159 + githubCardsObserver?.unobserve(entry.target)
160 + }
161 + })
162 + },
163 + { rootMargin: '200px' }
164 + )
165 +
166 + Array.from(githubCards).forEach((card) => githubCardsObserver?.observe(card))
167 + }
168 +
169 + lazySetupGithubCards()
170 + document.addEventListener('astro:page-load', lazySetupGithubCards)
171 +</script>
172 +
173 +<style>
174 + :global(.prose .gc-container) {
175 + display: block;
176 + border: 0.5px solid var(--border);
177 + border-radius: 10px;
178 + padding: 1rem 1.25rem 0.75rem 1.25rem;
179 + margin: 1.25rem 0 1.75rem 0;
180 + text-decoration: none;
181 + color: inherit;
182 + transition: background 0.2s ease-out;
183 + background: var(--astro-code-background);
184 + }
185 +
186 + :global(.prose .gc-container:hover) {
187 + background: var(--code-bg);
188 + text-decoration: none;
189 + }
190 +
191 + :global(.prose .gc-title-bar) {
192 + display: flex;
193 + align-items: center;
194 + gap: 0.75rem;
195 + margin-bottom: 0.75rem;
196 + }
197 +
198 + :global(.prose .gc-owner-avatar) {
199 + width: 1.5rem;
200 + height: 1.5rem;
201 + border-radius: 50%;
202 + background-color: var(--border);
203 + flex-shrink: 0;
204 + }
205 +
206 + :global(.prose .gc-repo-title) {
207 + font-size: var(--font-size-xl);
208 + font-weight: var(--font-weight-regular);
209 + color: var(--text-primary);
210 + flex-grow: 1;
211 + }
212 +
213 + :global(.prose .gc-repo-title strong) {
214 + font-weight: var(--font-weight-bold);
215 + }
216 +
217 + :global(.prose .gc-slash) {
218 + color: var(--text-secondary);
219 + margin: 0 0.375rem;
220 + }
221 +
222 + :global(.prose .gc-github-icon) {
223 + width: 1.5rem;
224 + height: 1.5rem;
225 + color: var(--text-primary);
226 + flex-shrink: 0;
227 + }
228 +
229 + :global(.prose .gc-repo-description) {
230 + font-size: var(--font-size-m);
231 + color: var(--text-primary);
232 + opacity: 0.75;
233 + margin: 0 0 0.75rem 0;
234 + line-height: 1.4;
235 + }
236 +
237 + :global(.prose .gc-info-bar) {
238 + display: flex;
239 + align-items: center;
240 + color: var(--text-primary);
241 + opacity: 0.75;
242 + gap: 0.35rem;
243 + }
244 +
245 + :global(
246 + .prose .gc-info-bar .gc-stars-count,
247 + .prose .gc-info-bar .gc-forks-count,
248 + .prose .gc-info-bar .gc-license-info
249 + ) {
250 + margin-right: 0.675rem;
251 + font-size: var(--font-size-s);
252 + }
253 +
254 + :global(.prose .gc-info-icon) {
255 + color: var(--text-primary);
256 + width: 0.875rem;
257 + height: 0.875rem;
258 + }
259 +</style>
src/components/ui/GradientMask.astro new
+55
@@ -0,0 +1,55 @@
1 +<div class="gradient-mask">
2 + <slot />
3 +</div>
4 +
5 +<script>
6 + function updateMask() {
7 + const mask = document.querySelector('.gradient-mask') as HTMLElement
8 + const threshold = 64
9 + const scrollY = window.scrollY
10 +
11 + if (scrollY >= threshold) {
12 + mask.style.opacity = '1'
13 + } else {
14 + mask.style.opacity = '0'
15 + }
16 + }
17 +
18 + document.addEventListener('DOMContentLoaded', () => {
19 + updateMask()
20 + window.addEventListener('scroll', updateMask)
21 + })
22 +</script>
23 +
24 +<style>
25 + .gradient-mask {
26 + position: fixed;
27 + top: 0;
28 + left: 0;
29 + width: 100%;
30 + height: 6rem;
31 + z-index: 99;
32 + pointer-events: none;
33 + background: linear-gradient(to bottom, var(--bg) 0%, transparent 100%);
34 + mask-image: linear-gradient(
35 + to bottom,
36 + black 0%,
37 + rgba(0, 0, 0, 0.8) 20%,
38 + rgba(0, 0, 0, 0.6) 40%,
39 + rgba(0, 0, 0, 0.4) 60%,
40 + rgba(0, 0, 0, 0.2) 80%,
41 + transparent 100%
42 + );
43 + -webkit-mask-image: linear-gradient(
44 + to bottom,
45 + black 0%,
46 + rgba(0, 0, 0, 0.8) 20%,
47 + rgba(0, 0, 0, 0.6) 40%,
48 + rgba(0, 0, 0, 0.4) 60%,
49 + rgba(0, 0, 0, 0.2) 80%,
50 + transparent 100%
51 + );
52 + opacity: 0;
53 + transition: opacity 0.3s ease;
54 + }
55 +</style>
src/components/ui/ImageViewer.astro new
+141
@@ -0,0 +1,141 @@
1 +<div id="image-viewer" class="image-viewer">
2 + <img id="image-viewer-img" src="" alt="" />
3 +</div>
4 +
5 +<script>
6 + function initImageViewer() {
7 + const viewer = document.getElementById('image-viewer')
8 + const viewerImg = document.getElementById('image-viewer-img') as HTMLImageElement
9 +
10 + if (!viewer || !viewerImg || viewerImg.tagName !== 'IMG') return
11 +
12 + // Display image in fullscreen viewer overlay
13 + function showImage(src: string, alt?: string) {
14 + if (viewerImg && src) {
15 + viewerImg.src = src
16 + viewerImg.alt = alt || ''
17 + }
18 + viewer?.classList.add('active')
19 + document.body.classList.add('image-viewer-open')
20 + document.body.style.overflow = 'hidden'
21 + document.body.dataset.scrollY = window.scrollY.toString()
22 + if (viewer) {
23 + viewer.style.cursor = 'auto'
24 + setTimeout(() => {
25 + viewer.style.cursor = ''
26 + }, 10)
27 + }
28 + }
29 +
30 + // Hide the image viewer and restore page scroll
31 + function hideImage() {
32 + viewer?.classList.remove('active')
33 + document.body.classList.remove('image-viewer-open')
34 + document.body.style.overflow = ''
35 + setTimeout(() => {
36 + if (viewer && !viewer.classList.contains('active') && viewerImg) {
37 + viewerImg.src = ''
38 + viewerImg.alt = ''
39 + viewer.style.cursor = 'auto'
40 + setTimeout(() => {
41 + viewer.style.cursor = ''
42 + }, 10)
43 + }
44 + }, 300)
45 + }
46 +
47 + // Bind click events to images with data-preview="true" attribute
48 + function bindImageClickEvents() {
49 + const previewImages = document.querySelectorAll('img[data-preview="true"]')
50 + previewImages.forEach((img) => {
51 + const imgElement = img as HTMLImageElement
52 + imgElement.style.cursor = 'zoom-in'
53 + imgElement.addEventListener('click', (e) => {
54 + e.preventDefault()
55 + const target = e.target as HTMLImageElement
56 + showImage(target.src, target.alt || '')
57 + })
58 + })
59 + }
60 +
61 + viewer?.addEventListener('click', hideImage)
62 +
63 + // Prevent touch scroll in image viewer
64 + viewer?.addEventListener(
65 + 'touchmove',
66 + (e) => {
67 + if (viewer.classList.contains('active')) {
68 + e.preventDefault()
69 + }
70 + },
71 + { passive: false }
72 + )
73 +
74 + document.addEventListener('keydown', (e) => {
75 + if (e.key === 'Escape' && viewer.classList.contains('active')) {
76 + hideImage()
77 + }
78 + })
79 +
80 + bindImageClickEvents()
81 +
82 + const observer = new MutationObserver(() => {
83 + bindImageClickEvents()
84 + })
85 +
86 + observer.observe(document.body, {
87 + childList: true,
88 + subtree: true
89 + })
90 + }
91 +
92 + if (document.readyState === 'loading') {
93 + document.addEventListener('DOMContentLoaded', initImageViewer)
94 + } else {
95 + initImageViewer()
96 + }
97 +
98 + document.addEventListener('astro:page-load', initImageViewer)
99 +</script>
100 +
101 +<style>
102 + .image-viewer {
103 + position: fixed;
104 + top: 0;
105 + left: 0;
106 + width: 100%;
107 + height: 100%;
108 + z-index: 9999;
109 + display: flex;
110 + align-items: center;
111 + justify-content: center;
112 + opacity: 0;
113 + visibility: hidden;
114 + transition: all 0.15s ease-in-out;
115 + background: color-mix(in srgb, var(--bg) 90%, transparent);
116 + cursor: zoom-out;
117 + }
118 +
119 + .image-viewer.active {
120 + opacity: 1;
121 + visibility: visible;
122 + }
123 +
124 + .image-viewer img {
125 + min-width: 45rem;
126 + max-width: 60vw;
127 + max-height: 80vh;
128 + object-fit: contain;
129 + cursor: zoom-out;
130 + }
131 +
132 + @media (max-width: 768px) {
133 + .image-viewer img {
134 + min-width: 100vw;
135 + }
136 + }
137 +
138 + body.image-viewer-open {
139 + overflow: hidden;
140 + }
141 +</style>
src/components/ui/PlayStoreButton.astro new
+60
@@ -0,0 +1,60 @@
1 +---
2 +import { SITE } from '@/config'
3 +---
4 +
5 +<a
6 + href="https://play.google.com/store/apps/dev?id=9116586035310009096"
7 + class="play-store-button"
8 + target="_blank"
9 + rel="noopener noreferrer"
10 +>
11 + <div class="play-store-icon">
12 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18">
13 + <path
14 + d="M3.609 1.814L13.792 12 3.61 22.186c-.37-.372-.585-.89-.585-1.435V3.25c0-.546.214-1.063.584-1.436zM14.746 12.96l4.497-2.58-3.182-1.83-3.483 2.077 2.168 2.334zM5.304 1.317l8.483 4.883-2.168 2.334L5.303 1.316zM19.243 9.889c.606.348.972.992.972 1.69 0 .55-.212 1.066-.583 1.439l-4.503 2.584-2.165-2.333 3.496-2.088 2.783-1.292z"
15 + fill="currentColor"></path>
16 + </svg>
17 + </div>
18 + <div class="play-store-text">
19 + <span class="download-text">Download</span>
20 + </div>
21 +</a>
22 +
23 +<style>
24 + .play-store-button {
25 + display: flex;
26 + align-items: center;
27 + background-color: var(--text-primary);
28 + color: var(--bg);
29 + text-decoration: none;
30 + padding: 0.4rem 0.75rem;
31 + border-radius: 6px;
32 + transition: opacity 0.2s ease;
33 + font-size: 0.875rem;
34 + }
35 +
36 + .play-store-button:hover {
37 + opacity: 0.9;
38 + }
39 +
40 + .play-store-button:active {
41 + opacity: 0.7;
42 + }
43 +
44 + .play-store-icon {
45 + margin-right: 0.5rem;
46 + display: flex;
47 + align-items: center;
48 + justify-content: center;
49 + }
50 +
51 + .play-store-text {
52 + display: flex;
53 + align-items: center;
54 + line-height: 1;
55 + }
56 +
57 + .download-text {
58 + font-weight: var(--font-weight-bold);
59 + }
60 +</style>
src/components/ui/TableOfContents.astro new
+334
@@ -0,0 +1,334 @@
1 +---
2 +import { SITE } from '@/config'
3 +import type { TOCProps } from '@/types'
4 +
5 +const { toc = [] }: TOCProps = Astro.props
6 +---
7 +
8 +<div class="toc-container" id="toc">
9 + <nav class="toc-nav">
10 + <ul class="toc-list" id="toc-list">
11 + <!-- Back to top link -->
12 + <li class="toc-item toc-level-0">
13 + <a href="#" class="toc-link toc-title" title="Back to top" data-text="Back to top">
14 + Back to top
15 + </a>
16 + </li>
17 +
18 + <!-- TOC items -->
19 + {
20 + toc.map((item) => (
21 + <li class={`toc-item toc-level-${item.level}`}>
22 + <a
23 + href={`#${item.id}`}
24 + class="toc-link"
25 + title={item.text}
26 + data-text={item.text}
27 + data-heading-id={item.id}
28 + >
29 + {item.text}
30 + </a>
31 + </li>
32 + ))
33 + }
34 + </ul>
35 + </nav>
36 +</div>
37 +
38 +<script
39 + is:inline
40 + define:vars={{
41 + contentWidth: SITE.contentWidth,
42 + centeredLayout: SITE.centeredLayout,
43 + toc: SITE.toc
44 + }}
45 +>
46 + ;(function () {
47 + let isInitialized = false
48 +
49 + // TOC positioning logic (similar to BackButton)
50 + function adjustTOCPosition() {
51 + const tocContainer = document.querySelector('.toc-container')
52 + if (!tocContainer) return
53 +
54 + // If not using centered layout, hide TOC
55 + if (!centeredLayout) {
56 + tocContainer.style.display = 'none'
57 + return
58 + }
59 +
60 + // Calculate available margin space for positioning
61 + const pageWidth = window.innerWidth
62 + const contentWidthValue = parseFloat(contentWidth)
63 + const margin = (pageWidth - contentWidthValue * 16) / 2
64 + const baseMinSpace = 11 * 16 // Base minimum space needed
65 + // If toc is enabled, need additional 2.5rem (40px) space
66 + const minSpace = toc ? baseMinSpace + 40 : baseMinSpace
67 +
68 + // Show and position TOC fixed on the left if there's enough space
69 + if (margin >= minSpace) {
70 + tocContainer.style.display = 'block'
71 + tocContainer.classList.add('fixed-position')
72 + const basePosition = margin - baseMinSpace
73 + // If toc is enabled, move 2.5rem (40px) further left
74 + const leftPosition = toc ? basePosition - 40 : basePosition
75 + tocContainer.style.left = `${leftPosition}px`
76 + } else {
77 + tocContainer.style.display = 'none'
78 + tocContainer.classList.remove('fixed-position')
79 + tocContainer.style.left = ''
80 + }
81 + }
82 +
83 + // Hide TOC if there are no headings (only title)
84 + function checkTOCVisibility() {
85 + const tocContainer = document.querySelector('.toc-container')
86 + const tocItems = document.querySelectorAll('.toc-item:not(.toc-level-0)')
87 +
88 + if (tocContainer && tocItems.length === 0) {
89 + tocContainer.style.display = 'none'
90 + }
91 + }
92 +
93 + // Add click handlers to TOC links using event delegation
94 + function addTOCEventListeners() {
95 + const tocContainer = document.querySelector('.toc-container')
96 + if (!tocContainer) return
97 +
98 + // Use event delegation for better performance and reliability
99 + tocContainer.addEventListener('click', function (e) {
100 + const link = e.target.closest('.toc-link')
101 + if (!link) return
102 +
103 + e.preventDefault()
104 +
105 + if (link.classList.contains('toc-title')) {
106 + // Back to top
107 + window.scrollTo({ top: 0, behavior: 'smooth' })
108 + history.pushState(null, null, '#')
109 + } else {
110 + // TOC item
111 + const href = link.getAttribute('href')
112 + if (href && href.startsWith('#')) {
113 + const targetId = href.substring(1)
114 + const target = document.getElementById(targetId)
115 + if (target) {
116 + const rect = target.getBoundingClientRect()
117 + const scrollTop = window.pageYOffset || document.documentElement.scrollTop
118 + const offset = rect.top + scrollTop - 96 // 6rem = 96px
119 + window.scrollTo({ top: offset, behavior: 'smooth' })
120 + history.pushState(null, null, href)
121 + }
122 + }
123 + }
124 + })
125 + }
126 +
127 + // Update active TOC item based on scroll position
128 + function updateActiveTOCItem() {
129 + const tocLinks = document.querySelectorAll('.toc-link')
130 + const headings = document.querySelectorAll('h1, h2, h3')
131 +
132 + let currentActive = null
133 + const scrollTop = window.pageYOffset + 100 // Offset for better detection
134 +
135 + // Check headings
136 + headings.forEach((heading, index) => {
137 + if (index === 0 && heading.tagName === 'H1') return
138 +
139 + const rect = heading.getBoundingClientRect()
140 + const offsetTop = rect.top + window.pageYOffset
141 +
142 + if (scrollTop >= offsetTop) {
143 + currentActive = heading.id
144 + }
145 + })
146 +
147 + tocLinks.forEach((link) => {
148 + link.classList.remove('active')
149 + if (link.getAttribute('href') === `#${currentActive}`) {
150 + link.classList.add('active')
151 + }
152 + })
153 +
154 + // Always highlight the first item ("Back to top") unless another TOC item is active
155 + if (!currentActive) {
156 + const titleLink = document.querySelector('.toc-link.toc-title')
157 + if (titleLink) {
158 + titleLink.classList.add('active')
159 + }
160 + }
161 + }
162 +
163 + function initTOC() {
164 + if (isInitialized) return
165 +
166 + adjustTOCPosition()
167 + checkTOCVisibility()
168 + addTOCEventListeners()
169 + updateActiveTOCItem() // Initial active state
170 +
171 + isInitialized = true
172 + }
173 +
174 + // Initialize on page load
175 + function handlePageLoad() {
176 + initTOC()
177 + }
178 +
179 + // Listen for various page load events
180 + document.addEventListener('astro:page-load', handlePageLoad)
181 + document.addEventListener('DOMContentLoaded', handlePageLoad)
182 +
183 + // Also initialize immediately if DOM is already loaded
184 + if (document.readyState === 'loading') {
185 + document.addEventListener('DOMContentLoaded', handlePageLoad)
186 + } else {
187 + handlePageLoad()
188 + }
189 +
190 + // Re-initialize on resize and scroll
191 + window.addEventListener('resize', adjustTOCPosition)
192 + window.addEventListener('scroll', updateActiveTOCItem)
193 + })()
194 +</script>
195 +
196 +<style is:global>
197 + .toc-container {
198 + width: 12rem;
199 + position: relative;
200 + left: -0.175em;
201 + }
202 +
203 + .toc-nav {
204 + font-family: var(--font-serif);
205 + font-size: var(--font-size-s);
206 + line-height: 1.5;
207 + }
208 +
209 + .toc-list {
210 + list-style: none;
211 + list-style-type: none;
212 + margin: 0 !important;
213 + padding: 0 !important;
214 + }
215 +
216 + .toc-list li {
217 + margin: 0 !important;
218 + padding: 0 !important;
219 + }
220 +
221 + .toc-item {
222 + list-style: none;
223 + list-style-type: none;
224 + }
225 +
226 + .toc-item::before {
227 + display: none;
228 + }
229 +
230 + .toc-item::marker {
231 + display: none;
232 + }
233 +
234 + .toc-link {
235 + display: block;
236 + color: transparent;
237 + text-decoration: none;
238 + position: relative;
239 + padding-left: 0;
240 + height: 1.125rem;
241 + width: 100%;
242 + min-height: 1rem;
243 + font-size: 0;
244 + line-height: 1.125rem;
245 + text-indent: 2rem;
246 + overflow: hidden;
247 + white-space: nowrap;
248 + text-overflow: ellipsis;
249 + transition:
250 + color 0.2s ease-out,
251 + font-size 0.2s ease-out,
252 + text-indent 0.2s ease-out;
253 + cursor: pointer;
254 + }
255 +
256 + .toc-link::after {
257 + content: attr(data-text);
258 + position: absolute;
259 + left: -0.5rem;
260 + top: 0;
261 + font-family: var(--font-sans);
262 + font-size: var(--font-size-s);
263 + letter-spacing: var(--spacing-m);
264 + line-height: 1.125rem;
265 + color: var(--text-primary);
266 + opacity: 0;
267 + transition:
268 + opacity 0.2s ease-out,
269 + left 0.2s ease-out;
270 + pointer-events: none;
271 + overflow: hidden;
272 + white-space: nowrap;
273 + text-overflow: ellipsis;
274 + max-width: 100%;
275 + }
276 +
277 + .toc-link:hover::after {
278 + opacity: 1;
279 + left: -0.75rem;
280 + }
281 +
282 + .toc-level-0 .toc-link:hover::after {
283 + opacity: 0;
284 + }
285 +
286 + .toc-level-1 .toc-link:hover::before,
287 + .toc-level-2 .toc-link:hover::before,
288 + .toc-level-3 .toc-link:hover::before {
289 + width: 0.75rem;
290 + transition: width 0.1s ease-out;
291 + }
292 +
293 + .toc-link.active {
294 + color: var(--text-primary);
295 + }
296 +
297 + /* Horizontal line indicators */
298 + .toc-level-0 .toc-link::before,
299 + .toc-level-1 .toc-link::before,
300 + .toc-level-2 .toc-link::before,
301 + .toc-level-3 .toc-link::before {
302 + content: '';
303 + position: absolute;
304 + left: 0;
305 + top: 50%;
306 + width: 2.5rem;
307 + height: 1px;
308 + background-color: var(--text-tertiary);
309 + transform: translateY(-50%);
310 + opacity: 0.4;
311 + transition: all 0.1s ease-out;
312 + }
313 +
314 + .toc-link:hover::before,
315 + .toc-link.active::before {
316 + opacity: 0.8;
317 + background-color: var(--text-primary);
318 + }
319 +
320 + .toc-container.fixed-position {
321 + position: fixed;
322 + top: 12rem; /* Position below BackButton */
323 + margin-top: 0;
324 + padding-left: 1rem;
325 + z-index: 10;
326 + }
327 +
328 + /* Hide on mobile and when space is limited */
329 + @media (max-width: 768px) {
330 + .toc-container {
331 + display: none !important;
332 + }
333 + }
334 +</style>
src/components/ui/ThemeToggle.astro new
+124
@@ -0,0 +1,124 @@
1 +---
2 +import { SITE } from '@/config'
3 +---
4 +
5 +{
6 + SITE.themeToggle && (
7 + <button id="theme-toggle" class="theme-toggle" aria-label="Toggle theme">
8 + <div class="theme-icon hollow-circle" />
9 + <div class="theme-icon solid-circle" />
10 + </button>
11 + )
12 +}
13 +
14 +<script is:inline>
15 + window.addEventListener('DOMContentLoaded', function () {
16 + const htmlElement = document.documentElement
17 +
18 + // Get system theme preference
19 + function getSystemTheme() {
20 + const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
21 + return isDark ? 'dark' : 'light'
22 + }
23 +
24 + // Get current actual theme state
25 + function getCurrentTheme() {
26 + const hasLight = htmlElement.classList.contains('light')
27 + const hasDark = htmlElement.classList.contains('dark')
28 +
29 + if (hasLight) {
30 + return 'light'
31 + }
32 + if (hasDark) {
33 + return 'dark'
34 + }
35 +
36 + const systemTheme = getSystemTheme()
37 + return systemTheme
38 + }
39 +
40 + // Apply theme
41 + function applyTheme(theme) {
42 + htmlElement.classList.remove('light', 'dark')
43 +
44 + if (theme === 'dark') {
45 + htmlElement.classList.add('dark')
46 + } else {
47 + htmlElement.classList.add('light')
48 + }
49 + }
50 +
51 + // Initialize theme - ensure explicit classes are always present
52 + function initTheme() {
53 + const systemTheme = getSystemTheme()
54 + applyTheme(systemTheme)
55 + }
56 +
57 + // Listen for system theme changes
58 + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
59 + mediaQuery.addEventListener('change', function (e) {
60 + const newTheme = e.matches ? 'dark' : 'light'
61 + applyTheme(newTheme)
62 + })
63 +
64 + // Get theme toggle button (only if it exists)
65 + const themeToggle = document.getElementById('theme-toggle')
66 + if (themeToggle) {
67 + // Toggle theme function
68 + function toggleTheme() {
69 + const currentTheme = getCurrentTheme()
70 + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
71 + applyTheme(newTheme)
72 + }
73 +
74 + themeToggle.addEventListener('click', function (e) {
75 + e.preventDefault()
76 + e.stopPropagation()
77 + toggleTheme()
78 + })
79 + }
80 +
81 + initTheme()
82 + })
83 +</script>
84 +
85 +<style>
86 + .theme-toggle {
87 + background: none;
88 + border: none;
89 + cursor: pointer;
90 + display: flex;
91 + align-items: center;
92 + height: 1.5rem;
93 + gap: 0.325rem;
94 + color: var(--text-primary);
95 + transition: opacity 0.2s ease;
96 + padding: 0;
97 + position: relative;
98 + }
99 +
100 + .theme-toggle:hover {
101 + opacity: 0.7;
102 + }
103 +
104 + .theme-toggle:active {
105 + opacity: 0.5;
106 + }
107 +
108 + .theme-icon {
109 + width: 0.5625rem;
110 + height: 0.5625rem;
111 + transition: all 0.2s ease;
112 + }
113 +
114 + .hollow-circle {
115 + border: none;
116 + border-radius: 50%;
117 + box-shadow: inset 0 0 0 1.5px var(--text-primary);
118 + }
119 +
120 + .solid-circle {
121 + background-color: var(--text-primary);
122 + border-radius: 50%;
123 + }
124 +</style>
src/components/ui/XPOST.astro new
+43
@@ -0,0 +1,43 @@
1 +<script>
2 + function loadXCards() {
3 + const xCards = document.querySelectorAll('.twitter-tweet')
4 + if (xCards.length === 0) return
5 +
6 + if (document.querySelector('script[src*="platform.twitter.com/widgets.js"]')) {
7 + return
8 + }
9 +
10 + const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
11 + xCards.forEach((element) => {
12 + element.setAttribute('data-theme', isDark ? 'dark' : 'light')
13 + })
14 +
15 + const script = document.createElement('script')
16 + script.src = 'https://platform.twitter.com/widgets.js'
17 + script.async = true
18 + document.head.appendChild(script)
19 + }
20 +
21 + document.addEventListener('DOMContentLoaded', loadXCards)
22 +
23 + document.addEventListener('astro:page-load', loadXCards)
24 +</script>
25 +
26 +<style>
27 + :global(.prose .x-card) {
28 + width: 100%;
29 + margin: 1em auto;
30 + text-align: center;
31 + }
32 +
33 + :global(.prose .x-card > *) {
34 + display: inline-block;
35 + max-width: 100%;
36 + margin: 0 auto;
37 + }
38 +
39 + :global(.prose .x-card iframe) {
40 + max-width: 100%;
41 + width: auto;
42 + }
43 +</style>
src/components/ui/_VariableBlurMask.astro new
+160
@@ -0,0 +1,160 @@
1 +<div class="variable-blur-mask">
2 + <div class="blur-bottom">
3 + <!-- Layer 1 -->
4 + <div
5 + class="blur-layer layer-1"
6 + style={{
7 + maskImage:
8 + 'linear-gradient(to top, rgba(0,0,0,0) 0%, rgba(255,255,255,1) 12.5%, rgba(255,255,255,1) 25%, rgba(0,0,0,0) 37.5%)',
9 + WebkitMaskImage:
10 + 'linear-gradient(to top, rgba(0,0,0,0) 0%, rgba(255,255,255,1) 12.5%, rgba(255,255,255,1) 25%, rgba(0,0,0,0) 37.5%)'
11 + }}
12 + >
13 + </div>
14 + <!-- Layer 2 -->
15 + <div
16 + class="blur-layer layer-2"
17 + style={{
18 + maskImage:
19 + 'linear-gradient(to top, rgba(0,0,0,0) 12.5%, rgba(255,255,255,1) 25%, rgba(255,255,255,1) 37.5%, rgba(0,0,0,0) 50%)',
20 + WebkitMaskImage:
21 + 'linear-gradient(to top, rgba(0,0,0,0) 12.5%, rgba(255,255,255,1) 25%, rgba(255,255,255,1) 37.5%, rgba(0,0,0,0) 50%)'
22 + }}
23 + >
24 + </div>
25 + <!-- Layer 3 -->
26 + <div
27 + class="blur-layer layer-3"
28 + style={{
29 + maskImage:
30 + 'linear-gradient(to top, rgba(0,0,0,0) 25%, rgba(255,255,255,1) 37.5%, rgba(255,255,255,1) 50%, rgba(0,0,0,0) 62.5%)',
31 + WebkitMaskImage:
32 + 'linear-gradient(to top, rgba(0,0,0,0) 25%, rgba(255,255,255,1) 37.5%, rgba(255,255,255,1) 50%, rgba(0,0,0,0) 62.5%)'
33 + }}
34 + >
35 + </div>
36 + <!-- Layer 4 -->
37 + <div
38 + class="blur-layer layer-4"
39 + style={{
40 + maskImage:
41 + 'linear-gradient(to top, rgba(0,0,0,0) 37.5%, rgba(255,255,255,1) 50%, rgba(255,255,255,1) 62.5%, rgba(0,0,0,0) 75%)',
42 + WebkitMaskImage:
43 + 'linear-gradient(to top, rgba(0,0,0,0) 37.5%, rgba(255,255,255,1) 50%, rgba(255,255,255,1) 62.5%, rgba(0,0,0,0) 75%)'
44 + }}
45 + >
46 + </div>
47 + <!-- Layer 5 -->
48 + <div
49 + class="blur-layer layer-5"
50 + style={{
51 + maskImage:
52 + 'linear-gradient(to top, rgba(0,0,0,0) 50%, rgba(255,255,255,1) 62.5%, rgba(255,255,255,1) 75%, rgba(0,0,0,0) 87.5%)',
53 + WebkitMaskImage:
54 + 'linear-gradient(to top, rgba(0,0,0,0) 50%, rgba(255,255,255,1) 62.5%, rgba(255,255,255,1) 75%, rgba(0,0,0,0) 87.5%)'
55 + }}
56 + >
57 + </div>
58 + <!-- Layer 6 -->
59 + <div
60 + class="blur-layer layer-6"
61 + style={{
62 + maskImage:
63 + 'linear-gradient(to top, rgba(0,0,0,0) 62.5%, rgba(255,255,255,1) 75%, rgba(255,255,255,1) 87.5%, rgba(0,0,0,0) 100%)',
64 + WebkitMaskImage:
65 + 'linear-gradient(to top, rgba(0,0,0,0) 62.5%, rgba(255,255,255,1) 75%, rgba(255,255,255,1) 87.5%, rgba(0,0,0,0) 100%)'
66 + }}
67 + >
68 + </div>
69 + <!-- Layer 7 -->
70 + <div
71 + class="blur-layer layer-7"
72 + style={{
73 + maskImage:
74 + 'linear-gradient(to top, rgba(0,0,0,0) 75%, rgba(255,255,255,1) 87.5%, rgba(255,255,255,1) 100%)',
75 + WebkitMaskImage:
76 + 'linear-gradient(to top, rgba(0,0,0,0) 75%, rgba(255,255,255,1) 87.5%, rgba(255,255,255,1) 100%)'
77 + }}
78 + >
79 + </div>
80 + <!-- Layer 8 -->
81 + <div
82 + class="blur-layer layer-8"
83 + style={{
84 + maskImage: 'linear-gradient(to top, rgba(0,0,0,0) 87.5%, rgba(255,255,255,1) 100%)',
85 + WebkitMaskImage: 'linear-gradient(to top, rgba(0,0,0,0) 87.5%, rgba(255,255,255,1) 100%)'
86 + }}
87 + >
88 + </div>
89 + </div>
90 + <slot />
91 +</div>
92 +
93 +<style>
94 + .variable-blur-mask {
95 + position: fixed;
96 + top: 0;
97 + left: 0;
98 + width: 100%;
99 + height: 4rem;
100 + z-index: 99;
101 + pointer-events: none;
102 + }
103 +
104 + .blur-bottom {
105 + position: absolute;
106 + top: 0;
107 + left: 0;
108 + width: 100%;
109 + height: 100%;
110 + pointer-events: none;
111 + }
112 +
113 + .blur-layer {
114 + position: absolute;
115 + top: 0;
116 + left: 0;
117 + width: 100%;
118 + height: 100%;
119 + }
120 +
121 + .layer-1 {
122 + z-index: 1;
123 + backdrop-filter: blur(0.5px);
124 + }
125 +
126 + .layer-2 {
127 + z-index: 2;
128 + backdrop-filter: blur(1px);
129 + }
130 +
131 + .layer-3 {
132 + z-index: 3;
133 + backdrop-filter: blur(2px);
134 + }
135 +
136 + .layer-4 {
137 + z-index: 4;
138 + backdrop-filter: blur(4px);
139 + }
140 +
141 + .layer-5 {
142 + z-index: 5;
143 + backdrop-filter: blur(8px);
144 + }
145 +
146 + .layer-6 {
147 + z-index: 6;
148 + backdrop-filter: blur(16px);
149 + }
150 +
151 + .layer-7 {
152 + z-index: 7;
153 + backdrop-filter: blur(32px);
154 + }
155 +
156 + .layer-8 {
157 + z-index: 8;
158 + backdrop-filter: blur(64px);
159 + }
160 +</style>
src/config.ts new
+27
@@ -0,0 +1,27 @@
1 +export const SITE = {
2 + // SITE INFO ///////////////////////////////////////////////////////////////////////////////////////////
3 + website: 'https://superteamstockholm.5mb.app/', // Site domain
4 + title: 'SuperTeam Stockholm', // Site title
5 + author: 'SuperTeam Stockholm', // Author name
6 + description: 'SuperTeam Stockholm chapter.', // Site description
7 + language: 'en-US', // Default language
8 +
9 + // GENERAL SETTINGS ////////////////////////////////////////////////////////////////////////////////////
10 + contentWidth: '35rem', // Content area width
11 + centeredLayout: true, // Use centered layout (false for left-aligned)
12 + favicon: false, // Show favicon on index page
13 + themeToggle: false, // Show theme toggle button (uses system theme by default)
14 + footer: true, // Show footer
15 + fadeAnimation: true, // Enable fade animations
16 +
17 + // DATE SETTINGS ///////////////////////////////////////////////////////////////////////////////////////
18 + dateFormat: 'YYYY-MM-DD', // Date format: YYYY-MM-DD, MM-DD-YYYY, DD-MM-YYYY, MONTH DAY YYYY, DAY MONTH YYYY
19 + dateSeparator: '.', // Date separator: . - / (except for MONTH DAY YYYY and DAY MONTH YYYY)
20 + dateOnRight: true, // Date position in post list (true for right, false for left)
21 +
22 + // POST SETTINGS ///////////////////////////////////////////////////////////////////////////////////////
23 + readingTime: false, // Show reading time in posts
24 + toc: true, // Show the table of contents when there is enough page width
25 + imageViewer: true, // Enable image viewer
26 + copyCode: true // Enable copy button in code blocks
27 +}
src/content.config.ts new
+24
@@ -0,0 +1,24 @@
1 +import { glob } from 'astro/loaders'
2 +import { defineCollection, z } from 'astro:content'
3 +
4 +const posts = defineCollection({
5 + // Load Markdown and MDX files in the `src/content/posts/` directory.
6 + loader: glob({ base: './src/content/posts', pattern: '**/*.{md,mdx}' }),
7 + // Type-check frontmatter using a schema
8 + schema: () =>
9 + z.object({
10 + title: z.string(),
11 + // Transform string to Date object
12 + pubDate: z.coerce.date(),
13 + image: z.string().optional()
14 + })
15 +})
16 +
17 +const about = defineCollection({
18 + // Load Markdown files in the `src/content/about/` directory.
19 + loader: glob({ base: './src/content/about', pattern: '**/*.md' }),
20 + // Type-check frontmatter using a schema
21 + schema: z.object({})
22 +})
23 +
24 +export const collections = { posts, about }
src/content/about/about.md new
+9
@@ -0,0 +1,9 @@
1 +---
2 +title: About
3 +---
4 +
5 +# SuperTeam Stockholm
6 +
7 +**SuperTeam Stockholm** is a community of Solana builders in Stockholm, Sweden. If you're into Rust, Solana, or crypto in general, you might want to join us.
8 +
9 +_"Let yourself be silently drawn by the strange pull of what you really love. It will not lead you astray." - Rumi_
src/content/config.ts new
+13
@@ -0,0 +1,13 @@
1 +import { defineCollection, z } from 'astro:content'
2 +
3 +const posts = defineCollection({
4 + type: 'content',
5 + schema: z.object({
6 + title: z.string(),
7 + pubDate: z.date()
8 + })
9 +})
10 +
11 +export const collections = {
12 + posts
13 +}
src/content/posts/_assets/copy-code.png
Binary files /dev/null and b/src/content/posts/_assets/copy-code.png differ
src/content/posts/_assets/date-on-left.png
Binary files /dev/null and b/src/content/posts/_assets/date-on-left.png differ
src/content/posts/_assets/hikari.jpg
Binary files /dev/null and b/src/content/posts/_assets/hikari.jpg differ
src/content/posts/_assets/reading-time.png
Binary files /dev/null and b/src/content/posts/_assets/reading-time.png differ
src/content/posts/_assets/theme-toggle.png
Binary files /dev/null and b/src/content/posts/_assets/theme-toggle.png differ
src/content/posts/_assets/toc.png
Binary files /dev/null and b/src/content/posts/_assets/toc.png differ
src/content/posts/_assets/tr-808.png
Binary files /dev/null and b/src/content/posts/_assets/tr-808.png differ
src/content/posts/getting-started.md new
+10
@@ -0,0 +1,10 @@
1 +---
2 +title: Getting Started
3 +pubDate: '2025-11-12'
4 +---
5 +
6 +# Getting Started
7 +
8 +We kicked off our Solana user group community today at Espresso House and then moved to Laughing Duck.
9 +
10 +*"What you seek is seeking you." - Rumi*
src/content/posts/privacy-policy.md new
+147
@@ -0,0 +1,147 @@
1 +---
2 +title: Privacy Policy
3 +pubDate: '2025-01-15'
4 +---
5 +
6 +# Privacy Policy for SuperTeam Stockholm
7 +
8 +*Last updated: January 15, 2025*
9 +
10 +## Introduction
11 +
12 +Welcome to SuperTeam Stockholm. We are committed to protecting your privacy and ensuring a safe learning experience. This Privacy Policy explains how we collect, use, and protect information when you use our mobile application ("App") and website.
13 +
14 +## Information We Collect
15 +
16 +### Account Information
17 +When you create an account, we may collect:
18 +- Email address
19 +- Username
20 +- Password (encrypted)
21 +- Profile information (optional)
22 +
23 +### Learning Data
24 +To provide personalized learning experiences, we collect:
25 +- Lesson progress and completion status
26 +- Quiz scores and exercise results
27 +- Learning streaks and achievements
28 +- Language proficiency levels
29 +- Study time and session duration
30 +
31 +### Device Information
32 +We may automatically collect:
33 +- Device type and model
34 +- Operating system version
35 +- App version
36 +- IP address
37 +- Language preferences
38 +- Time zone settings
39 +
40 +### Analytics Data
41 +We use analytics to improve the app experience:
42 +- App usage patterns
43 +- Feature interactions
44 +- Performance metrics
45 +- Crash reports and error logs
46 +
47 +## How We Use Your Information
48 +
49 +We use the collected information to:
50 +- Provide and maintain the SuperTeam Stockholm app
51 +- Personalize your learning experience
52 +- Track your progress and achievements
53 +- Send important updates and notifications
54 +- Improve app features and content
55 +- Analyze usage patterns to enhance user experience
56 +- Provide customer support
57 +- Ensure app security and prevent fraud
58 +
59 +## Data Storage and Security
60 +
61 +### Security Measures
62 +We implement industry-standard security measures to protect your data:
63 +- Encrypted data transmission (SSL/TLS)
64 +- Secure password storage (hashing and salting)
65 +- Regular security audits
66 +- Access controls and authentication
67 +
68 +### Data Retention
69 +- Account data is retained while your account is active
70 +- Learning progress data is stored to maintain continuity
71 +- You can request data deletion at any time
72 +
73 +## Third-Party Services
74 +
75 +Our app may use third-party services for:
76 +- **Authentication**: Secure login services
77 +- **Analytics**: App usage and performance monitoring
78 +- **Cloud Storage**: Data backup and synchronization
79 +- **Payment Processing**: In-app purchases (if applicable)
80 +
81 +These services have their own privacy policies and we recommend reviewing them.
82 +
83 +## Your Rights
84 +
85 +You have the right to:
86 +- **Access**: Request a copy of your personal data
87 +- **Correction**: Update or correct your information
88 +- **Deletion**: Request deletion of your account and data
89 +- **Export**: Download your learning data
90 +- **Opt-out**: Unsubscribe from marketing communications
91 +
92 +## Children's Privacy
93 +
94 +SuperTeam Stockholm is suitable for users of all ages. If you are under 13 years old (or under 16 in the EU), we require parental consent to use the app. We do not knowingly collect personal information from children without parental permission.
95 +
96 +## Cookies and Tracking
97 +
98 +Our website may use cookies to:
99 +- Remember your preferences
100 +- Analyze website traffic
101 +- Improve user experience
102 +
103 +You can control cookie settings in your browser.
104 +
105 +## Data Sharing
106 +
107 +We do not sell your personal information. We may share data only in these circumstances:
108 +- With your explicit consent
109 +- To comply with legal obligations
110 +- To protect our rights and safety
111 +- With service providers who help operate our app (under strict confidentiality)
112 +
113 +## International Data Transfers
114 +
115 +Your data may be processed in countries outside your residence. We ensure appropriate safeguards are in place to protect your information in accordance with applicable data protection laws.
116 +
117 +## Changes to This Privacy Policy
118 +
119 +We may update this Privacy Policy periodically. We will notify you of significant changes through:
120 +- In-app notifications
121 +- Email announcements
122 +- Website updates
123 +
124 +Continued use of the app after changes constitutes acceptance of the updated policy.
125 +
126 +## Contact Us
127 +
128 +If you have questions, concerns, or requests regarding this Privacy Policy or your data, please contact us:
129 +
130 +**Email**: splitfire@setoelkahfi.se
131 +
132 +**Website**: [https://superteamstockholm.5mb.app/](https://superteamstockholm.5mb.app/)
133 +
134 +## GDPR Compliance (EU Users)
135 +
136 +For users in the European Union, we comply with GDPR requirements. You have additional rights including:
137 +- Right to data portability
138 +- Right to object to processing
139 +- Right to lodge a complaint with supervisory authorities
140 +
141 +## CCPA Compliance (California Users)
142 +
143 +California residents have specific rights under the California Consumer Privacy Act (CCPA), including the right to know what personal information is collected and the right to opt-out of the sale of personal information.
144 +
145 +---
146 +
147 +*SuperTeam Stockholm is committed to protecting your privacy while helping you master the beautiful Persian language.*
src/content/posts/terms-of-use.md new
+233
@@ -0,0 +1,233 @@
1 +---
2 +title: Terms of Use
3 +pubDate: '2025-01-15'
4 +---
5 +
6 +# Terms of Use for SuperTeam Stockholm
7 +
8 +*Last updated: January 15, 2025*
9 +
10 +## 1. Acceptance of Terms
11 +
12 +By downloading, installing, accessing, or using the SuperTeam Stockholm mobile application ("App") and website ("Service"), you agree to be bound by these Terms of Use ("Terms"). If you do not agree to these Terms, please do not use our Service.
13 +
14 +## 2. Description of Service
15 +
16 +SuperTeam Stockholm is a language learning application designed to help users learn Persian (Farsi) through interactive lessons, vocabulary exercises, poetry, grammar guides, and cultural content.
17 +
18 +## 3. User Accounts
19 +
20 +### 3.1 Account Creation
21 +- You may need to create an account to access certain features
22 +- You must provide accurate and complete information
23 +- You are responsible for maintaining the confidentiality of your account credentials
24 +- You must be at least 13 years old to create an account (or 16 in the EU)
25 +- Users under the minimum age require parental consent
26 +
27 +### 3.2 Account Security
28 +- You are responsible for all activities under your account
29 +- Notify us immediately of any unauthorized use
30 +- We reserve the right to suspend or terminate accounts that violate these Terms
31 +
32 +## 4. User Conduct
33 +
34 +You agree NOT to:
35 +- Use the Service for any illegal or unauthorized purpose
36 +- Attempt to gain unauthorized access to our systems
37 +- Interfere with or disrupt the Service or servers
38 +- Share your account credentials with others
39 +- Use automated systems (bots) to access the Service
40 +- Copy, modify, or distribute our content without permission
41 +- Reverse engineer, decompile, or disassemble the App
42 +- Remove or modify any copyright notices or trademarks
43 +- Harass, abuse, or harm other users
44 +- Upload malicious code or viruses
45 +
46 +## 5. Intellectual Property Rights
47 +
48 +### 5.1 Our Content
49 +All content in the SuperTeam Stockholm App, including but not limited to:
50 +- Text, lessons, and educational materials
51 +- Audio recordings and pronunciations
52 +- Images, graphics, and illustrations
53 +- Software code and design
54 +- Trademarks and logos
55 +- Poetry translations and interpretations
56 +
57 +...is owned by Splitfire AB or our licensors and is protected by international copyright, trademark, and intellectual property laws.
58 +
59 +### 5.2 License Grant
60 +We grant you a limited, non-exclusive, non-transferable, revocable license to:
61 +- Use the App for personal, non-commercial language learning purposes
62 +- Access and view content within the App
63 +- Download content for offline use where explicitly permitted
64 +
65 +### 5.3 Restrictions
66 +You may NOT:
67 +- Reproduce, distribute, or create derivative works from our content
68 +- Use our content for commercial purposes without written permission
69 +- Extract or scrape content from the App for external use
70 +- Share premium content with non-subscribers
71 +
72 +## 6. User-Generated Content
73 +
74 +### 6.1 Your Content
75 +If you submit content (e.g., comments, feedback, translations):
76 +- You retain ownership of your content
77 +- You grant us a worldwide, non-exclusive, royalty-free license to use, display, and distribute your content within the Service
78 +- You represent that you have the right to share such content
79 +- You agree not to submit inappropriate, offensive, or unlawful content
80 +
81 +### 6.2 Content Moderation
82 +We reserve the right to:
83 +- Review, modify, or remove user-generated content
84 +- Suspend or ban users who violate content guidelines
85 +
86 +## 7. Subscriptions and Payments
87 +
88 +### 7.1 Premium Features
89 +- Certain features may require a paid subscription
90 +- Subscription terms and pricing are described at the time of purchase
91 +- Subscriptions automatically renew unless cancelled
92 +- Prices are subject to change with notice
93 +
94 +### 7.2 Refunds
95 +- Refund policies are governed by the App Store (iOS) or Google Play Store (Android) policies
96 +- Contact us for refund requests or billing issues
97 +
98 +### 7.3 Free Trial
99 +- Free trials may be offered for new subscribers
100 +- You must cancel before the trial period ends to avoid charges
101 +- One free trial per user
102 +
103 +## 8. Disclaimers and Warranties
104 +
105 +### 8.1 "As Is" Service
106 +The SuperTeam Stockholm Service is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, either express or implied, including but not limited to:
107 +- Merchantability
108 +- Fitness for a particular purpose
109 +- Non-infringement
110 +- Accuracy or completeness of content
111 +
112 +### 8.2 Learning Outcomes
113 +- We do not guarantee specific language proficiency results
114 +- Learning outcomes depend on individual effort and practice
115 +- Our content is for educational purposes only
116 +
117 +### 8.3 No Professional Advice
118 +The Service does not provide professional translation, interpretation, or linguistic certification services.
119 +
120 +## 9. Limitation of Liability
121 +
122 +To the maximum extent permitted by law, Splitfire AB shall not be liable for:
123 +- Indirect, incidental, special, consequential, or punitive damages
124 +- Loss of profits, data, or use
125 +- Service interruptions or technical issues
126 +- Inaccuracies in content or translations
127 +- Damages arising from your use or inability to use the Service
128 +
129 +Our total liability shall not exceed the amount you paid for the Service in the 12 months preceding the claim.
130 +
131 +## 10. Third-Party Services and Links
132 +
133 +### 10.1 Third-Party Content
134 +The App may contain links to third-party websites, services, or content. We are not responsible for:
135 +- The accuracy or availability of third-party content
136 +- Third-party privacy practices
137 +- Products or services offered by third parties
138 +
139 +### 10.2 App Stores
140 +Your use of the App is also subject to the terms of service of the Apple App Store or Google Play Store, as applicable.
141 +
142 +## 11. Changes to the Service
143 +
144 +We reserve the right to:
145 +- Modify, suspend, or discontinue any part of the Service
146 +- Update content and features
147 +- Change subscription pricing with notice
148 +- Terminate the Service with reasonable notice
149 +
150 +## 12. Termination
151 +
152 +### 12.1 By You
153 +You may delete your account and stop using the Service at any time.
154 +
155 +### 12.2 By Us
156 +We may suspend or terminate your access if you:
157 +- Violate these Terms
158 +- Engage in fraudulent or illegal activities
159 +- Abuse or misuse the Service
160 +- Fail to pay subscription fees
161 +
162 +### 12.3 Effect of Termination
163 +Upon termination:
164 +- Your license to use the Service ends
165 +- We may delete your account data (subject to legal requirements)
166 +- Certain provisions of these Terms survive termination
167 +
168 +## 13. Privacy
169 +
170 +Your use of the Service is also governed by our Privacy Policy. Please review it to understand how we collect, use, and protect your information.
171 +
172 +## 14. Governing Law and Disputes
173 +
174 +### 14.1 Governing Law
175 +These Terms are governed by the laws of Sweden, without regard to conflict of law principles.
176 +
177 +### 14.2 Dispute Resolution
178 +Any disputes arising from these Terms or your use of the Service shall be resolved through:
179 +1. Good faith negotiation
180 +2. Mediation (if negotiation fails)
181 +3. Arbitration or courts in Sweden (as applicable)
182 +
183 +### 14.3 Class Action Waiver
184 +You agree to resolve disputes individually and waive the right to participate in class actions or collective proceedings.
185 +
186 +## 15. Indemnification
187 +
188 +You agree to indemnify and hold harmless Splitfire AB, its affiliates, officers, directors, employees, and agents from any claims, damages, losses, liabilities, and expenses (including legal fees) arising from:
189 +- Your use of the Service
190 +- Your violation of these Terms
191 +- Your violation of any third-party rights
192 +- Your user-generated content
193 +
194 +## 16. Changes to Terms
195 +
196 +We may update these Terms from time to time. We will notify you of significant changes through:
197 +- In-app notifications
198 +- Email announcements
199 +- Website updates
200 +
201 +Your continued use of the Service after changes constitutes acceptance of the updated Terms.
202 +
203 +## 17. Severability
204 +
205 +If any provision of these Terms is found to be invalid or unenforceable, the remaining provisions will continue in full force and effect.
206 +
207 +## 18. Entire Agreement
208 +
209 +These Terms, together with our Privacy Policy, constitute the entire agreement between you and Splitfire AB regarding the SuperTeam Stockholm Service.
210 +
211 +## 19. No Waiver
212 +
213 +Our failure to enforce any provision of these Terms does not constitute a waiver of that provision or any other provision.
214 +
215 +## 20. Contact Information
216 +
217 +For questions, concerns, or notices regarding these Terms, please contact us:
218 +
219 +**Email**: splitfire@setoelkahfi.se
220 +
221 +**Website**: [https://superteamstockholm.5mb.app/](https://superteamstockholm.5mb.app/)
222 +
223 +**Company**: Splitfire AB, Sweden
224 +
225 +## 21. Acknowledgment
226 +
227 +By using SuperTeam Stockholm, you acknowledge that you have read, understood, and agree to be bound by these Terms of Use.
228 +
229 +---
230 +
231 +*Thank you for choosing SuperTeam Stockholm. We're excited to be part of your Persian language learning journey!*
232 +
233 +*"The wound is the place where the Light enters you." - Rumi*
src/content/posts/why-learn-persian.md new
+219
@@ -0,0 +1,219 @@
1 +---
2 +title: Why Learn Persian?
3 +pubDate: '2025-01-15'
4 +---
5 +
6 +# Why Learn Persian?
7 +
8 +Persian (Farsi) is one of the world's most beautiful and historically significant languages. Whether you're drawn to its poetry, culture, or practical benefits, learning Persian opens doors to a rich and fascinating world.
9 +
10 +## 🌍 A Global Language
11 +
12 +Persian is spoken by over **110 million people** worldwide:
13 +
14 +- **Iran**: ~85 million speakers (Farsi)
15 +- **Afghanistan**: ~15 million speakers (Dari)
16 +- **Tajikistan**: ~8 million speakers (Tajiki)
17 +- **Diaspora Communities**: Millions more in the USA, Canada, Europe, and the Middle East
18 +
19 +Persian is also understood in parts of Pakistan, Uzbekistan, and other Central Asian countries, making it a truly international language.
20 +
21 +## 📚 Gateway to Incredible Literature
22 +
23 +Persian literature spans over **1,000 years** and includes some of humanity's greatest poetic works:
24 +
25 +### The Great Persian Poets
26 +
27 +- **Rumi (Jalāl al-Dīn Rūmī)**: The best-selling poet in America, whose spiritual wisdom transcends cultures
28 +- **Hafez**: Master of love poetry and mysticism, whose tomb is a pilgrimage site
29 +- **Saadi**: Author of the Gulistan and Bustan, filled with timeless wisdom
30 +- **Ferdowsi**: Creator of the Shahnameh, Persia's epic masterpiece
31 +- **Omar Khayyam**: Mathematician, astronomer, and philosopher-poet
32 +
33 +Reading these masters in their original language reveals nuances lost in translation.
34 +
35 +## 🎨 Rich Cultural Heritage
36 +
37 +Persian culture has profoundly influenced:
38 +
39 +- **Architecture**: Stunning mosques, gardens, and palaces
40 +- **Art**: Miniature painting, calligraphy, and carpet weaving
41 +- **Music**: Classical Persian music with its unique modal system
42 +- **Cinema**: Award-winning Iranian cinema (Abbas Kiarostami, Asghar Farhadi)
43 +- **Cuisine**: Delicious dishes like kebabs, tahdig, and saffron rice
44 +
45 +## 💼 Career Opportunities
46 +
47 +Knowledge of Persian opens professional doors in:
48 +
49 +- **Diplomacy & International Relations**: Few Westerners speak Persian
50 +- **Business**: Trade opportunities with Iran, Afghanistan, and Central Asia
51 +- **Translation & Interpretation**: High demand, limited supply
52 +- **Journalism & Media**: Report from Persian-speaking regions
53 +- **Academia**: Research in Middle Eastern studies, history, or linguistics
54 +- **NGOs & Development**: Work in humanitarian organizations
55 +- **Intelligence & Security**: Government positions requiring Persian
56 +
57 +## 🧠 Cognitive Benefits
58 +
59 +Learning any language benefits your brain, but Persian offers unique advantages:
60 +
61 +- **New Writing System**: Master the beautiful Perso-Arabic script
62 +- **Different Grammar**: Exercise your mind with Persian's subject-object-verb structure
63 +- **Memory Enhancement**: Vocabulary building strengthens recall
64 +- **Cultural Perspective**: Gain new ways of thinking and expressing ideas
65 +
66 +## 🤝 Connect with People
67 +
68 +Learning Persian allows you to:
69 +
70 +- Communicate with millions of native speakers
71 +- Make friends in Persian-speaking communities
72 +- Travel more meaningfully through Iran, Afghanistan, and Central Asia
73 +- Understand your Persian heritage if you have Iranian ancestry
74 +- Bridge cultural divides and build international friendships
75 +
76 +## 🏛️ Historical Significance
77 +
78 +Persian has been a language of:
79 +
80 +- **Empire**: The official language of great empires (Achaemenid, Sassanid, Safavid)
81 +- **Science**: Medieval Persian scholars contributed to mathematics, astronomy, and medicine
82 +- **Philosophy**: Home to great thinkers like Avicenna (Ibn Sina) and Al-Ghazali
83 +- **Religion**: Important in Islamic scholarship and Sufi mysticism
84 +
85 +Many Arabic and Turkish words are borrowed from Persian, showing its historical influence.
86 +
87 +## 🗣️ It's Easier Than You Think
88 +
89 +Persian has several features that make it accessible:
90 +
91 +### What Makes Persian Learner-Friendly
92 +
93 +- **No Gender**: Unlike French or Arabic, Persian nouns have no grammatical gender
94 +- **Regular Verb Conjugation**: Predictable patterns with few irregular verbs
95 +- **No Articles**: No equivalent to "the" or "a/an"
96 +- **Familiar Vocabulary**: Many loanwords from Arabic, French, and English
97 +- **Phonetic Reading**: Once you learn the script, reading is straightforward
98 +- **Logical Structure**: Persian grammar follows consistent rules
99 +
100 +### Challenges (But Manageable!)
101 +
102 +- **New Alphabet**: The Perso-Arabic script takes practice but is beautiful
103 +- **Pronunciation**: Some sounds don't exist in English, but they're learnable
104 +- **Formality Levels**: Persian has formal and informal registers
105 +- **Ezafe Construction**: A unique grammatical feature for linking words
106 +
107 +## 🌟 Cultural Appreciation
108 +
109 +Persian culture values:
110 +
111 +- **Hospitality**: Iranians are known for their warmth and generosity
112 +- **Poetry**: Persians quote poetry in everyday conversation
113 +- **Family**: Strong family bonds and respect for elders
114 +- **History**: Pride in a 2,500-year-old civilization
115 +- **Arts**: Appreciation for beauty in all forms
116 +
117 +Understanding the language helps you appreciate these values deeply.
118 +
119 +## 🎯 Multiple Varieties, One Language
120 +
121 +Learning Persian gives you access to three main varieties:
122 +
123 +### Farsi (Iran)
124 +- Standard modern Persian
125 +- Most widely spoken variety
126 +- Rich media and literature
127 +
128 +### Dari (Afghanistan)
129 +- Very similar to Farsi
130 +- Different pronunciation of some words
131 +- Important for understanding Afghan culture
132 +
133 +### Tajiki (Tajikistan)
134 +- Written in Cyrillic script
135 +- Similar grammar and vocabulary
136 +- Gateway to Central Asian culture
137 +
138 +Once you learn one variety, the others become accessible with minimal effort.
139 +
140 +## 🎓 Academic Interest
141 +
142 +Persian is fascinating for students of:
143 +
144 +- **Linguistics**: Unique features and Indo-European heritage
145 +- **History**: Understand primary sources from Persian empires
146 +- **Religious Studies**: Access Islamic and Zoroastrian texts
147 +- **Literature**: Study poetry and storytelling traditions
148 +- **Middle Eastern Studies**: Essential for regional expertise
149 +
150 +## 🌐 Digital Age Advantages
151 +
152 +- **Online Communities**: Connect with Persian speakers worldwide
153 +- **Persian Media**: Access news, movies, and music in Persian
154 +- **Social Media**: Follow Iranian influencers and content creators
155 +- **Podcasts**: Learn from Persian-language audio content
156 +- **YouTube**: Watch Persian channels and tutorials
157 +
158 +## 💡 Personal Growth
159 +
160 +Learning Persian transforms you:
161 +
162 +- **New Perspectives**: See the world through a different cultural lens
163 +- **Patience**: Appreciate the journey of language learning
164 +- **Confidence**: Accomplish something challenging and rewarding
165 +- **Cultural Sensitivity**: Understand nuance and avoid stereotypes
166 +- **Lifelong Learning**: Develop a skill that enriches your entire life
167 +
168 +## 🎵 The Music of Persian
169 +
170 +Persian is renowned for its:
171 +
172 +- **Melodic Quality**: Beautiful, flowing sounds
173 +- **Poetic Expression**: Even everyday speech can sound poetic
174 +- **Rich Vocabulary**: Numerous words for subtle shades of meaning
175 +- **Metaphor**: Persian speakers love figurative language
176 +
177 +As Rumi said: *"The wound is the place where the Light enters you."* Persian expresses profound ideas with elegance.
178 +
179 +## 🚀 Getting Started
180 +
181 +Ready to begin your Persian learning journey? Here's how:
182 +
183 +1. **Download SuperTeam Stockholm**: Start with our beginner lessons
184 +2. **Learn the Alphabet**: Master the Perso-Arabic script first
185 +3. **Practice Daily**: Even 10 minutes a day makes a difference
186 +4. **Consume Persian Media**: Listen to music, watch movies
187 +5. **Find Language Partners**: Practice with native speakers
188 +6. **Be Patient**: Language learning is a marathon, not a sprint
189 +
190 +## 📱 Learn with Rumi
191 +
192 +The **SuperTeam Stockholm** app makes learning accessible:
193 +
194 +- Structured lessons from beginner to advanced
195 +- Poetry integrated throughout your learning
196 +- Cultural context for every lesson
197 +- Interactive exercises and quizzes
198 +- Progress tracking to stay motivated
199 +
200 +---
201 +
202 +## Conclusion
203 +
204 +Whether you're drawn to Persian poetry, seeking career opportunities, connecting with heritage, or simply love languages, **Persian offers something unique and valuable**.
205 +
206 +The journey of learning Persian is as beautiful as the destination. Every word you learn opens new doors of understanding, and every poem you read connects you to centuries of human wisdom.
207 +
208 +*"Let the beauty we love be what we do. There are hundreds of ways to kneel and kiss the ground." - Rumi*
209 +
210 +### Download SuperTeam Stockholm Today
211 +
212 +**iOS**: [Download on the App Store](https://apps.apple.com/se/app/rumi-l%C3%A4r-dig-persiska/id6753832408)
213 +**Android**: [Get it on Google Play](https://play.google.com/store/apps/details?id=xyz.smbcloud.rumi)
214 +
215 +Start your Persian learning adventure now!
216 +
217 +---
218 +
219 +*Have questions about learning Persian? [Contact us](/contact) - we're here to help!*
src/env.d.ts new
+12
@@ -0,0 +1,12 @@
1 +/// <reference types="astro/client" />
2 +/// <reference types="astro/content" />
3 +
4 +declare module 'astro:content' {
5 + interface Render {
6 + '.md': Promise<{
7 + Content: import('astro').MarkdownInstance<Record<string, unknown>>['Content']
8 + headings: import('astro').MarkdownHeading[]
9 + remarkPluginFrontmatter: Record<string, unknown>
10 + }>
11 + }
12 +}
src/layouts/BaseLayout.astro new
+74
@@ -0,0 +1,74 @@
1 +---
2 +import { SITE } from '@/config'
3 +import TransitionWrapper from '@/components/layout/TransitionWrapper.astro'
4 +import type { LayoutProps } from '@/types'
5 +
6 +type Props = LayoutProps
7 +
8 +const { type = 'page' } = Astro.props
9 +const contentWidth = SITE.contentWidth
10 +const widthValue = Math.min(parseFloat(contentWidth), 50)
11 +const shouldUseCustomWidth = widthValue > 25
12 +const finalWidth = shouldUseCustomWidth ? `${widthValue}rem` : '25rem'
13 +
14 +const language = SITE.language || 'en-US'
15 +---
16 +
17 +<html
18 + lang={language}
19 + class={SITE.fadeAnimation ? 'view-transitions-enabled' : 'view-transitions-disabled'}
20 + {...SITE.fadeAnimation ? { 'transition:animate': 'initial' } : {}}
21 +>
22 + <head>
23 + <slot name="head" />
24 + <script is:inline>
25 + // Initialize theme based on system preference
26 + function initTheme() {
27 + const htmlElement = document.documentElement
28 + const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
29 +
30 + // Remove any existing theme classes
31 + htmlElement.classList.remove('light', 'dark')
32 +
33 + // Apply the appropriate theme class
34 + htmlElement.classList.add(isDark ? 'dark' : 'light')
35 + }
36 +
37 + // Run on initial load
38 + initTheme()
39 +
40 + // Listen for system theme changes
41 + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
42 + const htmlElement = document.documentElement
43 + htmlElement.classList.remove('light', 'dark')
44 + htmlElement.classList.add(e.matches ? 'dark' : 'light')
45 + })
46 + </script>
47 + </head>
48 + <body
49 + data-centered={SITE.centeredLayout}
50 + class={!SITE.fadeAnimation ? 'no-fade' : ''}
51 + style={`
52 + max-width: ${finalWidth};
53 + ${shouldUseCustomWidth ? `--content-width: ${widthValue}rem;` : ''}
54 + `}
55 + >
56 + <TransitionWrapper type={type} class="layout-wrapper">
57 + <slot />
58 + </TransitionWrapper>
59 + </body>
60 +</html>
61 +
62 +<style is:global>
63 + .layout-wrapper {
64 + display: flex;
65 + flex-direction: column;
66 + min-height: calc(100vh - 7.5rem);
67 + }
68 +
69 + @media (max-width: 768px) {
70 + .layout-wrapper {
71 + min-height: calc(100vh - 5.5rem);
72 + }
73 + }
74 +</style>
src/layouts/IndexLayout.astro new
+43
@@ -0,0 +1,43 @@
1 +---
2 +import '@/styles/global.css'
3 +import BaseHead from '@/components/layout/BaseHead.astro'
4 +import Header from '@/components/layout/Header.astro'
5 +import Footer from '@/components/layout/Footer.astro'
6 +import BaseLayout from '@/layouts/BaseLayout.astro'
7 +import GradientMask from '@/components/ui/GradientMask.astro'
8 +import { SITE } from '@/config'
9 +
10 +const { title, description } = Astro.props
11 +---
12 +
13 +<BaseLayout title={title} description={description} type="page">
14 + <BaseHead title={title} description={description} slot="head" />
15 + <div class="page-content">
16 + <GradientMask />
17 + <div>
18 + <Header />
19 + </div>
20 + <main>
21 + <slot />
22 + </main>
23 + {
24 + SITE.footer && (
25 + <div>
26 + <Footer />
27 + </div>
28 + )
29 + }
30 + </div>
31 +</BaseLayout>
32 +
33 +<style is:global>
34 + .page-content {
35 + flex: 1;
36 + display: flex;
37 + flex-direction: column;
38 + }
39 +
40 + .page-content main {
41 + flex: 1;
42 + }
43 +</style>
src/layouts/PostLayout.astro new
+66
@@ -0,0 +1,66 @@
1 +---
2 +import '@/styles/global.css'
3 +import type { PostLayoutProps } from '@/types'
4 +import FormattedDate from '@/components/features/FormattedDate.astro'
5 +import FootnoteScroll from '@/components/features/FootnoteScroll.astro'
6 +import BaseHead from '@/components/layout/BaseHead.astro'
7 +import Footer from '@/components/layout/Footer.astro'
8 +import BackButton from '@/components/ui/BackButton.astro'
9 +import TableOfContents from '@/components/ui/TableOfContents.astro'
10 +import GradientMask from '@/components/ui/GradientMask.astro'
11 +import ImageViewer from '@/components/ui/ImageViewer.astro'
12 +import GitHubCard from '@/components/ui/GitHubCard.astro'
13 +import XPOST from '@/components/ui/XPOST.astro'
14 +import CopyCode from '@/components/ui/CopyCode.astro'
15 +import BaseLayout from '@/layouts/BaseLayout.astro'
16 +
17 +import { SITE } from '@/config'
18 +
19 +const { title, pubDate, readingTime, toc } = Astro.props as PostLayoutProps
20 +---
21 +
22 +<BaseLayout title={`${title} · ${SITE.title}`} description={SITE.description} type="post">
23 + <BaseHead title={`${title} · ${SITE.title}`} description={SITE.description} slot="head" />
24 + <div class="post-container">
25 + <main>
26 + <div class="prose">
27 + <GradientMask />
28 + <BackButton />
29 + {SITE.toc && <TableOfContents toc={toc} />}
30 + <div class="title">
31 + <h1>{title}</h1>
32 + <div class="date">
33 + <FormattedDate date={pubDate} />
34 + {
35 + SITE.readingTime && readingTime && (
36 + <span class="reading-time">
37 + <span class="separator">·</span>
38 + {readingTime.text}
39 + </span>
40 + )
41 + }
42 + </div>
43 + </div>
44 + <slot />
45 + </div>
46 + </main>
47 + <FootnoteScroll />
48 + <CopyCode />
49 + <GitHubCard />
50 + <XPOST />
51 + {SITE.imageViewer && <ImageViewer />}
52 + {SITE.footer && <Footer />}
53 + </div>
54 +</BaseLayout>
55 +
56 +<style>
57 + .post-container {
58 + display: flex;
59 + flex-direction: column;
60 + flex: 1;
61 + }
62 +
63 + .post-container main {
64 + flex: 1;
65 + }
66 +</style>
src/pages/404.astro new
+13
@@ -0,0 +1,13 @@
1 +---
2 +import IndexLayout from '@/layouts/IndexLayout.astro'
3 +import { SITE } from '@/config'
4 +---
5 +
6 +<IndexLayout title={`404 - ${SITE.title}`} description="Not Found">
7 + <style>
8 + .error-container {
9 + color: var(--text-secondary);
10 + }
11 + </style>
12 + <p class="error-container">Page Not Found...</p>
13 +</IndexLayout>
src/pages/[...slug].astro new
+26
@@ -0,0 +1,26 @@
1 +---
2 +import { type CollectionEntry, getCollection } from 'astro:content'
3 +import PostLayout from '@/layouts/PostLayout.astro'
4 +import { render } from 'astro:content'
5 +
6 +export async function getStaticPaths() {
7 + const posts = await getCollection('posts')
8 + return posts
9 + .filter((post) => !post.id.startsWith('_'))
10 + .map((post) => ({
11 + params: { slug: post.id },
12 + props: post
13 + }))
14 +}
15 +type Props = CollectionEntry<'posts'>
16 +
17 +const post = Astro.props
18 +const { Content, remarkPluginFrontmatter } = await render(post)
19 +
20 +const readingTime = remarkPluginFrontmatter.readingTime
21 +const toc = remarkPluginFrontmatter.toc || []
22 +---
23 +
24 +<PostLayout {...post.data} readingTime={readingTime} toc={toc}>
25 + <Content />
26 +</PostLayout>
src/pages/atom.xml.ts new
+6
@@ -0,0 +1,6 @@
1 +import type { APIContext } from 'astro'
2 +import { generateAtom } from '@/utils/feed'
3 +
4 +export async function GET(context: APIContext) {
5 + return generateAtom(context)
6 +}
src/pages/contact.astro new
+79
@@ -0,0 +1,79 @@
1 +---
2 +import IndexLayout from '@/layouts/IndexLayout.astro'
3 +import { SITE } from '@/config'
4 +---
5 +
6 +<IndexLayout
7 + title={`Contact - ${SITE.title}`}
8 + description="Get in touch with the SuperTeam Stockholm team"
9 +>
10 + <div class="contact-page prose">
11 + <h1>Contact Us</h1>
12 +
13 + <p>Have questions about the SuperTeam Stockholm?</p>
14 +
15 + <div class="contact-info">
16 + <h2>Get in Touch</h2>
17 + <p>Feel free to reach out to us via our telegram channel:</p>
18 + <div class="email-section">
19 + <a href="/#join-us" class="email-link"> Join Us</a>
20 + </div>
21 + </div>
22 + </div>
23 +</IndexLayout>
24 +
25 +<style>
26 + .contact-page {
27 + max-width: 100%;
28 + margin: 0 auto;
29 + padding: 2rem 0;
30 + }
31 +
32 + .contact-info {
33 + margin: 2rem 0;
34 + }
35 +
36 + .email-section {
37 + margin: 1.5rem 0;
38 + padding: 1rem;
39 + background: var(--code-bg);
40 + border-radius: 8px;
41 + border-left: 4px solid var(--accent);
42 + }
43 +
44 + .email-link {
45 + font-size: 1.25rem;
46 + font-weight: 600;
47 + color: var(--accent);
48 + text-decoration: none;
49 + word-break: break-all;
50 + }
51 +
52 + .email-link:hover {
53 + text-decoration: underline;
54 + }
55 +
56 + .topics {
57 + margin: 2rem 0;
58 + }
59 +
60 + .topics ul {
61 + list-style-type: disc;
62 + margin-left: 1.5rem;
63 + }
64 +
65 + .topics li {
66 + margin: 0.5rem 0;
67 + line-height: 1.6;
68 + }
69 +
70 + @media (max-width: 768px) {
71 + .contact-page {
72 + padding: 1rem 0;
73 + }
74 +
75 + .email-link {
76 + font-size: 1.1rem;
77 + }
78 + }
79 +</style>
src/pages/index.astro new
+16
@@ -0,0 +1,16 @@
1 +---
2 +import IndexLayout from '@/layouts/IndexLayout.astro'
3 +import About from '@/components/pages/About.astro'
4 +import PostList from '@/components/features/PostList.astro'
5 +import { SITE } from '@/config'
6 +import { getSortedFilteredPosts } from '@/utils/draft'
7 +
8 +const posts = await getSortedFilteredPosts()
9 +---
10 +
11 +<IndexLayout title={SITE.title} description={SITE.description}>
12 + <About />
13 + <main>
14 + <PostList posts={posts} />
15 + </main>
16 +</IndexLayout>
src/pages/rss.xml.ts new
+6
@@ -0,0 +1,6 @@
1 +import type { APIContext } from 'astro'
2 +import { generateRSS } from '@/utils/feed'
3 +
4 +export async function GET(context: APIContext) {
5 + return generateRSS(context)
6 +}
src/plugins/rehype-cleanup.mjs new
+35
@@ -0,0 +1,35 @@
1 +import { visit } from 'unist-util-visit'
2 +
3 +/**
4 + * Rehype plugin to cleanup and extract raw figure elements from paragraph nodes
5 + */
6 +export default function rehypeCleanup() {
7 + return (tree) => {
8 + visit(tree, 'element', (node, index, parent) => {
9 + if (node.tagName !== 'p') {
10 + return
11 + }
12 + if (!node.children?.length) {
13 + return
14 + }
15 + if (!parent) {
16 + return
17 + }
18 +
19 + const rawFigureNodes = []
20 +
21 + for (const child of node.children) {
22 + if (child.type === 'raw' && child.value && child.value.trim().startsWith('<figure')) {
23 + rawFigureNodes.push(child)
24 + } else if (child.type !== 'text' || child.value.trim() !== '') {
25 + return
26 + }
27 + }
28 +
29 + if (rawFigureNodes.length > 0) {
30 + parent.children.splice(index, 1, ...rawFigureNodes)
31 + return index
32 + }
33 + })
34 + }
35 +}
src/plugins/rehype-copy-code.mjs new
+38
@@ -0,0 +1,38 @@
1 +import { visit } from 'unist-util-visit'
2 +
3 +/**
4 + * Rehype plugin that adds copy button to code blocks for easy code copying functionality
5 + */
6 +export default function rehypeCopyCode() {
7 + return (tree) => {
8 + visit(tree, 'element', (node) => {
9 + if (node.tagName === 'pre') {
10 + if (!node.children || node.children.length === 0) {
11 + return
12 + }
13 +
14 + const codeElement = node.children.find((child) => child.tagName === 'code')
15 + if (!codeElement) {
16 + return
17 + }
18 +
19 + node.properties = node.properties || {}
20 + node.properties.className = node.properties.className || []
21 + node.properties.className.push('copy-code-block')
22 +
23 + const copyButton = {
24 + type: 'element',
25 + tagName: 'button',
26 + properties: {
27 + className: ['copy-button'],
28 + type: 'button',
29 + 'aria-label': 'Copy code'
30 + },
31 + children: []
32 + }
33 +
34 + node.children.unshift(copyButton)
35 + }
36 + })
37 + }
38 +}
src/plugins/rehype-image-processor.mjs new
+83
@@ -0,0 +1,83 @@
1 +import { visit } from 'unist-util-visit'
2 +import { SITE } from '../config.ts'
3 +
4 +/**
5 + * Rehype plugin that processes images in markdown content:
6 + * - Wraps images with alt text in figure/figcaption elements
7 + * - Adds data-preview attribute for image viewer functionality
8 + * - Handles multiple images in a single paragraph
9 + */
10 +export default function rehypeImageProcessor() {
11 + return (tree) => {
12 + visit(tree, 'element', (node, index, parent) => {
13 + if (node.tagName !== 'p') {
14 + return
15 + }
16 + if (!parent || typeof index !== 'number') {
17 + return
18 + }
19 +
20 + const imgNodes = []
21 + let hasNonImageContent = false
22 +
23 + for (const child of node.children) {
24 + if (child.type === 'element' && child.tagName === 'img') {
25 + imgNodes.push(child)
26 + } else if (child.type !== 'text' || child.value.trim() !== '') {
27 + hasNonImageContent = true
28 + }
29 + }
30 +
31 + if (hasNonImageContent || imgNodes.length === 0) {
32 + return
33 + }
34 +
35 + const newNodes = []
36 +
37 + for (const imgNode of imgNodes) {
38 + const alt = imgNode.properties?.alt?.trim()
39 +
40 + imgNode.properties = {
41 + ...imgNode.properties,
42 + 'data-preview': SITE.imageViewer ? 'true' : 'false'
43 + }
44 +
45 + if (!alt || alt.includes('_')) {
46 + newNodes.push(imgNode)
47 + continue
48 + }
49 +
50 + const figure = {
51 + type: 'element',
52 + tagName: 'figure',
53 + properties: {
54 + className: ['image-caption-wrapper']
55 + },
56 + children: [
57 + imgNode,
58 + {
59 + type: 'element',
60 + tagName: 'figcaption',
61 + properties: {
62 + className: ['img-caption']
63 + },
64 + children: [
65 + {
66 + type: 'text',
67 + value: alt
68 + }
69 + ]
70 + }
71 + ]
72 + }
73 +
74 + newNodes.push(figure)
75 + }
76 +
77 + if (newNodes.length > 0) {
78 + parent.children.splice(index, 1, ...newNodes)
79 + return index + newNodes.length - 1
80 + }
81 + })
82 + }
83 +}
src/plugins/remark-embedded-media.mjs new
+187
@@ -0,0 +1,187 @@
1 +import { visit } from 'unist-util-visit'
2 +
3 +/**
4 + * A remark plugin that converts custom directives to embedded media HTML elements
5 + */
6 +const embedHandlers = {
7 + // Spotify
8 + spotify: (node) => {
9 + const url = node.attributes?.url ?? ''
10 + if (!url) {
11 + return false
12 + }
13 + if (!/^https:\/\/open\.spotify\.com\//.test(url)) {
14 + return false
15 + }
16 + let embedUrl = url.replace('open.spotify.com/', 'open.spotify.com/embed/')
17 + if (!embedUrl.includes('utm_source=')) {
18 + embedUrl += (embedUrl.includes('?') ? '&' : '?') + 'utm_source=generator'
19 + }
20 +
21 + let height = '152'
22 + if (
23 + url.includes('/album/') ||
24 + url.includes('/playlist/') ||
25 + url.includes('/artist/') ||
26 + url.includes('/show/')
27 + ) {
28 + height = '352'
29 + }
30 +
31 + return `
32 + <figure>
33 + <iframe
34 + style="border-radius:12px"
35 + src="${embedUrl}"
36 + width="100%"
37 + height="${height}"
38 + frameBorder="0"
39 + allowfullscreen=""
40 + allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
41 + loading="lazy"
42 + ></iframe>
43 + </figure>
44 + `
45 + },
46 +
47 + // Youtube
48 + youtube: (node) => {
49 + let videoId = node.attributes?.id ?? ''
50 + const url = node.attributes?.url ?? ''
51 +
52 + if (!videoId && url) {
53 + const match = url.match(/(?:v=|\/embed\/|youtu\.be\/)([\w-]{11})/)
54 + if (match) videoId = match[1]
55 + }
56 +
57 + if (!videoId) {
58 + return false
59 + }
60 +
61 + return `
62 + <figure>
63 + <iframe
64 + src="https://www.youtube.com/embed/${videoId}"
65 + title="YouTube video player"
66 + loading="lazy"
67 + frameborder="0"
68 + allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
69 + allowfullscreen
70 + ></iframe>
71 + </figure>
72 + `
73 + },
74 +
75 + // Bilibili
76 + bilibili: (node) => {
77 + let bvid = node.attributes?.id ?? ''
78 + const url = node.attributes?.url ?? ''
79 + if (!bvid && url) {
80 + const match = url.match(/\/BV([\w]+)/)
81 + if (match) bvid = 'BV' + match[1]
82 + }
83 + if (!bvid) {
84 + return false
85 + }
86 +
87 + return `
88 + <figure>
89 + <iframe
90 + src="//player.bilibili.com/player.html?isOutside=true&bvid=${bvid}&p=1&autoplay=0&muted=0"
91 + title="Bilibili video player"
92 + loading="lazy"
93 + scrolling="no"
94 + border="0"
95 + frameborder="no"
96 + framespacing="0"
97 + allowfullscreen="true"
98 + ></iframe>
99 + </figure>
100 + `
101 + },
102 +
103 + // X Post Card
104 + x: (node) => {
105 + const xUrl = node.attributes?.url ?? ''
106 + if (!xUrl) {
107 + return false
108 + }
109 +
110 + const twitterUrl = xUrl.replace(/(\w+:\/\/)?x\.com\//g, '$1twitter.com/')
111 + const uniqueId = `x-card-${Math.random().toString(36).slice(2, 11)}`
112 +
113 + return `
114 + <figure class="x-card">
115 + <blockquote class="twitter-tweet" data-dnt="true" id="${uniqueId}">
116 + <a href="${twitterUrl}"></a>
117 + </blockquote>
118 + </figure>
119 + `
120 + },
121 +
122 + // Github Repository Card
123 + github: (node) => {
124 + const repo = node.attributes?.repo ?? ''
125 + if (!repo) {
126 + console.warn(`Missing GitHub repository`)
127 + return false
128 + }
129 +
130 + const [owner, name] = repo.split('/')
131 + if (!owner || !name) {
132 + console.warn(`Invalid GitHub repository format: "${repo}"`)
133 + return false
134 + }
135 +
136 + return `
137 + <a href="https://github.com/${repo}" class="gc-container" target="_blank" rel="noopener noreferrer" data-repo="${repo}">
138 + <div class="gc-title-bar">
139 + <div class="gc-owner-avatar" style="background-size: cover; background-position: center;" aria-hidden="true"></div>
140 + <span class="gc-repo-title">
141 + <span>${owner}<span class="gc-slash" aria-hidden="true">/</span><strong>${name}</strong></span>
142 + </span>
143 + <svg class="gc-github-icon" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
144 + <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path>
145 + </svg>
146 + </div>
147 + <p class="gc-repo-description">Loading repository data...</p>
148 + <div class="gc-info-bar">
149 + <svg class="gc-info-icon" height="16" width="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
150 + <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path>
151 + </svg>
152 + <span class="gc-stars-count" aria-label="Stars count">--</span>
153 + <svg class="gc-info-icon" height="16" width="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
154 + <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path>
155 + </svg>
156 + <span class="gc-forks-count" aria-label="Forks count">--</span>
157 + <svg class="gc-info-icon" height="16" width="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
158 + <path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path>
159 + </svg>
160 + <span class="gc-license-info" aria-label="License">--</span>
161 + </div>
162 + </a>
163 + `
164 + }
165 +}
166 +
167 +export default function remarkEmbeddedMedia() {
168 + return (tree) => {
169 + visit(tree, ['leafDirective', 'containerDirective', 'textDirective'], (node) => {
170 + const handler = embedHandlers[node.name]
171 + if (!handler) {
172 + return
173 + }
174 +
175 + const htmlContent = handler(node)
176 + if (!htmlContent) {
177 + return
178 + }
179 +
180 + node.type = 'html'
181 + node.value = htmlContent
182 + delete node.name
183 + delete node.attributes
184 + delete node.children
185 + })
186 + }
187 +}
src/plugins/remark-reading-time.mjs new
+21
@@ -0,0 +1,21 @@
1 +import { toString } from 'mdast-util-to-string'
2 +import getReadingTime from 'reading-time'
3 +
4 +/**
5 + * Remark plugin to calculate and add reading time information to markdown frontmatter
6 + */
7 +export default function remarkReadingTime() {
8 + return function (tree, file) {
9 + const textOnPage = toString(tree)
10 + const readingTime = getReadingTime(textOnPage)
11 +
12 + const minutes = Math.max(1, Math.round(readingTime.minutes))
13 + file.data.astro.frontmatter.minutesRead = `${minutes}min`
14 + file.data.astro.frontmatter.readingTime = {
15 + text: `${minutes}min`,
16 + minutes: minutes,
17 + time: readingTime.time,
18 + words: readingTime.words
19 + }
20 + }
21 +}
src/plugins/remark-toc.mjs new
+89
@@ -0,0 +1,89 @@
1 +import { visit } from 'unist-util-visit'
2 +
3 +export default function remarkTOC() {
4 + return function (tree, file) {
5 + const headings = []
6 + let headingIndex = 0
7 + const usedSlugs = new Set()
8 +
9 + // Extract headings from AST
10 + visit(tree, 'heading', (node) => {
11 + const level = node.depth
12 +
13 + // Only process h1, h2, h3
14 + if (level > 3) return
15 +
16 + // Skip the first h1
17 + if (level === 1 && headingIndex === 0) {
18 + headingIndex++
19 + return
20 + }
21 +
22 + const text = extractTextContent(node)
23 + if (!text) return
24 +
25 + // Generate unique slug from text
26 + const slug = generateUniqueSlug(text, usedSlugs)
27 + const id = slug
28 +
29 + if (!node.data) node.data = {}
30 + if (!node.data.hProperties) node.data.hProperties = {}
31 + node.data.hProperties.id = id
32 +
33 + headings.push({
34 + level,
35 + text,
36 + id,
37 + index: headingIndex
38 + })
39 +
40 + headingIndex++
41 + })
42 +
43 + // Store TOC data in file.data.astro.frontmatter
44 + if (!file.data.astro) file.data.astro = {}
45 + if (!file.data.astro.frontmatter) file.data.astro.frontmatter = {}
46 + file.data.astro.frontmatter.toc = headings
47 + }
48 +}
49 +
50 +function extractTextContent(node) {
51 + let text = ''
52 +
53 + visit(node, 'text', (textNode) => {
54 + text += textNode.value
55 + })
56 +
57 + return text.trim()
58 +}
59 +
60 +// Generate a slug from text
61 +function generateSlug(text) {
62 + return (
63 + text
64 + .toLowerCase()
65 + // Keep Chinese characters, English letters, numbers, spaces and hyphens
66 + .replace(/[^\u4e00-\u9fa5a-z0-9\s-]/g, '')
67 + // Replace spaces with hyphens
68 + .replace(/\s+/g, '-')
69 + // Replace multiple hyphens with single hyphen
70 + .replace(/-+/g, '-')
71 + // Remove leading and trailing hyphens
72 + .replace(/^-|-$/g, '')
73 + )
74 +}
75 +
76 +// Generate a unique slug from text
77 +function generateUniqueSlug(text, usedSlugs) {
78 + let slug = generateSlug(text)
79 + let counter = 1
80 + let uniqueSlug = slug
81 +
82 + while (usedSlugs.has(uniqueSlug)) {
83 + uniqueSlug = `${slug}-${counter}`
84 + counter++
85 + }
86 +
87 + usedSlugs.add(uniqueSlug)
88 + return uniqueSlug
89 +}
src/styles/fonts.css new
+21
@@ -0,0 +1,21 @@
1 +@font-face {
2 + font-family: 'Inter';
3 + font-style: normal;
4 + font-weight: 100 900;
5 + font-display: swap;
6 + src: url('/fonts/Inter.woff2') format('woff2');
7 + unicode-range:
8 + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074,
9 + U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
10 +}
11 +
12 +@font-face {
13 + font-family: 'Besley';
14 + font-style: italic;
15 + font-weight: 400;
16 + font-display: swap;
17 + src: url('/fonts/Besley-Italic.woff2') format('woff2');
18 + unicode-range:
19 + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074,
20 + U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
21 +}
src/styles/global.css new
+220
@@ -0,0 +1,220 @@
1 +@import 'tailwindcss';
2 +@import './fonts.css';
3 +@import './post.css';
4 +
5 +:root {
6 + /* Min Content Width */
7 + --content-width: 25rem;
8 +
9 + /* Typography */
10 + --font-sans:
11 + Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell,
12 + Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
13 + --font-serif: Besley, Baskerville, Georgia, Cambria, 'Times New Roman', Times, serif;
14 + --font-mono: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
15 +
16 + --font-size-s: 0.8125rem;
17 + --font-size-m: 0.9375rem;
18 + --font-size-l: 1.0625rem;
19 +
20 + --font-weight-light: 350;
21 + --font-weight-regular: 400;
22 + --font-weight-bold: 500;
23 +
24 + --spacing-s: -0.08em;
25 + --spacing-m: -0.02em;
26 +
27 + /* Light Mode Colors (Default) */
28 + --bg: #ffffff;
29 + --text-primary: rgba(0, 0, 0, 0.85);
30 + --text-secondary: rgba(0, 0, 0, 0.4);
31 + --text-tertiary: rgba(0, 0, 0, 0.24);
32 + --border: rgba(0, 0, 0, 0.1);
33 + --accent: #c026d3;
34 + --selection: rgba(197, 217, 50, 0.2);
35 + --code-bg: rgba(0, 0, 0, 0.06);
36 + --mark: rgba(197, 217, 50, 0.3);
37 +
38 + /* Syntax Theme */
39 + --astro-code-foreground: rgba(0, 0, 0, 0.85);
40 + --astro-code-background: rgba(0, 0, 0, 0.03);
41 + --astro-code-token-constant: rgba(0, 0, 0, 0.85);
42 + --astro-code-token-string: rgba(0, 0, 0, 0.85);
43 + --astro-code-token-comment: rgba(0, 0, 0, 0.35);
44 + --astro-code-token-keyword: rgba(0, 0, 0, 0.55);
45 + --astro-code-token-parameter: rgba(0, 0, 0, 0.85);
46 + --astro-code-token-function: rgba(0, 0, 0, 0.85);
47 + --astro-code-token-string-expression: rgba(0, 0, 0, 0.55);
48 + --astro-code-token-punctuation: rgba(0, 0, 0, 0.55);
49 + --astro-code-token-link: rgba(0, 0, 0, 0.55);
50 +}
51 +
52 +/* Light Mode (Explicit) */
53 +html.light {
54 + --bg: #ffffff;
55 + --text-primary: rgba(0, 0, 0, 0.85);
56 + --text-secondary: rgba(0, 0, 0, 0.4);
57 + --text-tertiary: rgba(0, 0, 0, 0.24);
58 + --border: rgba(0, 0, 0, 0.1);
59 + --accent: #c026d3;
60 + --selection: rgba(197, 217, 50, 0.2);
61 + --code-bg: rgba(0, 0, 0, 0.06);
62 + --mark: rgba(197, 217, 50, 0.3);
63 +
64 + /* Syntax Theme */
65 + --astro-code-foreground: rgba(0, 0, 0, 0.85);
66 + --astro-code-background: rgba(0, 0, 0, 0.03);
67 + --astro-code-token-constant: rgba(0, 0, 0, 0.85);
68 + --astro-code-token-string: rgba(0, 0, 0, 0.85);
69 + --astro-code-token-comment: rgba(0, 0, 0, 0.35);
70 + --astro-code-token-keyword: rgba(0, 0, 0, 0.5);
71 + --astro-code-token-parameter: rgba(0, 0, 0, 0.85);
72 + --astro-code-token-function: rgba(0, 0, 0, 0.85);
73 + --astro-code-token-string-expression: rgba(0, 0, 0, 0.55);
74 + --astro-code-token-punctuation: rgba(0, 0, 0, 0.55);
75 + --astro-code-token-link: rgba(0, 0, 0, 0.55);
76 +}
77 +
78 +/* Dark Mode (Explicit) */
79 +html.dark {
80 + --bg: #060d0c;
81 + --text-primary: rgba(255, 255, 255, 0.9);
82 + --text-secondary: rgba(255, 255, 255, 0.4);
83 + --text-tertiary: rgba(255, 255, 255, 0.24);
84 + --border: rgba(255, 255, 255, 0.1);
85 + --accent: #c026d3;
86 + --selection: rgba(197, 217, 50, 0.15);
87 + --code-bg: rgba(255, 255, 255, 0.06);
88 + --mark: rgba(197, 217, 50, 0.2);
89 +
90 + /* Syntax Theme */
91 + --astro-code-foreground: rgba(255, 255, 255, 0.9);
92 + --astro-code-background: rgba(255, 255, 255, 0.03);
93 + --astro-code-token-constant: rgba(255, 255, 255, 0.9);
94 + --astro-code-token-string: rgba(255, 255, 255, 0.9);
95 + --astro-code-token-comment: rgba(255, 255, 255, 0.35);
96 + --astro-code-token-keyword: rgba(255, 255, 255, 0.55);
97 + --astro-code-token-parameter: rgba(255, 255, 255, 0.9);
98 + --astro-code-token-function: rgba(255, 255, 255, 0.9);
99 + --astro-code-token-string-expression: rgba(255, 255, 255, 0.55);
100 + --astro-code-token-punctuation: rgba(255, 255, 255, 0.55);
101 + --astro-code-token-link: rgba(255, 255, 255, 0.55);
102 +}
103 +
104 +body {
105 + background-color: var(--bg);
106 + font-family: var(--font-sans);
107 + font-size: var(--font-size-m);
108 + line-height: 1.75;
109 + color: var(--text-primary);
110 + font-display: swap;
111 + word-wrap: break-word;
112 + overflow-wrap: break-word;
113 + margin: 0;
114 + min-height: 100vh;
115 + display: flex;
116 + flex-direction: column;
117 + box-sizing: border-box;
118 + letter-spacing: var(--spacing-m);
119 + padding: 6rem 1.5rem 1.5rem 1.5rem;
120 + overscroll-behavior-y: contain;
121 + transition: background-color 0.2s ease-out;
122 +}
123 +
124 +@media (max-width: 768px) {
125 + body {
126 + padding: 4rem 1.25rem 1.25rem 1.25rem;
127 + }
128 +}
129 +
130 +html {
131 + overscroll-behavior-y: contain;
132 + -webkit-overflow-scrolling: touch;
133 + scroll-behavior: smooth;
134 +}
135 +
136 +html.view-transitions-enabled {
137 + view-transition-name: enabled;
138 +}
139 +
140 +@view-transition {
141 + navigation: auto;
142 +}
143 +
144 +html.view-transitions-disabled {
145 + view-transition-name: none;
146 +}
147 +
148 +@media (prefers-reduced-motion: reduce) {
149 + @view-transition {
150 + navigation: none;
151 + }
152 +}
153 +
154 +::selection {
155 + background-color: var(--selection);
156 +}
157 +
158 +:focus {
159 + outline: 2px solid var(--accent);
160 + outline-offset: 2px;
161 +}
162 +
163 +:focus:not(:focus-visible) {
164 + outline: none;
165 +}
166 +
167 +:focus-visible {
168 + outline: 2px solid var(--accent);
169 + outline-offset: 2px;
170 +}
171 +
172 +body[data-width] {
173 + max-width: var(--content-width);
174 +}
175 +
176 +body[data-centered='true'] {
177 + margin: 0 auto;
178 +}
179 +
180 +main {
181 + flex: 1;
182 + display: flex;
183 + flex-direction: column;
184 + box-sizing: border-box;
185 +}
186 +
187 +.date {
188 + margin: 0;
189 + font-weight: var(--font-weight-light);
190 + color: var(--text-secondary);
191 + flex-shrink: 0;
192 + letter-spacing: var(--spacing-s);
193 + font-variant-numeric: tabular-nums;
194 + font-feature-settings:
195 + 'tnum' 1,
196 + 'zero' 0,
197 + 'cv01' 1,
198 + 'cv02' 1,
199 + 'calt' 1,
200 + 'ss03' 1,
201 + 'ordn' 1;
202 +}
203 +
204 +.date .month {
205 + letter-spacing: var(--spacing-m);
206 +}
207 +
208 +.sr-only {
209 + border: 0;
210 + padding: 0;
211 + margin: 0;
212 + position: absolute !important;
213 + height: 1px;
214 + width: 1px;
215 + overflow: hidden;
216 + clip: rect(1px 1px 1px 1px);
217 + clip: rect(1px, 1px, 1px, 1px);
218 + clip-path: inset(50%);
219 + white-space: nowrap;
220 +}
src/styles/post.css new
+532
@@ -0,0 +1,532 @@
1 +/* Base styles for all elements */
2 +.prose * {
3 + margin: 0;
4 + padding: 0;
5 + font-size: var(--font-size-m);
6 +}
7 +
8 +/* Main content container */
9 +.prose {
10 + margin-bottom: 8rem;
11 +}
12 +
13 +/* Post title section */
14 +.prose .title {
15 + margin-bottom: 2.5em;
16 +}
17 +
18 +.prose .title h1 {
19 + margin: 0 0 0.25rem 0;
20 +}
21 +
22 +/* Headings (h1-h5) */
23 +.prose h1,
24 +.prose h2,
25 +.prose h3,
26 +.prose h4,
27 +.prose h5 {
28 + font-size: var(--font-size-m);
29 + font-weight: var(--font-weight-bold);
30 + line-height: 1.75;
31 + margin: 3.25em 0 1em 0;
32 +}
33 +
34 +/* Bold text */
35 +.prose strong,
36 +.prose b {
37 + font-weight: var(--font-weight-bold);
38 +}
39 +
40 +/* Italic text */
41 +.prose em {
42 + font-family: var(--font-serif);
43 + font-style: italic;
44 + letter-spacing: 0;
45 +}
46 +
47 +/* Links */
48 +.prose a {
49 + color: var(--accent);
50 + text-decoration: underline;
51 + text-decoration-color: var(--text-tertiary);
52 + transition: text-decoration-color 0.2s ease-out;
53 +}
54 +
55 +.prose a:hover {
56 + color: var(--accent);
57 + text-decoration-color: var(--accent);
58 +}
59 +
60 +/* Paragraphs */
61 +.prose p {
62 + line-height: 1.75;
63 + margin-bottom: 1.25em;
64 +}
65 +
66 +/* Tables */
67 +.prose table {
68 + table-layout: fixed;
69 + width: 100%;
70 + border-collapse: separate;
71 + border-spacing: 0;
72 + margin: 1.25em 0;
73 + font-size: var(--font-size-m);
74 + border: 1px solid var(--border);
75 + border-radius: 8px;
76 + overflow: hidden;
77 +}
78 +
79 +/* Table cells */
80 +.prose th,
81 +.prose td {
82 + border: none;
83 + border-right: 1px solid var(--border);
84 + border-bottom: 1px solid var(--border);
85 + padding: 0.5em 1em;
86 + text-align: left;
87 +}
88 +
89 +.prose th:last-child,
90 +.prose td:last-child {
91 + border-right: none;
92 +}
93 +
94 +.prose tr:last-child td {
95 + border-bottom: none;
96 +}
97 +
98 +.prose th {
99 + background: var(--astro-code-background);
100 + font-weight: var(--font-weight-bold);
101 +}
102 +
103 +/* Images */
104 +.prose img {
105 + max-width: 100%;
106 + height: auto;
107 + display: block;
108 + margin: 1.25em 0;
109 +}
110 +
111 +.prose figure {
112 + margin-bottom: 1.25em;
113 + text-align: center;
114 +}
115 +
116 +.prose figure img {
117 + margin-bottom: 0.75em;
118 +}
119 +
120 +.prose figure figcaption {
121 + color: var(--text-secondary);
122 + font-size: var(--font-size-s);
123 + text-align: center;
124 +}
125 +
126 +.prose p > img {
127 + position: relative;
128 + margin-bottom: 1.25em;
129 +}
130 +
131 +.prose p > img::after {
132 + content: attr(alt);
133 + display: block;
134 + position: absolute;
135 + left: 0;
136 + width: 100%;
137 + text-align: center;
138 + color: var(--text-secondary);
139 + font-size: var(--font-size-s);
140 + margin-top: 0.75em;
141 +}
142 +
143 +.prose .img-caption {
144 + display: block;
145 + text-align: center;
146 + color: var(--text-secondary);
147 + font-size: var(--font-size-s);
148 + margin-bottom: 1.25em;
149 +}
150 +
151 +/* Inline code */
152 +.prose code {
153 + padding: 3px 4px;
154 + border-radius: 5px;
155 + background-color: var(--code-bg);
156 + font-family: var(--font-mono);
157 + font-size: 0.9em;
158 + font-feature-settings:
159 + 'liga' 0,
160 + 'calt' 0;
161 + -webkit-font-feature-settings:
162 + 'liga' 0,
163 + 'calt' 0;
164 +}
165 +
166 +/* Blockquotes */
167 +.prose blockquote {
168 + border-left: 1.5px solid var(--border);
169 + margin: 0 0 1.25em 0;
170 + padding: 0 0 0 1.25em;
171 + text-align: left;
172 +}
173 +
174 +.prose blockquote p {
175 + margin: 0;
176 +}
177 +
178 +.prose blockquote cite {
179 + display: inline-block;
180 + margin-top: 0.5em;
181 +}
182 +
183 +/* Unordered lists */
184 +.prose ul {
185 + list-style-type: none;
186 + padding-left: 0;
187 + margin-left: 1rem;
188 + margin-bottom: 1.25em;
189 + line-height: 1.75;
190 +}
191 +
192 +.prose ul ul {
193 + margin-left: 0.75rem;
194 + margin-top: 0.5em;
195 + margin-bottom: 0.5em;
196 +}
197 +
198 +.prose ul li {
199 + position: relative;
200 + padding-left: 0.25rem;
201 + margin-bottom: 0.5em;
202 +}
203 +
204 +.prose ul li:last-child {
205 + margin-bottom: 0;
206 +}
207 +
208 +.prose ul li > ul {
209 + margin-top: 0.5em;
210 + margin-bottom: 0.5em;
211 +}
212 +
213 +.prose ul li::before {
214 + content: '•';
215 + position: absolute;
216 + left: -1.375rem;
217 + top: -0.05em;
218 + width: 1.5rem;
219 + text-align: center;
220 + color: var(--text-tertiary);
221 +}
222 +
223 +/* Ordered lists */
224 +.prose ol {
225 + list-style-position: outside;
226 + padding-left: 0;
227 + margin-left: 1.25rem;
228 + margin-bottom: 1.25em;
229 + counter-reset: item;
230 +}
231 +
232 +.prose ol li {
233 + display: block;
234 + position: relative;
235 + margin-bottom: 0.5em;
236 +}
237 +
238 +.prose ol li:last-child {
239 + margin-bottom: 0;
240 +}
241 +
242 +.prose ol li::before {
243 + content: counter(item) '.';
244 + counter-increment: item;
245 + position: absolute;
246 + left: -1.15rem;
247 + width: 1.5rem;
248 + text-align: left;
249 + color: var(--text-secondary);
250 + font-variant-numeric: tabular-nums;
251 + font-feature-settings:
252 + 'tnum' 1,
253 + 'zero' 0,
254 + 'cv01' 1,
255 + 'cv02' 1,
256 + 'calt' 1,
257 + 'ss03' 1,
258 + 'liga' 1,
259 + 'ordn' 1;
260 +}
261 +
262 +/* Task lists */
263 +.prose ul.contains-task-list {
264 + list-style: none;
265 + margin-left: 0;
266 + white-space: nowrap;
267 +}
268 +
269 +.prose ul.contains-task-list li::before {
270 + content: none;
271 +}
272 +
273 +.prose ul.contains-task-list li.task-list-item {
274 + padding-left: 0.125em;
275 + margin-bottom: 0.5em;
276 +}
277 +
278 +.prose ul.contains-task-list li.task-list-item:last-child {
279 + margin-bottom: 0;
280 +}
281 +
282 +/* Task list checkboxes */
283 +.prose ul.contains-task-list li.task-list-item input[type='checkbox'] {
284 + margin-right: 0.375em;
285 + position: relative;
286 + top: 0.175em;
287 + width: 1em;
288 + height: 1em;
289 + border: 1.35px solid var(--text-tertiary);
290 + border-radius: 4px;
291 + background: transparent;
292 + appearance: none;
293 + -webkit-appearance: none;
294 +}
295 +
296 +.prose ul.contains-task-list li.task-list-item input[type='checkbox']:checked {
297 + position: relative;
298 + background: var(--code-bg);
299 + border: 1.35px solid var(--text-tertiary);
300 + opacity: 0.75;
301 +}
302 +
303 +.prose ul.contains-task-list li.task-list-item input[type='checkbox']:checked::before {
304 + content: '✓';
305 + font-family: var(--font-sans);
306 + color: var(--text-primary);
307 + opacity: 0.75;
308 + font-weight: var(--font-weight-bold);
309 + position: absolute;
310 + left: 0.15em;
311 + top: 0.05em;
312 + font-size: 0.75em;
313 + line-height: 1;
314 +}
315 +
316 +.prose ul.contains-task-list li.task-list-item input[type='checkbox'] + * {
317 + display: inline;
318 + margin-left: 0;
319 + line-height: 1.75;
320 + white-space: nowrap;
321 +}
322 +
323 +/* .prose ul.contains-task-list li.task-list-item:has(input[type='checkbox']:checked) {
324 + text-decoration: line-through;
325 +} */
326 +
327 +/* Subscript and superscript */
328 +.prose sup,
329 +.prose sub,
330 +.prose sup a {
331 + margin: 0 0.125em;
332 + font-size: 0.875em;
333 + line-height: 1;
334 +}
335 +
336 +/* Horizontal rule */
337 +.prose hr {
338 + margin: 2.5em 0;
339 + height: auto;
340 + border: none;
341 + background: none;
342 + text-align: center;
343 + position: relative;
344 +}
345 +
346 +.prose hr::before {
347 + content: '***';
348 + font-family: var(--font-mono);
349 + color: var(--text-tertiary);
350 + font-size: 0.875em;
351 + letter-spacing: 0.25em;
352 +}
353 +
354 +/* Keyboard input */
355 +.prose kbd {
356 + font-family: var(--font-mono);
357 + font-size: var(--font-size-s);
358 + border: 1px solid var(--text-tertiary);
359 + padding: 1px 4px;
360 + border-radius: 5px;
361 + min-width: 1.75em;
362 + display: inline-block;
363 + text-align: center;
364 + /* box-shadow: inset 0 -2.5px 0 var(--border); */
365 +}
366 +
367 +/* Highlighted text */
368 +.prose mark {
369 + background-color: var(--mark);
370 + color: var(--text-primary);
371 + padding: 3px 1px;
372 +}
373 +
374 +/* Footnotes */
375 +.prose .footnotes {
376 + margin-top: 4rem;
377 + padding-top: 1.75rem;
378 + position: relative;
379 +}
380 +
381 +.prose .footnotes::before {
382 + content: '';
383 + position: absolute;
384 + top: 0;
385 + left: 0;
386 + width: 4rem;
387 + height: 1px;
388 + background-color: var(--border);
389 +}
390 +
391 +.prose cite {
392 + font-style: normal;
393 +}
394 +
395 +/* Footnote references */
396 +.prose [data-footnote-backref] {
397 + position: relative;
398 + font-family: var(--font-mono);
399 + font-size: var(--font-size-l);
400 + top: -0.05em;
401 +}
402 +
403 +.prose [data-footnote-ref] {
404 + font-size: 1em;
405 + font-variant-numeric: tabular-nums;
406 + font-feature-settings:
407 + 'tnum' 1,
408 + 'zero' 0,
409 + 'cv01' 1,
410 + 'cv02' 1,
411 + 'calt' 1,
412 + 'ss03' 1,
413 + 'liga' 1,
414 + 'ordn' 1;
415 +}
416 +
417 +.prose [data-footnote-ref],
418 +.prose [data-footnote-backref] {
419 + color: var(--text-secondary);
420 + text-decoration: none;
421 + transition: color 0.2s ease-out;
422 + padding-right: 0.5em;
423 +}
424 +
425 +.prose [data-footnote-ref]:hover,
426 +.prose [data-footnote-backref]:hover {
427 + color: var(--text-primary);
428 +}
429 +
430 +/* Code blocks */
431 +.prose pre {
432 + background-color: var(--astro-code-background);
433 + border-radius: 8px;
434 + padding: 1.25em 1.5em;
435 + margin: 1.25em 0;
436 + overflow-x: auto;
437 +}
438 +
439 +@media (max-width: 768px) {
440 + .prose pre {
441 + padding: 1em 1.25em;
442 + }
443 +}
444 +
445 +.prose pre > code {
446 + font-family: var(--font-mono);
447 + font-feature-settings:
448 + 'liga' 0,
449 + 'calt' 0;
450 + display: block;
451 + white-space: pre-wrap;
452 + word-break: break-word;
453 + overflow-wrap: anywhere;
454 + padding: 0;
455 + margin: 0;
456 + background: none;
457 + border: none;
458 + line-height: 1.5;
459 + border-radius: 0;
460 +}
461 +
462 +.prose pre > code * {
463 + font-size: var(--font-size-s);
464 +}
465 +
466 +/* KaTeX Math Rendering */
467 +
468 +/* Hide MathML fallback to prevent duplication */
469 +.katex-mathml {
470 + display: none !important;
471 +}
472 +
473 +/* Ensure display math is centered */
474 +.katex-display {
475 + text-align: center;
476 + margin: 1.5em 0;
477 +}
478 +
479 +/* Reset any conflicting styles that might interfere with KaTeX */
480 +.katex * {
481 + box-sizing: content-box;
482 +}
483 +
484 +/* Ensure KaTeX elements inherit color properly */
485 +.katex,
486 +.katex * {
487 + color: inherit;
488 +}
489 +
490 +/* Specific fixes for common CSS framework conflicts */
491 +.katex .base,
492 +.katex .strut,
493 +.katex .mathit,
494 +.katex .mathrm,
495 +.katex .mathbf,
496 +.katex .mathsf,
497 +.katex .mathtt {
498 + line-height: initial;
499 + vertical-align: baseline;
500 +}
501 +
502 +/* Dark mode support */
503 +@media (prefers-color-scheme: dark) {
504 + .katex,
505 + .katex * {
506 + color: inherit;
507 + }
508 +}
509 +
510 +/* Reading Time */
511 +.reading-time {
512 + color: var(--text-secondary);
513 + letter-spacing: -0.025em;
514 +}
515 +
516 +.reading-time .separator {
517 + margin: 0 0.25em;
518 +}
519 +
520 +/* Video */
521 +.prose iframe {
522 + width: 100%;
523 + aspect-ratio: 16/9;
524 + border: none;
525 + border-radius: 6px;
526 + margin: 0.25em 0 0 0;
527 +}
528 +
529 +/* Spotify */
530 +.prose iframe[src*='spotify.com'] {
531 + aspect-ratio: auto;
532 +}
src/types/component.types.ts new
+33
@@ -0,0 +1,33 @@
1 +import type { TOCItem, ReadingTime } from './content.types'
2 +
3 +// TOC component props interface
4 +export interface TOCProps {
5 + toc?: TOCItem[]
6 +}
7 +
8 +// Post layout props interface (generic, not tied to specific data source)
9 +export interface PostLayoutProps {
10 + title: string
11 + pubDate: Date
12 + image?: string
13 + readingTime?: ReadingTime
14 + toc?: TOCItem[]
15 +}
16 +
17 +// Transition props interface
18 +export interface TransitionProps {
19 + type: 'post' | 'page'
20 + class?: string
21 +}
22 +
23 +// Layout props interface
24 +export interface LayoutProps extends TransitionProps {
25 + title?: string
26 + description?: string
27 +}
28 +
29 +// BaseHead component props interface
30 +export interface BaseHeadProps {
31 + title: string
32 + description: string
33 +}
src/types/config.types.ts new
+26
@@ -0,0 +1,26 @@
1 +// Date format types
2 +export type DateFormat =
3 + | 'YYYY-MM-DD'
4 + | 'MM-DD-YYYY'
5 + | 'DD-MM-YYYY'
6 + | 'MONTH DAY YYYY'
7 + | 'DAY MONTH YYYY'
8 +
9 +// Site configuration type
10 +export interface SiteConfig {
11 + website: string
12 + title: string
13 + author: string
14 + description: string
15 + language: string
16 + contentWidth: string
17 + centeredLayout: boolean
18 + favicon: boolean
19 + footer: boolean
20 + fadeAnimation: boolean
21 + dateFormat: DateFormat
22 + dateSeparator: string
23 + readingTime: boolean
24 + imageViewer: boolean
25 + copyCode: boolean
26 +}
src/types/content.types.ts new
+15
@@ -0,0 +1,15 @@
1 +// Reading time interface
2 +export interface ReadingTime {
3 + text: string
4 + minutes: number
5 + time: number
6 + words: number
7 +}
8 +
9 +// TOC item interface
10 +export interface TOCItem {
11 + level: number
12 + text: string
13 + id: string
14 + index: number
15 +}
src/types/index.ts new
+8
@@ -0,0 +1,8 @@
1 +// Configuration types
2 +export * from './config.types'
3 +
4 +// Content types
5 +export * from './content.types'
6 +
7 +// Component types
8 +export * from './component.types'
src/utils/date.ts new
+67
@@ -0,0 +1,67 @@
1 +import { SITE } from '@/config'
2 +
3 +const MONTHS_EN = [
4 + 'Jan',
5 + 'Feb',
6 + 'Mar',
7 + 'Apr',
8 + 'May',
9 + 'Jun',
10 + 'Jul',
11 + 'Aug',
12 + 'Sep',
13 + 'Oct',
14 + 'Nov',
15 + 'Dec'
16 +]
17 +
18 +const VALID_SEPARATORS = ['.', '-', '/']
19 +
20 +/**
21 + * @param date
22 + * @param format
23 + * @returns
24 + */
25 +export function formatDate(date: Date, format?: string): string {
26 + const formatStr = (format || SITE.dateFormat).trim()
27 + const configSeparator = SITE.dateSeparator || '-'
28 +
29 + const separator = VALID_SEPARATORS.includes(configSeparator.trim()) ? configSeparator.trim() : '.'
30 +
31 + const year = date.getFullYear()
32 + const month = date.getMonth() + 1
33 + const day = date.getDate()
34 + const monthName = MONTHS_EN[date.getMonth()]
35 +
36 + const pad = (num: number) => String(num).padStart(2, '0')
37 +
38 + switch (formatStr) {
39 + case 'YYYY-MM-DD':
40 + return `${year}${separator}${pad(month)}${separator}${pad(day)}`
41 +
42 + case 'MM-DD-YYYY':
43 + return `${pad(month)}${separator}${pad(day)}${separator}${year}`
44 +
45 + case 'DD-MM-YYYY':
46 + return `${pad(day)}${separator}${pad(month)}${separator}${year}`
47 +
48 + case 'MONTH DAY YYYY':
49 + return `<span class="month">${monthName}</span> ${day} ${year}`
50 +
51 + case 'DAY MONTH YYYY':
52 + return `${day} <span class="month">${monthName}</span> ${year}`
53 +
54 + default:
55 + return `${year}${separator}${pad(month)}${separator}${pad(day)}`
56 + }
57 +}
58 +
59 +export const SUPPORTED_DATE_FORMATS = [
60 + 'YYYY-MM-DD',
61 + 'MM-DD-YYYY',
62 + 'DD-MM-YYYY',
63 + 'MONTH DAY YYYY',
64 + 'DAY MONTH YYYY'
65 +] as const
66 +
67 +export type DateFormat = (typeof SUPPORTED_DATE_FORMATS)[number]
src/utils/draft.ts new
+27
@@ -0,0 +1,27 @@
1 +import { getCollection, type CollectionEntry } from 'astro:content'
2 +
3 +/**
4 + * Get all posts, filtering out posts whose filenames start with _ and static pages
5 + */
6 +export async function getFilteredPosts() {
7 + const posts = await getCollection('posts')
8 + const staticPages = ['privacy-policy', 'terms-of-use']
9 + const unpublishedPages = ['why-learn-persian', 'terms-of-use']
10 + return posts.filter(
11 + (post) =>
12 + !post.id.startsWith('_') &&
13 + !staticPages.includes(post.id) &&
14 + !unpublishedPages.includes(post.id)
15 + )
16 +}
17 +
18 +/**
19 + * Get all posts sorted by publication date, filtering out posts whose filenames start with _
20 + */
21 +export async function getSortedFilteredPosts() {
22 + const posts = await getFilteredPosts()
23 + return posts.sort(
24 + (a: CollectionEntry<'posts'>, b: CollectionEntry<'posts'>) =>
25 + b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
26 + )
27 +}
src/utils/feed.ts new
+72
@@ -0,0 +1,72 @@
1 +import type { CollectionEntry } from 'astro:content'
2 +import { SITE } from '@/config'
3 +import type { APIContext } from 'astro'
4 +import { getSortedFilteredPosts } from '@/utils/draft'
5 +
6 +export async function generateRSS(context: APIContext) {
7 + const sortedPosts = await getSortedFilteredPosts()
8 +
9 + const rss = `<?xml version="1.0" encoding="UTF-8" ?>
10 +<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
11 + <channel>
12 + <title>${SITE.title}</title>
13 + <link>${context.site}</link>
14 + <description>${SITE.description}</description>
15 + <language>zh-CN</language>
16 + <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
17 + <atom:link href="${context.site}/rss.xml" rel="self" type="application/rss+xml" />
18 + ${sortedPosts
19 + .map(
20 + (post: CollectionEntry<'posts'>) => `
21 + <item>
22 + <title><![CDATA[${post.data.title}]]></title>
23 + <link>${context.site}/${post.id}/</link>
24 + <guid>${context.site}/${post.id}/</guid>
25 + <pubDate>${post.data.pubDate.toUTCString()}</pubDate>
26 + <content:encoded><![CDATA[${post.body}]]></content:encoded>
27 + </item>
28 + `
29 + )
30 + .join('')}
31 + </channel>
32 +</rss>`
33 +
34 + return new Response(rss, {
35 + headers: {
36 + 'Content-Type': 'application/xml; charset=utf-8'
37 + }
38 + })
39 +}
40 +
41 +export async function generateAtom(context: APIContext) {
42 + const sortedPosts = await getSortedFilteredPosts()
43 +
44 + const atom = `<?xml version="1.0" encoding="utf-8"?>
45 +<feed xmlns="http://www.w3.org/2005/Atom">
46 + <title>${SITE.title}</title>
47 + <subtitle>${SITE.description}</subtitle>
48 + <link href="${context.site}/atom.xml" rel="self" type="application/atom+xml" />
49 + <link href="${context.site}" />
50 + <id>${context.site}</id>
51 + <updated>${new Date().toISOString()}</updated>
52 + ${sortedPosts
53 + .map(
54 + (post: CollectionEntry<'posts'>) => `
55 + <entry>
56 + <title>${post.data.title}</title>
57 + <link href="${context.site}/${post.id}/" />
58 + <id>${context.site}/${post.id}/</id>
59 + <published>${post.data.pubDate.toISOString()}</published>
60 + <content type="html"><![CDATA[${post.body}]]></content>
61 + </entry>
62 + `
63 + )
64 + .join('')}
65 +</feed>`
66 +
67 + return new Response(atom, {
68 + headers: {
69 + 'Content-Type': 'application/xml; charset=utf-8'
70 + }
71 + })
72 +}
tsconfig.json new
+12
@@ -0,0 +1,12 @@
1 +{
2 + "extends": "astro/tsconfigs/strict",
3 + "include": [".astro/types.d.ts", "**/*"],
4 + "exclude": ["dist"],
5 + "compilerOptions": {
6 + "strictNullChecks": true,
7 + "baseUrl": ".",
8 + "paths": {
9 + "@/*": ["src/*"]
10 + }
11 + }
12 +}