First Article&Routing

This commit is contained in:
2026-02-19 15:00:22 +01:00
parent 857467409d
commit f6eb9dd7e1
8 changed files with 90 additions and 17 deletions

View File

@@ -0,0 +1,45 @@
---
title: The Crucible
summary: Generates fantasy settings through seven interconnected alchemical stages.
cover:
showInHeader: false
publishDate: 2026-02-19T14:05:00.000Z
status: published
isFeatured: false
tags: []
relatedArticles: []
seo:
description: Short Pitch comes here
noIndex: false
---
## What this is
- Generates fantasy settings through seven interconnected alchemical stages
- Start with Geography, end with states locked in political tension
- Not balanced, not optimised designed to produce contradictions and tension
## Two Paths
- **Path I: »I want to generate«**
- Start Building
- Recommended for first-time users
- Path 2: **»I want to understand«**
- Learn the System
- Recommended for designers and theorists
## The Seven Stages
1. **Prima Materia. Land**
- Generate biomes and resources
1. **Calcination Kin**
- Generates kindred, heritage, and ancestry
1. **Fermentation Belief**
- Generates religion and belief
1. **Sublimation Witchcraft**
- Generates magical traditions and crafts
1. **Coagulation Vessels**
- Generates institutions and factions
1. **Conjunction Realms**
- Generates states, tribes, and settlements
1. **Dissolution**
- Ways for the state to interact with each over

View File

@@ -12,8 +12,8 @@ const articles = defineCollection({
showInHeader: z.boolean().default(false), showInHeader: z.boolean().default(false),
}) })
.optional(), .optional(),
publishDate: z.string(), publishDate: z.date(),
updateDate: z.string().optional(), updateDate: z.date().optional(),
status: z.enum(['draft', 'published', 'archived']).default('draft'), status: z.enum(['draft', 'published', 'archived']).default('draft'),
isFeatured: z.boolean().default(false), isFeatured: z.boolean().default(false),
parent: z.string().optional(), parent: z.string().optional(),

View File

@@ -10,11 +10,12 @@ export const createBaseArticleFields = () => ({
validation: { isRequired: true }, validation: { isRequired: true },
}), }),
cover: createCoverField(), cover: createCoverField(),
publishDate: fields.date({ publishDate: fields.datetime({
label: 'Publish Date', label: 'Publish Date',
validation: { isRequired: true }, validation: { isRequired: true },
defaultValue: { kind: 'now' },
}), }),
updateDate: fields.date({ updateDate: fields.datetime({
label: 'Update Date', label: 'Update Date',
}), }),
status: fields.select({ status: fields.select({
@@ -32,11 +33,11 @@ export const createBaseArticleFields = () => ({
}), }),
parent: fields.relationship({ parent: fields.relationship({
label: 'Parent', label: 'Parent',
collection: 'Articles', collection: 'articles',
}), }),
tags: fields.array(fields.text({ label: 'Tag' }), { tags: fields.array(fields.text({ label: 'Tag' }), {
label: 'Tags', label: 'Tags',
itemLabel = (props) => props.value, itemLabel: (props) => props.value,
}), }),
relatedArticles: fields.array( relatedArticles: fields.array(
fields.relationship({ label: 'Article', collection: 'articles' }), fields.relationship({ label: 'Article', collection: 'articles' }),

View File

@@ -3,13 +3,13 @@ import { fields } from '@keystatic/core';
export const createCoverField = () => export const createCoverField = () =>
fields.object( fields.object(
{ {
src: fields.object({ src: fields.image({
label: 'Cover Image', label: 'Cover Image',
directory: 'src/content/articles', directory: 'src/content/articles',
publicPath: '/content/articles', publicPath: '/content/articles',
}), }),
alt: fields.text({ label: 'Alt Text' }), alt: fields.text({ label: 'Alt Text' }),
caption: fields.text({ label: 'Caption', multline: true }), caption: fields.text({ label: 'Caption', multiline: true }),
showInHeader: fields.checkbox({ showInHeader: fields.checkbox({
label: 'Show in header', label: 'Show in header',
defaultValue: false, defaultValue: false,

28
src/pages/[...path].astro Normal file
View File

@@ -0,0 +1,28 @@
---
import { resolveAllPaths, type ResolvedEntry } from '../lib/paths';
import type { CollectionEntry } from 'astro:content';
import ArticleLayout from '../layouts/ArticleLayout.astro';
import PageLayout from '../layouts/PageLayout.astro';
export async function getStaticPaths() {
const entries = await resolveAllPaths();
return entries.map((entry) => ({
params: { path: entry.path },
props: entry,
}));
}
const { type, entry } = Astro.props as ResolvedEntry;
const props = Astro.props as ResolvedEntry;
---
{
type === 'article' && (
<ArticleLayout entry={props.entry as CollectionEntry<'articles'>} />
)
}
{
type === 'page' && (
<PageLayout entry={props.entry as CollectionEntry<'pages'>} />
)
}

View File

@@ -3,7 +3,7 @@
margin: 0 auto; margin: 0 auto;
padding: 0 var(--spacing-comfortable); padding: 0 var(--spacing-comfortable);
font-size: var(--typo-size-responsive); font-size: var(--typo-size-responsive);
font-family: var(--font-body);
/* === Headings === */ /* === Headings === */
& h1 { & h1 {

View File

@@ -1,6 +1,5 @@
:root { :root {
/* === Heading Colors & Font Sizes === */ /* === Heading Colors & Font Sizes === */
/* These remain variables because they reference semantic tokens */
--el-h1-color: var(--color-text-primary); --el-h1-color: var(--color-text-primary);
--el-h1-font-family: var(--font-display); --el-h1-font-family: var(--font-display);
@@ -28,9 +27,9 @@
/* === Heading Vertical Spacing === */ /* === Heading Vertical Spacing === */
--el-h1-vspace-base: calc(1em * 1.125); --el-h1-vspace-base: calc(1em * 1.125);
--el-h1-vspace-top: calc(var(--el-h1-vspace-base) * var(--vspace-spacious)); --el-h1-vspace-top: calc(var(--el-h1-vspace-base) * var(--vspace-snug));
--el-h1-vspace-bottom: calc( --el-h1-vspace-bottom: calc(
var(--el-h1-vspace-base) * var(--vspace-comfortable) var(--el-h1-vspace-base) * var(--vspace-compressed)
); );
--el-h2-vspace-base: calc(1em * 1.1765); --el-h2-vspace-base: calc(1em * 1.1765);

View File

@@ -1,10 +1,10 @@
:root { :root {
/* === Font Families === */ /* === Font Families === */
--font-header: var(--font-geist-sans); --font-header: 'Geist Variable';
--font-display: var(--font-blaka); --font-display: 'Blaka';
--font-body: var(--font-geist-mono); --font-body: 'Geist Mono Variable';
--font-mono: var(--font-geist-mono); --font-mono: 'Geist Mono Variable';
--font-symbols: var(); --font-symbols: 'Unigrim Dee';
/* === Type Scale === */ /* === Type Scale === */
--typo-size-responsive: clamp(1rem, 2.5vw, 1.25rem); --typo-size-responsive: clamp(1rem, 2.5vw, 1.25rem);