Added Masthead, CMDPalette and PostHeader Components
This commit is contained in:
@@ -4,14 +4,22 @@ import markdoc from '@astrojs/markdoc';
|
|||||||
import keystatic from '@keystatic/astro';
|
import keystatic from '@keystatic/astro';
|
||||||
import node from '@astrojs/node';
|
import node from '@astrojs/node';
|
||||||
|
|
||||||
|
import preact from '@astrojs/preact';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
output: 'static',
|
output: 'static',
|
||||||
integrations: [react(), markdoc(), keystatic()],
|
integrations: [react(), markdoc(), keystatic(), preact()],
|
||||||
|
|
||||||
adapter: node({
|
adapter: node({
|
||||||
mode: 'standalone',
|
mode: 'standalone',
|
||||||
}),
|
}),
|
||||||
});
|
vite: {
|
||||||
|
ssr: {
|
||||||
|
noExternal: ['lodash'],
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['react', 'react-dom', 'react/jsx-runtime'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
import { config } from '@keystatic/core';
|
import { config } from '@keystatic/core';
|
||||||
import { articles } from './src/keystatic/collections/articles';
|
import { articles } from './src/keystatic/collections/articles';
|
||||||
import { pages } from './src/keystatic/collections/pages';
|
import { pages } from './src/keystatic/collections/pages';
|
||||||
|
import crucibleCollections from './src/keystatic/collections/crucible';
|
||||||
|
|
||||||
export default config({
|
export default config({
|
||||||
storage: {
|
storage: {
|
||||||
kind: 'local',
|
kind: 'local',
|
||||||
},
|
},
|
||||||
|
ui: {
|
||||||
|
navigation: {
|
||||||
|
General: ['articles', 'pages'],
|
||||||
|
Crucible: ['cr_elements'],
|
||||||
|
},
|
||||||
|
},
|
||||||
collections: {
|
collections: {
|
||||||
articles,
|
articles,
|
||||||
pages,
|
pages,
|
||||||
|
...crucibleCollections,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
14
markdoc.config.mjs
Normal file
14
markdoc.config.mjs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
|
||||||
|
|
||||||
|
export default defineMarkdocConfig({
|
||||||
|
tags: {
|
||||||
|
ElementSymbol: {
|
||||||
|
render: component('./src/components/content/ElementSymbol.astro'),
|
||||||
|
attributes: {
|
||||||
|
element: { type: String },
|
||||||
|
size: { type: String },
|
||||||
|
color: { type: String },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
520
package-lock.json
generated
520
package-lock.json
generated
@@ -11,15 +11,18 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/markdoc": "^0.12.9",
|
"@astrojs/markdoc": "^0.12.9",
|
||||||
"@astrojs/node": "^9.5.4",
|
"@astrojs/node": "^9.5.4",
|
||||||
|
"@astrojs/preact": "^4.1.3",
|
||||||
"@astrojs/react": "^4.2.0",
|
"@astrojs/react": "^4.2.0",
|
||||||
"@fontsource-variable/geist": "^5.2.8",
|
"@fontsource-variable/geist": "^5.2.8",
|
||||||
"@fontsource-variable/geist-mono": "^5.2.7",
|
"@fontsource-variable/geist-mono": "^5.2.7",
|
||||||
"@fontsource/blaka": "^5.2.7",
|
"@fontsource/blaka": "^5.2.7",
|
||||||
|
"@keystar/ui": "^0.7.19",
|
||||||
"@keystatic/astro": "^5.0.6",
|
"@keystatic/astro": "^5.0.6",
|
||||||
"@keystatic/core": "^0.5.48",
|
"@keystatic/core": "^0.5.48",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.0.3",
|
||||||
"astro": "^5.2.5",
|
"astro": "^5.2.5",
|
||||||
|
"preact": "^10.28.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
@@ -29,11 +32,16 @@
|
|||||||
"@typescript-eslint/parser": "^8.56.0",
|
"@typescript-eslint/parser": "^8.56.0",
|
||||||
"eslint": "^10.0.0",
|
"eslint": "^10.0.0",
|
||||||
"eslint-plugin-astro": "^1.6.0",
|
"eslint-plugin-astro": "^1.6.0",
|
||||||
|
"postcss-html": "^1.8.1",
|
||||||
"postcss-import": "^16.1.1",
|
"postcss-import": "^16.1.1",
|
||||||
|
"postcss-mixins": "^12.1.2",
|
||||||
"postcss-preset-env": "^11.1.3",
|
"postcss-preset-env": "^11.1.3",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-astro": "^0.14.1",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
"stylelint": "^17.3.0",
|
"stylelint": "^17.3.0",
|
||||||
|
"stylelint-config-astro": "^2.0.0",
|
||||||
|
"stylelint-config-clean-order": "^8.0.1",
|
||||||
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-standard": "^40.0.0",
|
"stylelint-config-standard": "^40.0.0",
|
||||||
"stylelint-order": "^7.0.1"
|
"stylelint-order": "^7.0.1"
|
||||||
}
|
}
|
||||||
@@ -134,6 +142,24 @@
|
|||||||
"integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==",
|
"integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@astrojs/preact": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@astrojs/preact/-/preact-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-Ph416wbgyumkmYr7erZ83l/d+LXdZethlHRRCbgoKEn8wo3Rkq13shKFp0QYXYSDYxVaA6UBdkdimeowy/lMLQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@preact/preset-vite": "^2.10.2",
|
||||||
|
"@preact/signals": "^2.3.1",
|
||||||
|
"preact-render-to-string": "^6.6.1",
|
||||||
|
"vite": "^6.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "18.20.8 || ^20.3.0 || >=22.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": "^10.6.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@astrojs/prism": {
|
"node_modules/@astrojs/prism": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.2.0.tgz",
|
||||||
@@ -259,6 +285,18 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/helper-annotate-as-pure": {
|
||||||
|
"version": "7.27.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
|
||||||
|
"integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/types": "^7.27.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.28.6",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
||||||
@@ -387,6 +425,55 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/plugin-syntax-jsx": {
|
||||||
|
"version": "7.28.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
|
||||||
|
"integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-plugin-utils": "^7.28.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/plugin-transform-react-jsx": {
|
||||||
|
"version": "7.28.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz",
|
||||||
|
"integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-annotate-as-pure": "^7.27.3",
|
||||||
|
"@babel/helper-module-imports": "^7.28.6",
|
||||||
|
"@babel/helper-plugin-utils": "^7.28.6",
|
||||||
|
"@babel/plugin-syntax-jsx": "^7.28.6",
|
||||||
|
"@babel/types": "^7.28.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/plugin-transform-react-jsx-development": {
|
||||||
|
"version": "7.27.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz",
|
||||||
|
"integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/plugin-transform-react-jsx": "^7.27.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
||||||
"version": "7.27.1",
|
"version": "7.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
|
||||||
@@ -3667,6 +3754,121 @@
|
|||||||
"url": "https://opencollective.com/pkgr"
|
"url": "https://opencollective.com/pkgr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@preact/preset-vite": {
|
||||||
|
"version": "2.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.10.3.tgz",
|
||||||
|
"integrity": "sha512-1SiS+vFItpkNdBs7q585PSAIln0wBeBdcpJYbzPs1qipsb/FssnkUioNXuRsb8ZnU8YEQHr+3v8+/mzWSnTQmg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/plugin-transform-react-jsx": "^7.27.1",
|
||||||
|
"@babel/plugin-transform-react-jsx-development": "^7.27.1",
|
||||||
|
"@prefresh/vite": "^2.4.11",
|
||||||
|
"@rollup/pluginutils": "^5.0.0",
|
||||||
|
"babel-plugin-transform-hook-names": "^1.0.2",
|
||||||
|
"debug": "^4.4.3",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"vite-prerender-plugin": "^0.5.8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "7.x",
|
||||||
|
"vite": "2.x || 3.x || 4.x || 5.x || 6.x || 7.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@preact/signals": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@preact/signals/-/signals-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-wX6U0SpcCukZTJBs5ChljvBZb3XmYzA5gd4vKHgX8wZZKaQCo2WHtmThdLx+mcVvlBa5u3XShC7ffbETJD4BiQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@preact/signals-core": "^1.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": ">= 10.25.0 || >=11.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@preact/signals-core": {
|
||||||
|
"version": "1.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.13.0.tgz",
|
||||||
|
"integrity": "sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/babel-plugin": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/core": {
|
||||||
|
"version": "1.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prefresh/core/-/core-1.5.9.tgz",
|
||||||
|
"integrity": "sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": "^10.0.0 || ^11.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/utils": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prefresh/utils/-/utils-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/vite": {
|
||||||
|
"version": "2.4.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.12.tgz",
|
||||||
|
"integrity": "sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.22.1",
|
||||||
|
"@prefresh/babel-plugin": "^0.5.2",
|
||||||
|
"@prefresh/core": "^1.5.0",
|
||||||
|
"@prefresh/utils": "^1.2.0",
|
||||||
|
"@rollup/pluginutils": "^4.2.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": "^10.4.0 || ^11.0.0-0",
|
||||||
|
"vite": ">=2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/vite/node_modules/@rollup/pluginutils": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"estree-walker": "^2.0.1",
|
||||||
|
"picomatch": "^2.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/vite/node_modules/estree-walker": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@prefresh/vite/node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-aria/actiongroup": {
|
"node_modules/@react-aria/actiongroup": {
|
||||||
"version": "3.7.23",
|
"version": "3.7.23",
|
||||||
"resolved": "https://registry.npmjs.org/@react-aria/actiongroup/-/actiongroup-3.7.23.tgz",
|
"resolved": "https://registry.npmjs.org/@react-aria/actiongroup/-/actiongroup-3.7.23.tgz",
|
||||||
@@ -7369,6 +7571,15 @@
|
|||||||
"npm": ">=6"
|
"npm": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/babel-plugin-transform-hook-names": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/babel-plugin-transform-hook-names/-/babel-plugin-transform-hook-names-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.12.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bail": {
|
"node_modules/bail": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
||||||
@@ -7528,6 +7739,16 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelcase-css": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001770",
|
"version": "1.0.30001770",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
|
||||||
@@ -9333,6 +9554,15 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/he": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"he": "bin/he"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hookified": {
|
"node_modules/hookified": {
|
||||||
"version": "1.15.1",
|
"version": "1.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz",
|
||||||
@@ -9832,6 +10062,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/kolorist": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/levn": {
|
"node_modules/levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
@@ -11170,6 +11406,16 @@
|
|||||||
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
|
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-html-parser": {
|
||||||
|
"version": "6.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz",
|
||||||
|
"integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-select": "^5.1.0",
|
||||||
|
"he": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-mock-http": {
|
"node_modules/node-mock-http": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz",
|
||||||
@@ -11923,6 +12169,79 @@
|
|||||||
"postcss": "^8.4"
|
"postcss": "^8.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-html": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-OLF6P7qctfAWayOhLpcVnTGqVeJzu2W3WpIYelfz2+JV5oGxfkcEvweN9U4XpeqE0P98dcD9ssusGwlF0TK0uQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"htmlparser2": "^8.0.0",
|
||||||
|
"js-tokens": "^9.0.0",
|
||||||
|
"postcss": "^8.5.0",
|
||||||
|
"postcss-safe-parser": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-html/node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-html/node_modules/htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-html/node_modules/js-tokens": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/postcss-html/node_modules/postcss-safe-parser": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-image-set-function": {
|
"node_modules/postcss-image-set-function": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-8.0.0.tgz",
|
||||||
@@ -11968,6 +12287,32 @@
|
|||||||
"postcss": "^8.0.0"
|
"postcss": "^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-js": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase-css": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12 || ^14 || >= 16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.4.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-lab-function": {
|
"node_modules/postcss-lab-function": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-8.0.1.tgz",
|
||||||
@@ -12024,6 +12369,35 @@
|
|||||||
"postcss": "^8.4"
|
"postcss": "^8.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-mixins": {
|
||||||
|
"version": "12.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-12.1.2.tgz",
|
||||||
|
"integrity": "sha512-90pSxmZVfbX9e5xCv7tI5RV1mnjdf16y89CJKbf/hD7GyOz1FCxcYMl8ZYA8Hc56dbApTKKmU9HfvgfWdCxlwg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-js": "^4.0.1",
|
||||||
|
"postcss-simple-vars": "^7.0.1",
|
||||||
|
"sugarss": "^5.0.0",
|
||||||
|
"tinyglobby": "^0.2.14"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.0 || ^22.0 || >=24.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-nesting": {
|
"node_modules/postcss-nesting": {
|
||||||
"version": "14.0.0",
|
"version": "14.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-14.0.0.tgz",
|
||||||
@@ -12337,6 +12711,23 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-simple-vars": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-sorting": {
|
"node_modules/postcss-sorting": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-9.1.0.tgz",
|
||||||
@@ -12372,6 +12763,25 @@
|
|||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/preact": {
|
||||||
|
"version": "10.28.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz",
|
||||||
|
"integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/preact-render-to-string": {
|
||||||
|
"version": "6.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.6.tgz",
|
||||||
|
"integrity": "sha512-EfqZJytnjJldV+YaaqhthU2oXsEf5e+6rDv957p+zxAvNfFLQOPfvBOTncscQ+akzu6Wrl7s3Pa0LjUQmWJsGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": ">=10 || >= 11.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@@ -13205,6 +13615,15 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-code-frame": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-code-frame/-/simple-code-frame-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"kolorist": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@@ -13364,6 +13783,15 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stack-trace": {
|
||||||
|
"version": "1.0.0-pre2",
|
||||||
|
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-1.0.0-pre2.tgz",
|
||||||
|
"integrity": "sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
@@ -13483,6 +13911,48 @@
|
|||||||
"node": ">=20.19.0"
|
"node": ">=20.19.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylelint-config-astro": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-astro/-/stylelint-config-astro-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BSl+wNEa3h1+GhHAfI3WO/fPylcVoePLIMd+JX1hz1Pt2cnqRswjfA4EqD6Wy2DqrariqYJE1xXZCnuJNrjb8w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss-html": "^1.0.0",
|
||||||
|
"stylelint": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/stylelint-config-clean-order": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-clean-order/-/stylelint-config-clean-order-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-zKjp7BiINXRZOG9m0fE/6UKoM6clPekL+LoAiHMCiQU2hgirKL5G0mKc5Z0ygIhQXfb1+DTRDM0mu6Ecdv4q8g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"stylelint": ">=16",
|
||||||
|
"stylelint-order": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/stylelint-config-html": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylelint-config-html/-/stylelint-config-html-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12 || >=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ota-meshi"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss-html": "^1.0.0",
|
||||||
|
"stylelint": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stylelint-config-recommended": {
|
"node_modules/stylelint-config-recommended": {
|
||||||
"version": "18.0.0",
|
"version": "18.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz",
|
||||||
@@ -13651,6 +14121,29 @@
|
|||||||
"s.color": "0.0.15"
|
"s.color": "0.0.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sugarss": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sugarss/-/sugarss-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-ctS5RYCBVvPoZAnzIaX5QSShK8ZiZxD5HUqSxlusvEMC+QZQIPCPOIJg6aceFX+K2rf4+SH89eu++h1Zmsr2nw==",
|
||||||
|
"devOptional": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/superstruct": {
|
"node_modules/superstruct": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz",
|
||||||
@@ -13995,7 +14488,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -14492,6 +14984,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-prerender-plugin": {
|
||||||
|
"version": "0.5.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-prerender-plugin/-/vite-prerender-plugin-0.5.12.tgz",
|
||||||
|
"integrity": "sha512-EiwhbMn+flg14EysbLTmZSzq8NGTxhytgK3bf4aGRF1evWLGwZiHiUJ1KZDvbxgKbMf2pG6fJWGEa3UZXOnR1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"kolorist": "^1.8.0",
|
||||||
|
"magic-string": "0.x >= 0.26.0",
|
||||||
|
"node-html-parser": "^6.1.12",
|
||||||
|
"simple-code-frame": "^1.3.0",
|
||||||
|
"source-map": "^0.7.4",
|
||||||
|
"stack-trace": "^1.0.0-pre2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": "5.x || 6.x || 7.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite-prerender-plugin/node_modules/source-map": {
|
||||||
|
"version": "0.7.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||||
|
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vitefu": {
|
"node_modules/vitefu": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
|
||||||
|
|||||||
@@ -10,15 +10,18 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/markdoc": "^0.12.9",
|
"@astrojs/markdoc": "^0.12.9",
|
||||||
"@astrojs/node": "^9.5.4",
|
"@astrojs/node": "^9.5.4",
|
||||||
|
"@astrojs/preact": "^4.1.3",
|
||||||
"@astrojs/react": "^4.2.0",
|
"@astrojs/react": "^4.2.0",
|
||||||
"@fontsource-variable/geist": "^5.2.8",
|
"@fontsource-variable/geist": "^5.2.8",
|
||||||
"@fontsource-variable/geist-mono": "^5.2.7",
|
"@fontsource-variable/geist-mono": "^5.2.7",
|
||||||
"@fontsource/blaka": "^5.2.7",
|
"@fontsource/blaka": "^5.2.7",
|
||||||
|
"@keystar/ui": "^0.7.19",
|
||||||
"@keystatic/astro": "^5.0.6",
|
"@keystatic/astro": "^5.0.6",
|
||||||
"@keystatic/core": "^0.5.48",
|
"@keystatic/core": "^0.5.48",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.0.3",
|
||||||
"astro": "^5.2.5",
|
"astro": "^5.2.5",
|
||||||
|
"preact": "^10.28.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
@@ -35,11 +38,16 @@
|
|||||||
"@typescript-eslint/parser": "^8.56.0",
|
"@typescript-eslint/parser": "^8.56.0",
|
||||||
"eslint": "^10.0.0",
|
"eslint": "^10.0.0",
|
||||||
"eslint-plugin-astro": "^1.6.0",
|
"eslint-plugin-astro": "^1.6.0",
|
||||||
|
"postcss-html": "^1.8.1",
|
||||||
"postcss-import": "^16.1.1",
|
"postcss-import": "^16.1.1",
|
||||||
|
"postcss-mixins": "^12.1.2",
|
||||||
"postcss-preset-env": "^11.1.3",
|
"postcss-preset-env": "^11.1.3",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-astro": "^0.14.1",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
"stylelint": "^17.3.0",
|
"stylelint": "^17.3.0",
|
||||||
|
"stylelint-config-astro": "^2.0.0",
|
||||||
|
"stylelint-config-clean-order": "^8.0.1",
|
||||||
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-standard": "^40.0.0",
|
"stylelint-config-standard": "^40.0.0",
|
||||||
"stylelint-order": "^7.0.1"
|
"stylelint-order": "^7.0.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import postcssGlobalData from '@csstools/postcss-global-data';
|
import postcssGlobalData from '@csstools/postcss-global-data';
|
||||||
import postcssImport from 'postcss-import';
|
import postcssImport from 'postcss-import';
|
||||||
import postcssPresetEnv from 'postcss-preset-env';
|
import postcssPresetEnv from 'postcss-preset-env';
|
||||||
|
import postcssMixins from 'postcss-mixins';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
plugins: [
|
plugins: [
|
||||||
postcssGlobalData({
|
postcssGlobalData({
|
||||||
files: ['./src/styles/custom-media.css'],
|
files: ['./src/styles/base/custom-media.css'],
|
||||||
|
}),
|
||||||
|
postcssMixins({
|
||||||
|
mixinsDir: './src/styles/mixins/',
|
||||||
}),
|
}),
|
||||||
postcssImport(),
|
postcssImport(),
|
||||||
postcssPresetEnv({
|
postcssPresetEnv({
|
||||||
|
|||||||
72
src/components/content/ElementSymbol.astro
Normal file
72
src/components/content/ElementSymbol.astro
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
import { getEntry } from 'astro:content';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
element: string;
|
||||||
|
size: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FontSymbol {
|
||||||
|
discriminant: 'font';
|
||||||
|
value: {
|
||||||
|
family: string;
|
||||||
|
character: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SVGSymbol {
|
||||||
|
discriminant: 'svg';
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Symbol = FontSymbol | SVGSymbol;
|
||||||
|
|
||||||
|
const { element, size, color } = Astro.props;
|
||||||
|
const entry = await getEntry('elements', element);
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
console.warn(`Element not found: ${element}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const symbol = entry?.data.symbol as Symbol | undefined;
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
symbol?.discriminant === 'font' && (
|
||||||
|
<span
|
||||||
|
class="element font"
|
||||||
|
style={`font-family: '${(symbol as FontSymbol).value.family}', sans-serif; font-size: ${size}; color: ${color};`}
|
||||||
|
>
|
||||||
|
{(symbol as FontSymbol).value.character}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
symbol?.discriminant === 'svg' && (
|
||||||
|
<span
|
||||||
|
class="element svg"
|
||||||
|
style={`width: ${size}; height: ${size}; color: ${color}`}
|
||||||
|
set:html={(symbol as SVGSymbol).value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.font {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.svg {
|
||||||
|
display: inline-flex;
|
||||||
|
line-height: 1;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.svg :global(svg) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
211
src/components/layout/CMDPalette/CMDPalette.module.css
Normal file
211
src/components/layout/CMDPalette/CMDPalette.module.css
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
.trigger {
|
||||||
|
@mixin ml auto;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap:var(--ui-spacing-comfortable);
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
padding: var(--ui-spacing-snug) var(--ui-spacing-spacious);
|
||||||
|
border: var(--size-px) solid var(--color-border-normal);
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-md);
|
||||||
|
color: var(--text-color-disabled);
|
||||||
|
|
||||||
|
background: var(--color-palette-charcoal-gray);
|
||||||
|
|
||||||
|
transition: border-color 0.15s, color 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--color-text-inverse);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .kbd {
|
||||||
|
padding: var(--ui-spacing-hairline) var( --ui-spacing-cozy);
|
||||||
|
border: var(--size-px) solid var(--color-border-normal);
|
||||||
|
border-radius: var(--size-05);
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-xs);
|
||||||
|
|
||||||
|
background: var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.backdrop {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--color-overlay-heavy);
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
top: 20%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
width: min(var(--size-128), 90vw);
|
||||||
|
padding: var(--ui-spacing-tight);
|
||||||
|
border: var(--size-05) solid var(--color-primary);
|
||||||
|
|
||||||
|
background: var(--color-surface-inverse);
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 var(--size-px) var(--color-border-strong),
|
||||||
|
var(--size-1) var(--size-1) 0 var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
@mixin px var(--ui-spacing-generous);
|
||||||
|
@mixin border-b var(--size-px), solid, var(--color-border-strong);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: var(--ui-spacing-comfortable);
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& .icon {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-lg);
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .input {
|
||||||
|
@mixin py var(--ui-spacing-generous);
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-lg);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
|
||||||
|
background: transparent;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .esc {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--typo-size-xs);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: var(--size-96);
|
||||||
|
|
||||||
|
& .groupLabel {
|
||||||
|
padding: var(--ui-spacing-relaxed) var(--ui-spacing-generous) var(--ui-spacing-snug);
|
||||||
|
|
||||||
|
font-size: var(--ui-typo-size-2xs);
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--spacing-loosest);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .result {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: var(--ui-spacing-relaxed);
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
padding: var(--ui-spacing-comfortable) var(--ui-spacing-generous);
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-md);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--typo-spacing-relaxed);
|
||||||
|
|
||||||
|
transition: background 0.8s;
|
||||||
|
|
||||||
|
& .type {
|
||||||
|
min-width: var(--size-16);
|
||||||
|
|
||||||
|
font-size: var(--ui-typo-size-2xs);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
text-align: right;
|
||||||
|
letter-spacing: var(--typo-spacing-looser);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .label {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .path {
|
||||||
|
font-size: var(--ui-typo-size-2xs);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .arrow {
|
||||||
|
font-size: var(--ui-typo-size-xs);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.selected {
|
||||||
|
background: var(--color-border-strong);
|
||||||
|
|
||||||
|
& .arrow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
padding: var(--ui-spacing-luxurious) var(--ui-spacing-generous);
|
||||||
|
|
||||||
|
font-size: var(--ui-typo-size-sm);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--typo-spacing-comfortable);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
@mixin border-t var(--size-px), solid, var(--color-border-strong);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
padding: var(--ui-spacing-comfortable) var(--ui-spacing-generous);
|
||||||
|
|
||||||
|
font-size: var(--ui-typo-size-xs);
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
|
||||||
|
& .group {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--ui-spacing-relaxed);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& kbd {
|
||||||
|
@mixin mx var(--ui-spacing-tight);
|
||||||
|
|
||||||
|
padding: var(--ui-spacing-tight) var(--ui-spacing-snug);
|
||||||
|
border: var(--size-px) solid var(--color-border-normal);
|
||||||
|
border-radius: var(--size-05);
|
||||||
|
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--ui-typo-size-2xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
287
src/components/layout/CMDPalette/index.tsx
Normal file
287
src/components/layout/CMDPalette/index.tsx
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
import {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
} from 'preact/hooks';
|
||||||
|
import type { PaletteEntry, ContentType } from '@lib/types/content';
|
||||||
|
import styles from './CMDPalette.module.css';
|
||||||
|
|
||||||
|
/* CONSTANTS */
|
||||||
|
const MAX_DEFAULT = 20;
|
||||||
|
const MAX_SEARCH = 30;
|
||||||
|
|
||||||
|
const TYPE_LABELS: Record<ContentType, string> = {
|
||||||
|
article: 'Article',
|
||||||
|
element: 'Element',
|
||||||
|
page: 'Page',
|
||||||
|
};
|
||||||
|
|
||||||
|
/* INDEX ENTRY */
|
||||||
|
interface IndexedEntry extends PaletteEntry {
|
||||||
|
_label: string;
|
||||||
|
_parent: string;
|
||||||
|
_type: string;
|
||||||
|
_path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalize = (str: string): string =>
|
||||||
|
str.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
|
|
||||||
|
const indexEntry = (entry: PaletteEntry): IndexedEntry => ({
|
||||||
|
...entry,
|
||||||
|
_label: normalize(entry.label),
|
||||||
|
_parent: normalize(entry.parent ?? ''),
|
||||||
|
_type: normalize(entry.type),
|
||||||
|
_path: normalize(entry.path),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* SCORING */
|
||||||
|
const scoreEntry = (entry: IndexedEntry, q: string): number => {
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
if (entry._label === q) score += 100;
|
||||||
|
else if (entry._label.startsWith(q)) score += 80;
|
||||||
|
else if (entry._label.includes(q)) score += 60;
|
||||||
|
if (entry._parent.includes(q)) score += 30;
|
||||||
|
if (entry._type.includes(q)) score += 20;
|
||||||
|
if (entry._path.includes(q)) score += 10;
|
||||||
|
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* RENDERABLE ROW – single-pass from filtered entries */
|
||||||
|
interface RenderRow {
|
||||||
|
kind: 'label' | 'result';
|
||||||
|
key: string;
|
||||||
|
group?: string;
|
||||||
|
entry?: PaletteEntry;
|
||||||
|
index?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildRows = (entries: PaletteEntry[]): RenderRow[] => {
|
||||||
|
const rows: RenderRow[] = [];
|
||||||
|
let currentGroup = '';
|
||||||
|
let idx = 0;
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const group = entry.parent ?? TYPE_LABELS[entry.type] ?? 'Other';
|
||||||
|
|
||||||
|
if (group !== currentGroup) {
|
||||||
|
currentGroup = group;
|
||||||
|
rows.push({ kind: 'label', key: `label-${group}`, group });
|
||||||
|
}
|
||||||
|
rows.push({
|
||||||
|
kind: 'result',
|
||||||
|
key: entry.path,
|
||||||
|
entry,
|
||||||
|
index: idx++,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* COMPONENT */
|
||||||
|
export default function CommandPalette() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [query, setQuery] = useState('');
|
||||||
|
const [index, setIndex] = useState<IndexedEntry[]>([]);
|
||||||
|
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||||
|
|
||||||
|
const selectedRef = useRef(-1);
|
||||||
|
const loadingRef = useRef(false);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const resultsRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
/* Keep ref in sync for stable access in callbacks */
|
||||||
|
useEffect(() => {
|
||||||
|
selectedRef.current = selectedIndex;
|
||||||
|
}, [selectedIndex]);
|
||||||
|
|
||||||
|
/* Load index (ref-guarded, no race conditions) */
|
||||||
|
const loadIndex = useCallback(async () => {
|
||||||
|
if (index.length > 0 || loadingRef.current) return;
|
||||||
|
loadingRef.current = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/palette-index.json');
|
||||||
|
const data: PaletteEntry[] = await res.json();
|
||||||
|
setIndex(data.map(indexEntry));
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load palette index:', err);
|
||||||
|
loadingRef.current = false;
|
||||||
|
}
|
||||||
|
}, [index.length]);
|
||||||
|
|
||||||
|
/* OPEN / CLOSE */
|
||||||
|
const open = useCallback(async () => {
|
||||||
|
await loadIndex();
|
||||||
|
setIsOpen(true);
|
||||||
|
setQuery('');
|
||||||
|
setSelectedIndex(-1);
|
||||||
|
}, [loadIndex]);
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
setSelectedIndex(-1);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/* GLOBAL KEYBOARD SHORTCUTS */
|
||||||
|
useEffect(() => {
|
||||||
|
const onKeydown = (e: KeyboardEvent) => {
|
||||||
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||||
|
e.preventDefault();
|
||||||
|
isOpen ? close() : open();
|
||||||
|
}
|
||||||
|
if (e.key === 'Escape' && isOpen) {
|
||||||
|
e.preventDefault();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', onKeydown);
|
||||||
|
return () => document.removeEventListener('keydown', onKeydown);
|
||||||
|
}, [isOpen, open, close]);
|
||||||
|
|
||||||
|
/* FOCUS INPUT WHEN OPENING*/
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) requestAnimationFrame(() => inputRef.current?.focus());
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
/* FILTERED ENTRIES -> RENDER ROWS */
|
||||||
|
const filtered = useMemo(() => {
|
||||||
|
if (!query.trim()) {
|
||||||
|
return index.filter((e) => e.depth <= 2).slice(0, MAX_DEFAULT);
|
||||||
|
}
|
||||||
|
const q = normalize(query);
|
||||||
|
return index
|
||||||
|
.map((entry) => ({ entry, score: scoreEntry(entry, q) }))
|
||||||
|
.filter((r) => r.score > 0)
|
||||||
|
.sort((a, b) => b.score - a.score)
|
||||||
|
.slice(0, MAX_SEARCH)
|
||||||
|
.map((r) => r.entry);
|
||||||
|
}, [index, query]);
|
||||||
|
|
||||||
|
const rows = useMemo(() => buildRows(filtered), [filtered]);
|
||||||
|
|
||||||
|
/* COUNT OF NAVIGABLE RESULTS (excludes labels) */
|
||||||
|
const resultCount = useMemo(
|
||||||
|
() => rows.filter((r) => r.kind === 'result').length,
|
||||||
|
[rows],
|
||||||
|
);
|
||||||
|
|
||||||
|
/* RESET SELECTION ON QUERY CHANGE */
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedIndex(-1);
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
|
/*SCROLL SELECTED INTO VIEW */
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedIndex < 0) return;
|
||||||
|
resultsRef.current
|
||||||
|
?.querySelector(`[data-index="${selectedIndex}"]`)
|
||||||
|
?.scrollIntoView({ block: 'nearest' });
|
||||||
|
}, [selectedIndex]);
|
||||||
|
|
||||||
|
/* INPUT KEYBOARD NAVIGATION */
|
||||||
|
const onInputKeydown = useCallback(
|
||||||
|
(e: KeyboardEvent) => {
|
||||||
|
if (!resultCount) return;
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setSelectedIndex((i) => (i + 1) % resultCount);
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
setSelectedIndex((i) => (i <= 0 ? resultCount - 1 : i - 1));
|
||||||
|
} else if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
const idx = selectedRef.current;
|
||||||
|
const target = rows.find((r) => r.kind === 'result' && r.index === idx);
|
||||||
|
if (target?.entry) {
|
||||||
|
window.location.href = target.entry.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[resultCount, rows],
|
||||||
|
);
|
||||||
|
|
||||||
|
/* RENDER */
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
class={styles.trigger}
|
||||||
|
onClick={open}
|
||||||
|
aria-label="Open Navigation"
|
||||||
|
>
|
||||||
|
<span>Navigate…</span>
|
||||||
|
<kbd class={styles.kbd}>⌘K</kbd>
|
||||||
|
</button>
|
||||||
|
{isOpen && <div class={styles.backdrop} onClick={close} />}
|
||||||
|
{isOpen && (
|
||||||
|
<div
|
||||||
|
class={styles.palette}
|
||||||
|
role="dialog"
|
||||||
|
aria-label="Navigation palette"
|
||||||
|
>
|
||||||
|
<div class={styles.header}>
|
||||||
|
<span class={styles.icon}>⟩</span>
|
||||||
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
class={styles.input}
|
||||||
|
type="text"
|
||||||
|
placeholder="Where do you want to go?"
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck={false}
|
||||||
|
value={query}
|
||||||
|
onInput={(e) => setQuery((e.target as HTMLInputElement).value)}
|
||||||
|
onKeyDown={onInputKeydown}
|
||||||
|
/>
|
||||||
|
<kbd class={styles.esc}>esc</kbd>
|
||||||
|
</div>
|
||||||
|
<div class={styles.results} ref={resultsRef} role="listbox">
|
||||||
|
{rows.map((row) =>
|
||||||
|
row.kind === 'label' ? (
|
||||||
|
<div key={row.key} class={styles.groupLabel}>
|
||||||
|
{row.group}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<a
|
||||||
|
key={row.key}
|
||||||
|
class={`${styles.result}${row.index === selectedIndex ? ` ${styles.selected}` : ''}`}
|
||||||
|
href={row.entry!.path}
|
||||||
|
role="option"
|
||||||
|
data-index={row.index}
|
||||||
|
aria-selected={row.index === selectedIndex}
|
||||||
|
>
|
||||||
|
<span class={styles.type}>
|
||||||
|
{TYPE_LABELS[row.entry!.type] ?? row.entry!.type}
|
||||||
|
</span>
|
||||||
|
<span class={styles.label}>{row.entry!.label}</span>
|
||||||
|
<span class={styles.path}>{row.entry!.path}</span>
|
||||||
|
<span class={styles.arrow}>→</span>
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
{resultCount === 0 && (
|
||||||
|
<div class={styles.empty}>No results found</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class={styles.footer}>
|
||||||
|
<div class={styles.group}>
|
||||||
|
<span>
|
||||||
|
<kbd>↑</kbd>
|
||||||
|
<kbd>↓</kbd> navigate
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<kbd>↵</kbd> open
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
<kbd>esc</kbd> close
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
129
src/components/layout/MastHead.astro
Normal file
129
src/components/layout/MastHead.astro
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
---
|
||||||
|
import CommandPalette from "./CMDPalette"
|
||||||
|
---
|
||||||
|
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="inner">
|
||||||
|
<a href="/" class="link">
|
||||||
|
<span class="site-logo">◬</span>
|
||||||
|
<span class="site-name">
|
||||||
|
dave
|
||||||
|
<span class="bracket">[</span>
|
||||||
|
dmg
|
||||||
|
<span class="bracket">]</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<CommandPalette client:load />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.site-header {
|
||||||
|
@mixin py var(--el-masthead-paddingY);
|
||||||
|
|
||||||
|
position: sticky;
|
||||||
|
z-index: 9;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
|
||||||
|
background-color: var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
@mixin layout-wrapper;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--ui-spacing-cozy);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
font-size: var(--el-masthead-font-size);
|
||||||
|
line-height: var(--el-masthead-line-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-logo {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
animation:
|
||||||
|
logo-pulse 5s cubic-bezier(0.4, 0, 0.6, 1) infinite,
|
||||||
|
logo-glitch 13s step-end infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-name {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bracket {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logo-pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
opacity: 0.66;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.33;
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
opacity: 0.66;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logo-glitch {
|
||||||
|
0%,
|
||||||
|
84% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
filter: brightness(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
85% {
|
||||||
|
transform: translate(-2px, 0);
|
||||||
|
filter: brightness(0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
86% {
|
||||||
|
transform: translate(1px, -1px);
|
||||||
|
filter: brightness(0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
87% {
|
||||||
|
transform: translate(-1px, 1px);
|
||||||
|
filter: brightness(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
88% {
|
||||||
|
transform: translate(2px, 0);
|
||||||
|
filter: brightness(0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
89% {
|
||||||
|
transform: translate(-2px, 1px);
|
||||||
|
filter: brightness(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
90% {
|
||||||
|
transform: translate(0, -1px);
|
||||||
|
filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
91%,
|
||||||
|
100% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
filter: brightness(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
75
src/components/layout/PostHeader/Cover.astro
Normal file
75
src/components/layout/PostHeader/Cover.astro
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
interface Props {
|
||||||
|
src: string;
|
||||||
|
alt: string;
|
||||||
|
caption?: string;
|
||||||
|
}
|
||||||
|
const { src, alt, caption } = Astro.props;
|
||||||
|
|
||||||
|
const images = import.meta.glob<{ default: ImageMetadata }>(
|
||||||
|
'/src/content/**/cover/*.{png,jpg,jpeg,webp,avif}',
|
||||||
|
{ eager: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const imagePath = `/src${src}`;
|
||||||
|
const image = images[imagePath]?.default;
|
||||||
|
---
|
||||||
|
|
||||||
|
<figure class="cover">
|
||||||
|
{
|
||||||
|
image ? (
|
||||||
|
<Image
|
||||||
|
class="image"
|
||||||
|
src={image}
|
||||||
|
alt={alt}
|
||||||
|
widths={[600, 900, 1280, 1440, 1600, 1920]}
|
||||||
|
sizes="100vw"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<img class="image" src={src} alt={alt} loading="lazy" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<figcaption class="caption">
|
||||||
|
<div class="wrapper">
|
||||||
|
{
|
||||||
|
caption ? (
|
||||||
|
<span class="caption-text">{caption}</span>
|
||||||
|
) : (
|
||||||
|
<span class="caption-meta">{src}</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cover {
|
||||||
|
@mixin border-t 12px, solid, var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 60vw;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
padding: var(--spacing-snug);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
background-color: var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
font-size: var(font-size-responsive);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption-text,
|
||||||
|
.caption-meta {
|
||||||
|
font-size: var(--typo-size-sm);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
78
src/components/layout/PostHeader/Meta.astro
Normal file
78
src/components/layout/PostHeader/Meta.astro
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
tags: string[];
|
||||||
|
updateDate?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tags, updateDate } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="meta">
|
||||||
|
<div class="section">
|
||||||
|
<span class="label"> Author </span>
|
||||||
|
<span class="author item">Dave Damage</span>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
tags && tags.length > 0 && (
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Tags</span>
|
||||||
|
<ul class="taglist">
|
||||||
|
{tags.map((tag) => (
|
||||||
|
<li class="tag item">{tag}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
updateDate && (
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Last Update</span>
|
||||||
|
<time class="updatedate item">{updateDate}</time>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.meta {
|
||||||
|
@mixin layout-wrapper;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: var(--spacing-relaxed);
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
min-width: 12ch;
|
||||||
|
@mixin py var(--spacing-snug);
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
@mixin mb var(--spacing-tight);
|
||||||
|
@mixin pb var(--spacing-tight);
|
||||||
|
@mixin border-b 2px, solid, var(--color-border-strong);
|
||||||
|
display: block;
|
||||||
|
font-size: var(--typo-size-xs);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: var(--typo-spacing-comfortable);
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.taglist {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--spacing-tight);
|
||||||
|
}
|
||||||
|
.tag {
|
||||||
|
@mixin py var(--spacing-tight);
|
||||||
|
@mixin px var(--spacing-snug);
|
||||||
|
border: 4px solid var(--color-palette-charcoal-gray);
|
||||||
|
letter-spacing: var(--typo-spacing-relaxed);
|
||||||
|
background: var(--color-palette-charcoal-gray);
|
||||||
|
color: var(--color-palette-off-white);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
68
src/components/layout/PostHeader/Overline.astro
Normal file
68
src/components/layout/PostHeader/Overline.astro
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
import type { BreadcrumbSegment } from '@lib/types/content';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
breadcrumbs: BreadcrumbSegment[];
|
||||||
|
publicationDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { breadcrumbs, publicationDate } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="overline">
|
||||||
|
<div class="wrapper">
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumbs">
|
||||||
|
<li class="crumb">
|
||||||
|
<a href="/" class="link">dave-dmg.de</a>
|
||||||
|
</li>
|
||||||
|
{
|
||||||
|
breadcrumbs.map((crumb) => (
|
||||||
|
<li class="crumb">
|
||||||
|
<span class="separator">/</span>
|
||||||
|
<a href={crumb.href} class="link">
|
||||||
|
{crumb.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
<time class="publicationdate">
|
||||||
|
⟫ {publicationDate}
|
||||||
|
</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overline {
|
||||||
|
background-color: var(--color-surface-inverse);
|
||||||
|
}
|
||||||
|
.wrapper {
|
||||||
|
@mixin layout-wrapper;
|
||||||
|
padding-block: var(--spacing-snug);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: var(--typo-size-responsive);
|
||||||
|
}
|
||||||
|
.breadcrumbs {
|
||||||
|
display: flex;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--typo-size-sm);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
}
|
||||||
|
.link {
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
transition: color 0.5s ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-tertiary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.publicationdate {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: var(--typo-size-xs);
|
||||||
|
font-weight: var(--typo-weight-bold);
|
||||||
|
color: var(--color-text-inverse);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
38
src/components/layout/PostHeader/Title.astro
Normal file
38
src/components/layout/PostHeader/Title.astro
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
subtitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title, subtitle } = Astro.props;
|
||||||
|
|
||||||
|
console.log(subtitle);
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<h1 class="title">{title}</h1>
|
||||||
|
{subtitle && <p class="subtitle">{subtitle}</p>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
@mixin layout-wrapper;
|
||||||
|
@mixin py var(--spacing-relaxed);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: var(--el-h1-color);
|
||||||
|
font-family: var(--el-h1-font-family);
|
||||||
|
font-size: var(--el-h1-font-size);
|
||||||
|
line-height: var(--typo-leading-tight);
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
@mixin mt var(--spacing-snug);
|
||||||
|
font-family: var(--font-header);
|
||||||
|
font-size: var(--typo-size-lg);
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: 0.075em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
46
src/components/layout/PostHeader/index.astro
Normal file
46
src/components/layout/PostHeader/index.astro
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
import type { BreadcrumbSegment } from '@lib/types/content';
|
||||||
|
import Overline from './Overline.astro';
|
||||||
|
import Title from './Title.astro';
|
||||||
|
import Meta from './Meta.astro';
|
||||||
|
import Cover from './Cover.astro';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
cover?: {
|
||||||
|
src: string;
|
||||||
|
alt: string;
|
||||||
|
caption: string;
|
||||||
|
showInHeader: boolean;
|
||||||
|
};
|
||||||
|
subtitle?: string;
|
||||||
|
tags: string[];
|
||||||
|
publishDate: string;
|
||||||
|
updateDate?: string;
|
||||||
|
breadcrumbs: BreadcrumbSegment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title, cover, subtitle, tags, publishDate, updateDate, breadcrumbs } =
|
||||||
|
Astro.props;
|
||||||
|
const showCover = cover?.src && cover?.showInHeader;
|
||||||
|
|
||||||
|
console.log(Astro.props);
|
||||||
|
---
|
||||||
|
|
||||||
|
<header class="wrapper">
|
||||||
|
<Overline breadcrumbs={breadcrumbs} publicationDate={publishDate} />
|
||||||
|
<Title title={title} subtitle={subtitle} />
|
||||||
|
{
|
||||||
|
showCover && (
|
||||||
|
<Cover alt={cover.alt} src={cover.src} caption={cover?.caption} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<Meta tags={tags} updateDate={updateDate} />
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
@mixin border-b 8px, solid, var(--color-border-strong);
|
||||||
|
background-color: var(--color-surface-base);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
src/content/articles/alchemical-materialism/cover/src.png
Normal file
BIN
src/content/articles/alchemical-materialism/cover/src.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 155 KiB |
309
src/content/articles/alchemical-materialism/index.mdoc
Normal file
309
src/content/articles/alchemical-materialism/index.mdoc
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
---
|
||||||
|
title: Alchemical Materialism
|
||||||
|
subtitle: A Systematic Framework for Worldbuilding Through Elemental Combination
|
||||||
|
summary: A Systematic Framework for Worldbuilding Through Elemental Combination
|
||||||
|
cover:
|
||||||
|
src: /content/articles/alchemical-materialism/cover/src.png
|
||||||
|
alt: Man approach a volcano
|
||||||
|
caption: The Eshian God-Alchemists claimed this was the face of Monad
|
||||||
|
showInHeader: true
|
||||||
|
publishDate: 2026-02-20T11:17:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: framework
|
||||||
|
tags:
|
||||||
|
- Was ist Was?
|
||||||
|
- Framework
|
||||||
|
- Worldbuilding
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
- **Foundational system** of the crucible
|
||||||
|
- Generates **entities** – cultures, religions, states, vessels, magical traditions – through **systematic elemental combination,** not arbitrary assignment
|
||||||
|
- Two interlocking element sets
|
||||||
|
- **Three Primes =>** Soul, Body, Spirit; dynamic forces in tension
|
||||||
|
- **Five Essences =>** Earth, Fire, Water, Air, Aether; multivalent elemental character
|
||||||
|
- **Elemental Pool Mechanic =>** add tokens from material conditions and history, tally, spend on capabilities, traits, and relationships
|
||||||
|
- **One Engine =>** elemental pool drives everything; capabilities, identity, and cultural character all flow from the same source
|
||||||
|
|
||||||
|
## The Three Primes
|
||||||
|
|
||||||
|
- *Dynamic Forces in Tension* within each entity
|
||||||
|
- Correspond to the three alchemical principles observed when substance is placed in the crucible:
|
||||||
|
- Something **burns** (Sulfur)
|
||||||
|
- Something **remains** (Salt)
|
||||||
|
- Something **transforms** (Mercury)
|
||||||
|
- Each entity contains all three; dominance determines character.
|
||||||
|
- Material conditions determine which Prime dominates; not cultural preference or collective personality
|
||||||
|
- **Interdependence:**
|
||||||
|
- Without **Soul,** nothing starts; structure sits inert, nothing transforms
|
||||||
|
- Without **Body,** nothing holds; fire has no fuel, transforming has no material
|
||||||
|
- Without **Spirit,** nothing changes; fire burns the same thing forever, structure never adapts
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Prime
|
||||||
|
- Glyph
|
||||||
|
- Alchemical
|
||||||
|
- Core
|
||||||
|
- Keyword
|
||||||
|
- Organization
|
||||||
|
- Failure
|
||||||
|
---
|
||||||
|
- [Body](/the-crucible/references/elements/body)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="body"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Salt
|
||||||
|
- Structure; the form
|
||||||
|
- »It endures«
|
||||||
|
- Institutional strength
|
||||||
|
- Calcifies everything
|
||||||
|
---
|
||||||
|
- [Soul](/the-crucible/references/elements/soul)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="soul"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Sulfur
|
||||||
|
- Agency; the Spark
|
||||||
|
- »I burn«
|
||||||
|
- Individual excellence
|
||||||
|
- Consumes everything
|
||||||
|
---
|
||||||
|
- [Spirit](/the-crucible/references/elements/spirit)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="spirit"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Mercury
|
||||||
|
- Transformation; the flux
|
||||||
|
- »Nothing stays«
|
||||||
|
- Adaptive innovation
|
||||||
|
- Dissolves everything
|
||||||
|
{% /table %}
|
||||||
|
|
||||||
|
## The Five Essences
|
||||||
|
|
||||||
|
- Describe the **material character** of an entity
|
||||||
|
- Operates on two tiers simultaneously
|
||||||
|
- **Character =>** Material expression; how the essence manifests across any domain of society
|
||||||
|
- **Symbolic =>** Thematic resonance; enriches religion, mythology, cultural flavour
|
||||||
|
- Each essence has a **primary capability affinity** and two **secondary affinities;** connecting them to the five universal capability tracks
|
||||||
|
- Essences are multivalent → it can express across multiple domains but it has a home
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Essence
|
||||||
|
- Symbol
|
||||||
|
- Properties
|
||||||
|
- IS
|
||||||
|
- Image
|
||||||
|
---
|
||||||
|
- [Aether](/the-crucible/references/elements/aether)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="aether"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Quintessence
|
||||||
|
- Transcendent, ordered, numinous
|
||||||
|
- The Stars
|
||||||
|
---
|
||||||
|
- [Air](/the-crucible/references/elements/air)
|
||||||
|
- {% ElementSymbol element="air" size="var(--typo-size-2xl)" color="inherit" /%}
|
||||||
|
- Hot & Wet
|
||||||
|
- Invisible, expansive, permeating
|
||||||
|
- The Storm
|
||||||
|
---
|
||||||
|
- [Earth](/the-crucible/references/elements/earth)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="earth"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Cold & Dry
|
||||||
|
- Heavy, material, foundational
|
||||||
|
- The Mountain
|
||||||
|
---
|
||||||
|
- [Fire](/the-crucible/references/elements/fire)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="fire"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Hot & Dry
|
||||||
|
- Bright, consuming, refining
|
||||||
|
- The Volcano
|
||||||
|
---
|
||||||
|
- [Water](/the-crucible/references/elements/water)
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="water"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Cold & Wet
|
||||||
|
- Flowing, deep, dissolving
|
||||||
|
- The River
|
||||||
|
{% /table %}
|
||||||
|
|
||||||
|
### The Five Capability Tracks
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Domain
|
||||||
|
- Covers
|
||||||
|
---
|
||||||
|
- **Prosperity**
|
||||||
|
- Labor, production, construction, infrastructure
|
||||||
|
---
|
||||||
|
- **Warfare**
|
||||||
|
- Armies, defense, fortifications, armaments
|
||||||
|
---
|
||||||
|
- **Statecraft**
|
||||||
|
- Governance, administration, law, diplomacy
|
||||||
|
---
|
||||||
|
- **Lore**
|
||||||
|
- Knowledge, education, medicine, philosophy, sciences
|
||||||
|
---
|
||||||
|
- **Rites**
|
||||||
|
- Religion, ritual, sacred practice, arcane arts, cosmology
|
||||||
|
{% /table %}
|
||||||
|
|
||||||
|
#### Essence-to-Capability Affinity
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Essence
|
||||||
|
- Primary
|
||||||
|
- Secondary 1
|
||||||
|
- Secondary 2
|
||||||
|
---
|
||||||
|
- **Aether**
|
||||||
|
- Rites
|
||||||
|
- Statecraft
|
||||||
|
- Lore
|
||||||
|
---
|
||||||
|
- **Air**
|
||||||
|
- Lore
|
||||||
|
- Prosperity
|
||||||
|
- Warfare
|
||||||
|
---
|
||||||
|
- **Earth**
|
||||||
|
- Prosperity
|
||||||
|
- Warfare
|
||||||
|
- Rites
|
||||||
|
---
|
||||||
|
- **Fire**
|
||||||
|
- Warfare
|
||||||
|
- Lore
|
||||||
|
- Statecraft
|
||||||
|
---
|
||||||
|
- **Water**
|
||||||
|
- Statecraft
|
||||||
|
- Rites
|
||||||
|
- Prosperity
|
||||||
|
{% /table %}
|
||||||
|
|
||||||
|
### The Transformation Triangle
|
||||||
|
|
||||||
|
- Three elements involve Transformation → distinguished by mode
|
||||||
|
- **Fire =>** Transformation is *destructive –* purification through consumption
|
||||||
|
- **Water =>** Transformation is *gradual* – erosion, dissolution, blending
|
||||||
|
- **Spirit =>** Transformation is *synthetic* – *solve et coagula,* a new thing born from recombination
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Element
|
||||||
|
- What happens
|
||||||
|
- Process
|
||||||
|
- Image
|
||||||
|
- Reversible
|
||||||
|
---
|
||||||
|
- **Fire**
|
||||||
|
- Destroys to create
|
||||||
|
- Input consumed; new thing exists
|
||||||
|
- The Forge
|
||||||
|
- No – Ore is gone, steel remains
|
||||||
|
---
|
||||||
|
- **Water**
|
||||||
|
- Dissolves to mix
|
||||||
|
- Boundaries erode; things blend
|
||||||
|
- The Solvent
|
||||||
|
- Partially – Salt in Water is still salt-and-water
|
||||||
|
---
|
||||||
|
- **Spirit**
|
||||||
|
- Recombines to become
|
||||||
|
- Inputs loose identity; genuinely new things emerge
|
||||||
|
- The Alembic
|
||||||
|
- No – the product is neither ingredient
|
||||||
|
{% /table %}
|
||||||
|
|
||||||
|
## The Seven Aspects
|
||||||
|
|
||||||
|
- Provide additional specificity
|
||||||
|
- Corresponding to the 7 classical metals and their planetary associations
|
||||||
|
- Categorise what exists and operates within the World
|
||||||
|
|
||||||
|
{% table %}
|
||||||
|
- Aspects
|
||||||
|
- Symbol
|
||||||
|
- Metal
|
||||||
|
- Planet
|
||||||
|
- Association
|
||||||
|
---
|
||||||
|
- *Entities*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="entities"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Silver
|
||||||
|
- Moon
|
||||||
|
- Living beings; flesh, beasts, plants, spirits
|
||||||
|
---
|
||||||
|
- *Matter*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="matter"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Lead
|
||||||
|
- Saturn
|
||||||
|
- Physical substances; materials, terrain, stone, foundations
|
||||||
|
---
|
||||||
|
- *Mind*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="mind"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Quicksilver
|
||||||
|
- Mercury
|
||||||
|
- Thought, consciousness; intellect, emotion, skills
|
||||||
|
---
|
||||||
|
- *Society*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="society"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Tin
|
||||||
|
- Jupiter
|
||||||
|
- Collective organisation; governance, law, institutions
|
||||||
|
---
|
||||||
|
- *Art*
|
||||||
|
- {% ElementSymbol element="art" size="var(--typo-size-2xl)" color="inherit" /%}
|
||||||
|
- Copper
|
||||||
|
- Venus
|
||||||
|
- Creation, expression; artistry, rituals, craft
|
||||||
|
---
|
||||||
|
- *Mysteries*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="mysteries"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Gold
|
||||||
|
- Sun
|
||||||
|
- Hidden, occult; magic, destiny, secrets, *residua*
|
||||||
|
---
|
||||||
|
- *Forces*
|
||||||
|
- {% ElementSymbol
|
||||||
|
element="forces"
|
||||||
|
size="var(--typo-size-2xl)"
|
||||||
|
color="inherit" /%}
|
||||||
|
- Iron
|
||||||
|
- Mars
|
||||||
|
- Energies, natural laws; power, conflict, dynamics
|
||||||
|
{% /table %}
|
||||||
13
src/content/articles/awq/index.mdoc
Normal file
13
src/content/articles/awq/index.mdoc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: Advanced Warhammer Quest
|
||||||
|
summary: A dungeoncrawler for the last millenium!
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-27T14:39:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
13
src/content/articles/chainbreaker/index.mdoc
Normal file
13
src/content/articles/chainbreaker/index.mdoc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: Chainbreaker
|
||||||
|
summary: Last blood in a world gone mad
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-27T14:40:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
14
src/content/articles/elements/index.mdoc
Normal file
14
src/content/articles/elements/index.mdoc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Elements
|
||||||
|
summary: References for all the Elements
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T09:44:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: references
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
23
src/content/articles/framework/index.mdoc
Normal file
23
src/content/articles/framework/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: The Framework
|
||||||
|
summary: Conceptual Foundation of Crucible
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-20T11:14:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: the-crucible
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
|
- Alchemical Materialism
|
||||||
|
- The Primes
|
||||||
|
- The Essences
|
||||||
|
- Affinity
|
||||||
|
- Pool
|
||||||
|
- Design Principles
|
||||||
|
- Tiers
|
||||||
|
- Domains
|
||||||
|
- Sin Engine
|
||||||
20
src/content/articles/materia/index.mdoc
Normal file
20
src/content/articles/materia/index.mdoc
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: Materia
|
||||||
|
subtitle: The Elemental Pool
|
||||||
|
summary: Foundation of the Crucible, the elemental pool
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T23:19:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: framework
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
|
- Pool is both **identity** and **budget**
|
||||||
|
1. **Generate Materia =>** from *material conditions* (environment, subsistence, mythology, history)
|
||||||
|
1. **Read Identity =>** From a grid depending on the entity's nature (e.g. *Ethos, Theology, Polity)*
|
||||||
|
1. **Spend tokens**
|
||||||
|
- Leftover tokens are not carried over
|
||||||
17
src/content/articles/prima-materia/index.mdoc
Normal file
17
src/content/articles/prima-materia/index.mdoc
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: Prima Materia
|
||||||
|
subtitle: Where we read the earth and learn what it provides
|
||||||
|
summary: Where we read the earth and learn what it provides
|
||||||
|
cover:
|
||||||
|
showInHeader: true
|
||||||
|
publishDate: 2026-02-25T23:28:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: the-crucible
|
||||||
|
tags:
|
||||||
|
- Crucible Stage
|
||||||
|
- Generation
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
14
src/content/articles/references/index.mdoc
Normal file
14
src/content/articles/references/index.mdoc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: References
|
||||||
|
summary: Where we collect all the references
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T09:43:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: the-crucible
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
---
|
||||||
@@ -29,16 +29,16 @@ seo:
|
|||||||
|
|
||||||
## The Seven Stages
|
## The Seven Stages
|
||||||
|
|
||||||
1. **Prima Materia. – Land**
|
1. **Prima Materia. – Material Conditions**
|
||||||
- Generate biomes and resources
|
- Generates land and kin
|
||||||
1. **Calcination – Kin**
|
1. **Calcination – Kin**
|
||||||
- Generates kindred, heritage, and ancestry
|
- Generates heritage and ancestry
|
||||||
1. **Fermentation – Belief**
|
1. **Fermentation – Belief**
|
||||||
- Generates religion and belief
|
- Generates religion and faith
|
||||||
1. **Sublimation – Witchcraft**
|
1. **Sublimation – Witchcraft**
|
||||||
- Generates magical traditions and crafts
|
- Generates disciplines and crafts
|
||||||
1. **Coagulation – Vessels**
|
1. **Coagulation – Factions**
|
||||||
- Generates institutions and factions
|
- Generates vessels
|
||||||
1. **Conjunction – Realms**
|
1. **Conjunction – Realms**
|
||||||
- Generates states, tribes, and settlements
|
- Generates states, tribes, and settlements
|
||||||
1. **Dissolution**
|
1. **Dissolution**
|
||||||
|
|||||||
@@ -1,45 +1,76 @@
|
|||||||
import { defineCollection, z } from 'astro:content';
|
import { defineCollection, z } from 'astro:content';
|
||||||
|
import { glob } from 'astro/loaders';
|
||||||
|
|
||||||
|
const symbolSchema = z.discriminatedUnion('discriminant', [
|
||||||
|
z.object({
|
||||||
|
discriminant: z.literal('font'),
|
||||||
|
value: z.object({
|
||||||
|
family: z.string(),
|
||||||
|
character: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
discriminant: z.literal('svg'),
|
||||||
|
value: z.string(),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const seoSchema = z
|
||||||
|
.object({
|
||||||
|
title: z.string().optional(),
|
||||||
|
description: z.string().optional(),
|
||||||
|
noIndex: z.boolean().default(false),
|
||||||
|
})
|
||||||
|
.optional();
|
||||||
|
|
||||||
|
const coverSchema = z
|
||||||
|
.object({
|
||||||
|
src: z.string().optional(),
|
||||||
|
alt: z.string().optional(),
|
||||||
|
caption: z.string().optional(),
|
||||||
|
showInHeader: z.boolean().default(false),
|
||||||
|
})
|
||||||
|
.optional();
|
||||||
|
|
||||||
|
const baseArticleSchema = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
summary: z.string(),
|
||||||
|
subtitle: z.string().optional(),
|
||||||
|
cover: coverSchema,
|
||||||
|
publishDate: z.date(),
|
||||||
|
updateDate: z.date().optional(),
|
||||||
|
status: z.enum(['draft', 'published', 'archived']).default('draft'),
|
||||||
|
isFeatured: z.boolean().default(false),
|
||||||
|
parent: z.string().optional(),
|
||||||
|
tags: z.array(z.string()).default([]),
|
||||||
|
relatedArticles: z.array(z.string()).default([]),
|
||||||
|
seo: seoSchema,
|
||||||
|
});
|
||||||
|
|
||||||
const articles = defineCollection({
|
const articles = defineCollection({
|
||||||
schema: z.object({
|
loader: glob({
|
||||||
title: z.string(),
|
pattern: '**/index.mdoc',
|
||||||
summary: z.string(),
|
base: './src/content/articles',
|
||||||
cover: z
|
|
||||||
.object({
|
|
||||||
src: z.string().optional(),
|
|
||||||
alt: z.string().optional(),
|
|
||||||
caption: z.string().optional(),
|
|
||||||
showInHeader: z.boolean().default(false),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
publishDate: z.date(),
|
|
||||||
updateDate: z.date().optional(),
|
|
||||||
status: z.enum(['draft', 'published', 'archived']).default('draft'),
|
|
||||||
isFeatured: z.boolean().default(false),
|
|
||||||
parent: z.string().optional(),
|
|
||||||
tags: z.array(z.string()).default([]),
|
|
||||||
relatedArticles: z.array(z.string()).default([]),
|
|
||||||
seo: z
|
|
||||||
.object({
|
|
||||||
title: z.string().optional(),
|
|
||||||
description: z.string().optional(),
|
|
||||||
noIndex: z.boolean().default(false),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
}),
|
}),
|
||||||
|
schema: baseArticleSchema,
|
||||||
});
|
});
|
||||||
|
|
||||||
const pages = defineCollection({
|
const pages = defineCollection({
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
seo: z
|
seo: seoSchema,
|
||||||
.object({
|
|
||||||
title: z.string().optional(),
|
|
||||||
description: z.string().optional(),
|
|
||||||
noIndex: z.boolean().default(false),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collections = { articles, pages };
|
const elements = defineCollection({
|
||||||
|
loader: glob({
|
||||||
|
pattern: '**/index.mdoc',
|
||||||
|
base: './src/content/crucible/elements',
|
||||||
|
}),
|
||||||
|
schema: baseArticleSchema.extend({
|
||||||
|
category: z.enum(['prime', 'essence', 'aspect']).default('prime'),
|
||||||
|
symbol: symbolSchema,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = { articles, pages, elements };
|
||||||
|
|||||||
52
src/content/crucible/elements/aether/index.mdoc
Normal file
52
src/content/crucible/elements/aether/index.mdoc
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
title: Aether
|
||||||
|
subtitle: The Transcendent, The Ordered, The Numinous
|
||||||
|
summary: Exploring the Essence »Aether« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T13:02:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Essences
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: essence
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: D
|
||||||
|
---
|
||||||
|
- **Alchemical Properties =>** the fifth element; beyond the four mundane; celestial, incorruptible
|
||||||
|
- **Primary Affinity =>** Rites
|
||||||
|
- **Associations**
|
||||||
|
- What lies beyond the material; the fifth thing
|
||||||
|
- Cosmic order → the pattern behind apparent chaos
|
||||||
|
- The numinous → the experience of something greater
|
||||||
|
- The bridge between mortal and divine; threshold substance
|
||||||
|
- Meaning itself; the answer to »why does this matter?«
|
||||||
|
- **Material Character**
|
||||||
|
- *Rites =>* Priesthoods, temples, divine mandate; fate, destiny, the inescapable
|
||||||
|
- *Statecraft =>* Divine legitimacy, sacred law, oaths before gods, hierarchy sanctified from above
|
||||||
|
- *Lore =>* Revelation, prophecy, mystical insight; knowledge from beyond; mystery traditions
|
||||||
|
- *Warfare =>* Holy war, divine champions, sacred weapons; morale & terror; the fear of the supernatural
|
||||||
|
- *Prosperity =>* Sacred crafts, ritual objects; things made for purposes beyond the materials;
|
||||||
|
- **Symbolic**
|
||||||
|
- Transcendence
|
||||||
|
- Order
|
||||||
|
- Mystery
|
||||||
|
- Meaning
|
||||||
|
- The Sacred
|
||||||
|
- What make mundane things matter
|
||||||
|
- The pattern behind the noise
|
||||||
|
- Incorruptible and therefore terrifying
|
||||||
|
- The divine gaze
|
||||||
|
- **Failures**
|
||||||
|
- Disconnection from reality
|
||||||
|
- Cosmic order that crushes mortal will
|
||||||
|
- Meaning so heavy it makes life unbearable
|
||||||
|
- Madness from contact with the transcendent
|
||||||
|
- **Key Image =>** the Stars
|
||||||
50
src/content/crucible/elements/air/index.mdoc
Normal file
50
src/content/crucible/elements/air/index.mdoc
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: Air
|
||||||
|
subtitle: The Invisible, The Expansive, The Permeating
|
||||||
|
summary: Exploring the Prime »Air« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T13:01:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Essences
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: essence
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: H
|
||||||
|
---
|
||||||
|
- **Alchemical Properties =>** Hot & Wet; ascending, expanding, permeating
|
||||||
|
- **Primary Affinity =>** Lore
|
||||||
|
- **Associations**
|
||||||
|
- The invisible medium; what fills all space
|
||||||
|
- Breath literally, life itself; pneuma
|
||||||
|
- Movement, speed, freedom; what cannot be grasped
|
||||||
|
- The space between things; the medium of sound and speech
|
||||||
|
- Expansion without limit; the storm that scatters
|
||||||
|
- **Material Character**
|
||||||
|
- *Lore →* Speech, rhetoric, philosophy, abstract thought; pneuma as intellect; the word as power
|
||||||
|
- *Statecraft →* Communication, rumour, reputation on the wind; freedom from obligation: the ungovernable
|
||||||
|
- *Warfare →* Cavalry, archery, speed & mobility; hit-&-run; the charge; storms as divine wrath
|
||||||
|
- *Prosperity →* Windmills, sailing, ventilation of mines; the medium through which trade moves
|
||||||
|
- *Rites →* Sky-gods, storm deities, breath-of-life; divine voice; oracles; the heavens
|
||||||
|
- **Symbolic**
|
||||||
|
- Freedom
|
||||||
|
- Invisibility
|
||||||
|
- Speed
|
||||||
|
- Communication
|
||||||
|
- Expansion
|
||||||
|
- **Failures**
|
||||||
|
- Scattering
|
||||||
|
- Nothing holds
|
||||||
|
- All form dispersed
|
||||||
|
- Rootlessness
|
||||||
|
- The storm that destroys all structure
|
||||||
|
- Empty air → nothing there at all
|
||||||
|
- **Key Image =>** the Storm
|
||||||
23
src/content/crucible/elements/art/index.mdoc
Normal file
23
src/content/crucible/elements/art/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Art
|
||||||
|
summary: Exploring the Aspect »Art« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:56:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: F
|
||||||
|
---
|
||||||
|
- **Planet =>** Venus
|
||||||
|
- **Metal =>** Copper
|
||||||
|
- Creation, expression; artistry, rituals, craft
|
||||||
49
src/content/crucible/elements/body/index.mdoc
Normal file
49
src/content/crucible/elements/body/index.mdoc
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
title: Body
|
||||||
|
summary: Exploring the Prime »Body« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
alt: Salt – »What remains«
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T12:27:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Primes
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: prime
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: M
|
||||||
|
---
|
||||||
|
- **Alchemical principle =>** the fixed residue; what's left after burning; the stable principle
|
||||||
|
- **Core =>** Structure; form; persistence; what endures
|
||||||
|
- **Keyword =>** »It endures«
|
||||||
|
- **Principles**
|
||||||
|
- The principle of **structural persistence;** the substrate
|
||||||
|
- The institution that outlives its founders; the tradition that continues because it continues
|
||||||
|
- *Body* doesn't drive action: it's what's already there when action occurs
|
||||||
|
- Soul ignites, spirit transforms, Body is the **medium and the resistance**
|
||||||
|
- **Organisational expressions:** Institutional production: organised labor, standardised input, persistent infrastructure
|
||||||
|
- **Expressions**
|
||||||
|
- The bureaucracy processing forms centuries after anyone remembers why
|
||||||
|
- The kinship system determining marriage partners before birth
|
||||||
|
- The city walls that still stand
|
||||||
|
- The language that shapes though before you think
|
||||||
|
- The caste that tells you who you are before you are born
|
||||||
|
- The road network that dictates where trade flows
|
||||||
|
- **Failures**
|
||||||
|
- Calcification
|
||||||
|
- Rigidity
|
||||||
|
- the structure that cannot bend and therefore breaks
|
||||||
|
- the dead institution
|
||||||
|
- Tradition that crushes all life from what it holds
|
||||||
|
- **Quality**
|
||||||
|
- Fixed
|
||||||
|
- Crystalline
|
||||||
|
- Enduring
|
||||||
|
- Structural
|
||||||
50
src/content/crucible/elements/earth/index.mdoc
Normal file
50
src/content/crucible/elements/earth/index.mdoc
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: Earth
|
||||||
|
summary: Exploring the Prime »Earth« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
alt: The Material, The Heavy, The Foundation
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T12:56:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Essences
|
||||||
|
relatedArticles:
|
||||||
|
- alchemical-materialism
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: essence
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: X
|
||||||
|
---
|
||||||
|
- **Alchemical Properties =>** Cold & Dry; descending, condensing, solidifying
|
||||||
|
- **Primary affinity =>** Prosperity
|
||||||
|
- **Associations**
|
||||||
|
- Weight, density, solidity; the things that's *there*
|
||||||
|
- The ground beneath; territory, boundary, the physical
|
||||||
|
- Resistance to movement; inertia; mass
|
||||||
|
- The body itself: flesh, bone, muscle
|
||||||
|
- What can be held, measured, counted, divided
|
||||||
|
- **Material Character**
|
||||||
|
- *Prosperity →* Extraction, agriculture, physical labour; working the land; masonry, road-building
|
||||||
|
- *Warfare →* Heavy infantry, siege, fortification; holding ground; crushing weight
|
||||||
|
- *Statecraft →* Territorial administration; »this is MY land«;
|
||||||
|
- *Lore →* Practical craft, material science; knowing by doing and touching
|
||||||
|
- *Rites →* Sacred ground, burial rites, fertility rituals; the body as sacred; chthonic power
|
||||||
|
- **Symbolic**
|
||||||
|
- Rootedness
|
||||||
|
- Stubbornness
|
||||||
|
- Endurance
|
||||||
|
- Possession
|
||||||
|
- Gravity
|
||||||
|
- The foundational
|
||||||
|
- **Failures**
|
||||||
|
- Immoveable
|
||||||
|
- Crushing
|
||||||
|
- Suffocating
|
||||||
|
- The weight that buries
|
||||||
|
- **Key Image:** the Mountain
|
||||||
23
src/content/crucible/elements/entities/index.mdoc
Normal file
23
src/content/crucible/elements/entities/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Entities
|
||||||
|
summary: Exploring the Aspect »Entities« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:42:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: O
|
||||||
|
---
|
||||||
|
- **Metal =>** Silver
|
||||||
|
- **Planet =>** Moon
|
||||||
|
- Living beings; flesh, beasts, plants, spirits
|
||||||
47
src/content/crucible/elements/fire/index.mdoc
Normal file
47
src/content/crucible/elements/fire/index.mdoc
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
title: Fire
|
||||||
|
subtitle: The Bright, The Consuming, The Refining
|
||||||
|
summary: Exploring the Prime »Fire« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T12:58:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Essences
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: essence
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: C
|
||||||
|
---
|
||||||
|
- **Alchemical Properties =>** Hot & Dry; ascending, illuminating, consuming
|
||||||
|
- **Primary affinity =>** Warfare
|
||||||
|
- **Associations**
|
||||||
|
- Light that reveals; heat that transforms
|
||||||
|
- Consumption → Fire needs fuel and destroys what it burns
|
||||||
|
- The Forge → Destruction that creates something better
|
||||||
|
- Illuminations and blindness simultaneously
|
||||||
|
- Purification through burning away impurity
|
||||||
|
- **Material Character**
|
||||||
|
- *Warfare →* scorched earth, purges, burning the heretic; destroying to cleanse; Greek Fire; purification through destruction
|
||||||
|
- *Prosperity →* the forge, the kiln; smelting, glasswork, ceramics; refining the raw into finished
|
||||||
|
- *Statecraft →* passionate bonds, burning loyalty; consuming rivalries; bonds that burn bright and burn out
|
||||||
|
- *Lore →* revelation, illumination, mastery; orthodoxy as the »one true light«
|
||||||
|
- *Rites →* sacred flames, purification rites, trial by fire; burnt offerings; the sun as god
|
||||||
|
- **Symbolic**
|
||||||
|
- Brilliance
|
||||||
|
- Hunger
|
||||||
|
- Purification
|
||||||
|
- Consumption
|
||||||
|
- the hearth that warms AND the wildfire that destroys
|
||||||
|
- **Failures**
|
||||||
|
- Consumes all fuel
|
||||||
|
- Scorches what it meant to warm
|
||||||
|
- Purification that leaves nothing alive
|
||||||
|
- **Key Image:** the Forge
|
||||||
23
src/content/crucible/elements/forces/index.mdoc
Normal file
23
src/content/crucible/elements/forces/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Forces
|
||||||
|
summary: Exploring the Aspect »Forces« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T22:01:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: B
|
||||||
|
---
|
||||||
|
- **Planet =>** Mars
|
||||||
|
- **Metal =>** Iron
|
||||||
|
- Energies, natural laws; power, conflict, dynamics
|
||||||
23
src/content/crucible/elements/matter/index.mdoc
Normal file
23
src/content/crucible/elements/matter/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Matter
|
||||||
|
summary: Exploring the Aspect »Matter« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:49:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: S
|
||||||
|
---
|
||||||
|
- **Metal =>** Lead
|
||||||
|
- **Planet =>** Saturn
|
||||||
|
- Physical substances; materials, terrain, stone, foundations
|
||||||
23
src/content/crucible/elements/mind/index.mdoc
Normal file
23
src/content/crucible/elements/mind/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Mind
|
||||||
|
summary: Exploring the Aspect »Mind« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:51:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: I
|
||||||
|
---
|
||||||
|
- **Metal =>** Quicksilver
|
||||||
|
- **Planet =>** Mercury
|
||||||
|
- Thought, consciousness; intellect, emotion, skills
|
||||||
23
src/content/crucible/elements/mysteries/index.mdoc
Normal file
23
src/content/crucible/elements/mysteries/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Mysteries
|
||||||
|
summary: Exploring the Aspect »Mysteries« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:59:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: R
|
||||||
|
---
|
||||||
|
- **Planet =>** Sun
|
||||||
|
- **Metal =>** Gold
|
||||||
|
- Hidden, occult; magic, destiny; secrets, realms beyond
|
||||||
23
src/content/crucible/elements/society/index.mdoc
Normal file
23
src/content/crucible/elements/society/index.mdoc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: Society
|
||||||
|
summary: Exploring the Aspect »Society« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-25T21:54:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags: []
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: aspect
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: L
|
||||||
|
---
|
||||||
|
- **Metal =>** Tin
|
||||||
|
- **Planet =>** Jupiter
|
||||||
|
- Collective organisation; governance, institutions, law
|
||||||
46
src/content/crucible/elements/soul/index.mdoc
Normal file
46
src/content/crucible/elements/soul/index.mdoc
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
title: Soul
|
||||||
|
summary: Exploring the Prime »Soul« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T11:26:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Primes
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: prime
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: A
|
||||||
|
---
|
||||||
|
- **Alchemical Principle =>** the combustible essence; what makes fire catch; the active principle
|
||||||
|
- **Core =>** Agency; drive; the spark that initiates action
|
||||||
|
- **Keyword =>** »I burn«
|
||||||
|
- **Principles**
|
||||||
|
- The principle of **individual agency and animation**
|
||||||
|
- Greed is one expression; so is passion, obsession, curiosity, protective fury, creative drive
|
||||||
|
- What unites Soul expressions: the fire originates in *a person,* not a structure or process
|
||||||
|
- **Organisational expression:** Individual excellence; master craftsmen, personal glory, competitive innovation
|
||||||
|
- **Expressions**
|
||||||
|
- The merchant hoarding silver
|
||||||
|
- The sculptor destroying a statue because of a imperfection only they can see
|
||||||
|
- The parent killing to protect their child
|
||||||
|
- The explorer walking into the unknown
|
||||||
|
- The warrior seeking glory
|
||||||
|
- The inventor breaking every rule
|
||||||
|
- **Failures:**
|
||||||
|
- Consumes everything
|
||||||
|
- Burns out
|
||||||
|
- Burns what it touches
|
||||||
|
- Individual drive that destroys because it cannot moderate
|
||||||
|
- **Qualities:**
|
||||||
|
- Combustible
|
||||||
|
- Animating
|
||||||
|
- Individual
|
||||||
|
- Igniting
|
||||||
57
src/content/crucible/elements/spirit/index.mdoc
Normal file
57
src/content/crucible/elements/spirit/index.mdoc
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
title: Spirit
|
||||||
|
subtitle: Mercury – What transforms
|
||||||
|
summary: Exploring the Prime »Spirit« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T12:42:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Primes
|
||||||
|
relatedArticles:
|
||||||
|
- alchemical-materialism
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: prime
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: E
|
||||||
|
---
|
||||||
|
- **Alchemical Principle =>** the volatile mediator; what escapes, dissolves, and recombines; the transformation principle
|
||||||
|
- **Core =>** Transformation, synthesis; *becoming*
|
||||||
|
- **Keyword =>** »Nothing stays, everything becomes«
|
||||||
|
- **Principles**
|
||||||
|
- The principle of **transformation as a positive force;** not mere reaction or survival
|
||||||
|
- *»Solve et coagula«* → dissolve and recombine
|
||||||
|
- Mediation, adaption, and change-as-drive are all expressions of transformation
|
||||||
|
- Mercury is the *most alchemically important* of the three → the philosopher's stone ingredient
|
||||||
|
- **Organisational Expression**
|
||||||
|
- Adaptive innovation
|
||||||
|
- Cross-pollination
|
||||||
|
- Hybrid techniques
|
||||||
|
- Syncretic methods
|
||||||
|
- **Expressions**
|
||||||
|
- Syncretic cultures absorbing and remaking what they encounter
|
||||||
|
- Trade-diaspora peoples existing between cultures; transforming both
|
||||||
|
- Revolutionary movements dissolving old structures
|
||||||
|
- Liminal societies at crossroads, borders, thresholds
|
||||||
|
- Alchemists literally
|
||||||
|
- Seasonal/cyclical peoples participating in cycles of transformation
|
||||||
|
- Mediators who create new arrangements, not just broker peace
|
||||||
|
- **Failures**
|
||||||
|
- Dissolves everything
|
||||||
|
- Nothing holds
|
||||||
|
- Identity lost
|
||||||
|
- Perpetual revolution devouring its own
|
||||||
|
- Formlessness
|
||||||
|
- Mercury slipping through every grasp
|
||||||
|
- **Quality**
|
||||||
|
- Volatile
|
||||||
|
- Liminal
|
||||||
|
- Mercurial
|
||||||
|
- Syncretic
|
||||||
|
- Transformative
|
||||||
50
src/content/crucible/elements/water/index.mdoc
Normal file
50
src/content/crucible/elements/water/index.mdoc
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: Water
|
||||||
|
subtitle: The Flowing, The Deep, The Dissolving
|
||||||
|
summary: Exploring the Essence »Water« in the Alchemical Materialism framework
|
||||||
|
cover:
|
||||||
|
showInHeader: false
|
||||||
|
publishDate: 2026-02-24T12:59:00.000Z
|
||||||
|
status: published
|
||||||
|
isFeatured: false
|
||||||
|
parent: elements
|
||||||
|
tags:
|
||||||
|
- Essences
|
||||||
|
relatedArticles: []
|
||||||
|
seo:
|
||||||
|
noIndex: false
|
||||||
|
category: essence
|
||||||
|
symbol:
|
||||||
|
discriminant: font
|
||||||
|
value:
|
||||||
|
family: Unigrim Dee
|
||||||
|
character: Q
|
||||||
|
---
|
||||||
|
- **Alchemical Properties =>** Cold & Wet; descending, flowing, dissolving
|
||||||
|
- **Primary Affinity =>** Statecraft
|
||||||
|
- **Associations**
|
||||||
|
- The universal solvent -> what dissolves boundaries
|
||||||
|
- Flow, connection → the medium of exchange
|
||||||
|
- Depth and concealment → What's hidden beneath the surface
|
||||||
|
- Life-giving AND drowning: rain AND Flood
|
||||||
|
- Takes the shape of its container; adapt to form
|
||||||
|
- **Material Character**
|
||||||
|
- *Statecraft →* Networks, exchange, reciprocity; debts that flow; diplomacy; status as current
|
||||||
|
- *Prosperity →* Irrigation, fishing, brewing, dyeing; the river as economic artery
|
||||||
|
- *Arms →* Naval power, coastal raiding, poison; erosion/attrition warfare
|
||||||
|
- *Lore →* Hidden knowledge, mysteries of the deep; intuition over analysis; the murky and the clear
|
||||||
|
- *Rites →* Baptism, sacred rivers, purification by washing; sea-gods; the abyss
|
||||||
|
- **Symbolic**
|
||||||
|
- Fluidity
|
||||||
|
- Depth
|
||||||
|
- Concealment
|
||||||
|
- Connection
|
||||||
|
- Erosion
|
||||||
|
- What flows between
|
||||||
|
- What lies beneath
|
||||||
|
- Patience that wears stone away
|
||||||
|
- **Failures**
|
||||||
|
- Drowning
|
||||||
|
- Erosion
|
||||||
|
- Formlessness
|
||||||
|
- **Key Image:** the River
|
||||||
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Bold.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Bold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-BoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-BoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-BoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBold.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraBoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraLight.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraLight.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraLightItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ExtraLightItalic.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Heavy.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Heavy.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-HeavyItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-HeavyItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-HeavyOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-HeavyOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Italic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Italic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Light.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Light.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-LightItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-LightItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-LightOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-LightOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Medium.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Medium.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-MediumItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-MediumOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-MediumOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Oblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Oblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Regular.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Regular.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBold.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-SemiBoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Thin.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-Thin.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ThinItalic.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ThinItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ThinOblique.woff2
Normal file
BIN
src/fonts/IosevkaSansMono/IosevkaSansMono-ThinOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Bold.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Bold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-BoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-BoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-BoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBold.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraBoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLight.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLight.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLightItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLightItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLightOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ExtraLightOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Heavy.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Heavy.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-HeavyItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-HeavyItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-HeavyOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-HeavyOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Italic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Italic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Light.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Light.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-LightItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-LightItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-LightOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-LightOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Medium.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Medium.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-MediumItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-MediumOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-MediumOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Oblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Oblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Regular.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Regular.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBold.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBold.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBoldItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBoldOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-SemiBoldOblique.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Thin.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-Thin.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ThinItalic.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ThinItalic.woff2
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ThinOblique.woff2
Normal file
BIN
src/fonts/IosevkaSlabQp/IosevkaSlabQp-ThinOblique.woff2
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
import { collection } from '@keystatic/core';
|
import { collection } from '@keystatic/core';
|
||||||
import { createBaseArticleFields } from '../fields/base-article.ts';
|
import { createBaseArticleFields } from '@fields/base-article.ts';
|
||||||
import { createContentField } from '../fields/content.ts';
|
import { createContentField } from '@fields/content.ts';
|
||||||
|
|
||||||
export const articles = collection({
|
export const articles = collection({
|
||||||
label: 'Articles',
|
label: 'Articles',
|
||||||
|
|||||||
66
src/keystatic/collections/crucible/elements.ts
Normal file
66
src/keystatic/collections/crucible/elements.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { collection, fields } from '@keystatic/core';
|
||||||
|
import { createBaseArticleFields } from '@fields/base-article.ts';
|
||||||
|
import { createContentField } from '@fields/content.ts';
|
||||||
|
|
||||||
|
export const elements = collection({
|
||||||
|
label: 'Elements',
|
||||||
|
slugField: 'title',
|
||||||
|
path: 'src/content/crucible/elements/*/',
|
||||||
|
columns: ['category'],
|
||||||
|
|
||||||
|
format: {
|
||||||
|
contentField: 'body',
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
...createBaseArticleFields(),
|
||||||
|
body: createContentField(),
|
||||||
|
category: fields.select({
|
||||||
|
label: 'Category',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Prime',
|
||||||
|
value: 'prime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Essence',
|
||||||
|
value: 'essence',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Aspect',
|
||||||
|
value: 'aspect',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultValue: 'prime',
|
||||||
|
}),
|
||||||
|
symbol: fields.conditional(
|
||||||
|
fields.select({
|
||||||
|
label: 'Type',
|
||||||
|
defaultValue: 'font',
|
||||||
|
options: [
|
||||||
|
{ label: 'Font', value: 'font' },
|
||||||
|
{ label: 'SVG', value: 'svg' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
svg: fields.text({
|
||||||
|
label: 'SVG Markup',
|
||||||
|
multiline: true,
|
||||||
|
}),
|
||||||
|
font: fields.object({
|
||||||
|
family: fields.select({
|
||||||
|
label: 'Font Family',
|
||||||
|
defaultValue: 'Unigrim Dee',
|
||||||
|
options: [
|
||||||
|
{ label: 'Unigrim Dee', value: 'Unigrim Dee' },
|
||||||
|
{ label: 'Unigrim Hochenheim', value: 'Unigrim Hochenheim' },
|
||||||
|
{ label: 'Unigrim Trithemius', value: 'Unigrim Trithemius' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
character: fields.text({
|
||||||
|
label: 'Character',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
7
src/keystatic/collections/crucible/index.ts
Normal file
7
src/keystatic/collections/crucible/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { elements } from './elements';
|
||||||
|
|
||||||
|
const crucibleCollections = {
|
||||||
|
cr_elements: elements,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default crucibleCollections;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { collection, fields } from '@keystatic/core';
|
import { collection, fields } from '@keystatic/core';
|
||||||
import { createSEOField } from '../fields/seo.ts';
|
import { createSEOField } from '@fields/seo.ts';
|
||||||
import { createContentField } from '../fields/content.ts';
|
import { createContentField } from '@fields/content.ts';
|
||||||
|
|
||||||
export const pages = collection({
|
export const pages = collection({
|
||||||
label: 'Pages',
|
label: 'Pages',
|
||||||
|
|||||||
50
src/keystatic/components/element.ts
Normal file
50
src/keystatic/components/element.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { componentIcon } from '@keystar/ui/icon/icons/componentIcon';
|
||||||
|
import { inline } from '@keystatic/core/content-components';
|
||||||
|
import { fields } from '@keystatic/core';
|
||||||
|
|
||||||
|
const elementCompontent = {
|
||||||
|
ElementSymbol: inline({
|
||||||
|
label: 'Element Symbol',
|
||||||
|
icon: componentIcon,
|
||||||
|
schema: {
|
||||||
|
element: fields.relationship({
|
||||||
|
label: 'Element',
|
||||||
|
collection: 'cr_elements',
|
||||||
|
}),
|
||||||
|
size: fields.select({
|
||||||
|
label: 'Size',
|
||||||
|
defaultValue: 'var(--typo-size-md)',
|
||||||
|
options: [
|
||||||
|
{ label: '2XS', value: 'var(--typo-size-2xs)' },
|
||||||
|
{ label: 'XS', value: 'var(--typo-size-xs)' },
|
||||||
|
{ label: 'SM', value: 'var(--typo-size-sm)' },
|
||||||
|
{ label: 'MD', value: 'var(--typo-size-md)' },
|
||||||
|
{ label: 'LG', value: 'var(--typo-size-lg)' },
|
||||||
|
{ label: 'XL', value: 'var(--typo-size-xl)' },
|
||||||
|
{ label: '2XL', value: 'var(--typo-size-2xl)' },
|
||||||
|
{ label: '3XL', value: 'var(--typo-size-3xl)' },
|
||||||
|
{ label: '4XL', value: 'var(--typo-size-4xl)' },
|
||||||
|
{ label: '5XL', value: 'var(--typo-size-5xl)' },
|
||||||
|
{ label: '6XL', value: 'var(--typo-size-6xl)' },
|
||||||
|
{ label: '7XL', value: 'var(--typo-size-7xl)' },
|
||||||
|
{ label: '8XL', value: 'var(--typo-size-8xl)' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
color: fields.select({
|
||||||
|
label: 'Color',
|
||||||
|
defaultValue: 'inherit',
|
||||||
|
options: [
|
||||||
|
{ label: 'Inherit', value: 'inherit' },
|
||||||
|
{ label: 'primary', value: 'var(--color-primary)' },
|
||||||
|
{ label: 'secondary', value: 'var(--color-secondary)' },
|
||||||
|
{ label: 'tertiary', value: 'var(--color-tertiary)' },
|
||||||
|
{ label: 'primary', value: 'var(--color-primary)' },
|
||||||
|
{ label: 'Text', value: 'var(--color-text-primary)' },
|
||||||
|
{ label: 'Text Inverse', value: 'var(--color-text-inverse)' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default elementCompontent;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user