Schema-Markup-Mechanismus für templated Sites (custom Sites bleiben unberührt).
- templates/base.html: {{schema_jsonld}} Slot im <head>.
- site.yaml: optionaler `schema:` Block. `type:` -> `@type`, `@context`
wird automatisch ergänzt. Fehlt der Block, bleibt der Slot leer.
- render.sh: liest schema via `yq -o=json`, transformiert mit jq, fügt
Template-Default für `type` ein (person-* -> Person, product-* -> Product,
editorial -> Article).
- render.sh: literal-string replace (lreplace) statt awk gsub für multiline-
Substitution. Behebt nebenbei einen latenten Bug, bei dem `©` im
template_body als `{{body}}copy;` corrupted wurde (gsub interpretierte
`&` als matched text).
- tests/schema-test.sh + 4 Fixtures: validiert explicit type, Template-
Defaults für 3 Templates, leerer Slot ohne schema-Block.
- README.md: Schema.org-Konvention dokumentiert (Block-Format, Defaults,
Custom-Sites-Hinweis, Schema.org-Validator-Link).
QA: ./build.sh -> 59 sites OK, custom Sites byte-identical zur Source,
3 templated Fixtures rendern valides JSON-LD (Person/Product/Article),
no-schema-Fixture produziert keinen <script>-Tag.
Closes #9 nicht - head reviewed + merged.
134 lines
3.9 KiB
Markdown
134 lines
3.9 KiB
Markdown
# onepager
|
|
|
|
Mono-repo for 40+ vanity domain onepager sites. Single nginx container with template system and server_name-based routing.
|
|
|
|
## Structure
|
|
|
|
```
|
|
sites/ # One folder per domain
|
|
example.de/
|
|
site.yaml # Domain config, template choice, variables
|
|
index.html # Content (generated or hand-crafted)
|
|
assets/ # Optional images, fonts
|
|
templates/ # Shared HTML templates
|
|
shared/css/ # Shared CSS (variables, responsive, animations)
|
|
nginx/ # Generated nginx.conf + generator script
|
|
build/ # Generated output (gitignored)
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Add a new site
|
|
|
|
```bash
|
|
# Templated site
|
|
./add-site.sh example.de --template person-dark --name "Max Mustermann"
|
|
|
|
# Custom HTML site
|
|
./add-site.sh example.de --template custom
|
|
```
|
|
|
|
### Build
|
|
|
|
```bash
|
|
./build.sh
|
|
```
|
|
|
|
Requires `yq` for YAML parsing. Outputs to `build/` directory.
|
|
|
|
### Deploy
|
|
|
|
Push to main — Dokploy auto-deploys. All domains must be configured in Dokploy.
|
|
|
|
## Templates
|
|
|
|
| Template | Description |
|
|
|----------|-------------|
|
|
| `person-dark` | Professional profile, dark theme |
|
|
| `person-light` | Professional profile, light/cream theme |
|
|
| `product-dark` | Product/service landing page, dark |
|
|
| `editorial` | Long-form manifesto/editorial style |
|
|
| `fun` | Playful/personal pages |
|
|
| `minimal` | Bare-bones single section |
|
|
| `custom` | Hand-crafted HTML, no rendering |
|
|
|
|
## site.yaml
|
|
|
|
```yaml
|
|
domain: example.de
|
|
aliases: [www.example.de]
|
|
template: person-dark
|
|
title: "Page Title"
|
|
description: "Meta description"
|
|
lang: de
|
|
|
|
vars:
|
|
name: "Name"
|
|
role: "Role"
|
|
initials: "AB"
|
|
tagline: "Tagline here"
|
|
accent: "#c9a84c"
|
|
accent_light: "rgba(201, 168, 76, 0.1)"
|
|
font_primary: "Inter"
|
|
font_secondary: "Newsreader"
|
|
tags: ["Tag 1", "Tag 2"]
|
|
sections:
|
|
- type: features
|
|
title: "Section Title"
|
|
items:
|
|
- title: "Item"
|
|
desc: "Description"
|
|
- type: profile
|
|
bio: "Bio text"
|
|
cta:
|
|
text: "Contact"
|
|
href: "mailto:info@example.de"
|
|
|
|
schema:
|
|
type: Person
|
|
name: "Erika Mustermann"
|
|
url: "https://example.de/"
|
|
jobTitle: "Patentanwältin"
|
|
sameAs:
|
|
- https://www.linkedin.com/in/erika-mustermann/
|
|
- https://github.com/erika-mustermann
|
|
```
|
|
|
|
## Schema.org / JSON-LD (GEO/SEO)
|
|
|
|
Templated sites can declare a `schema:` block in `site.yaml`. `render.sh` emits it as `<script type="application/ld+json">…</script>` inside `<head>` (slot `{{schema_jsonld}}` in `templates/base.html`). See `docs/geo-seo-guideline.md` §3.3 for rationale.
|
|
|
|
### Conventions
|
|
|
|
- `schema.type` → `@type` (the YAML key is `type`, the rendered key is `@type`).
|
|
- `@context: https://schema.org` is added automatically.
|
|
- Nested objects use the JSON-LD form directly: write `"@type": Organization` (quoted because of the `@`).
|
|
- Array fields like `sameAs:` are passed through as JSON arrays.
|
|
- If `schema:` is absent, no `<script>` tag is emitted (empty slot).
|
|
- If `schema.type` is omitted, the template default applies:
|
|
- `person-dark`, `person-light` → `Person`
|
|
- `product-dark` → `Product`
|
|
- `editorial` → `Article`
|
|
- `fun`, `minimal` → no default (set `type:` explicitly).
|
|
|
|
Supported types include `Person`, `Organization`, `Article`, `Product`, `FAQPage`, `LocalBusiness`. Schema.org accepts any type — these are just the ones we use most.
|
|
|
|
### Custom sites
|
|
|
|
`template: custom` skips rendering, so the slot is **not applied**. Hand-craft the JSON-LD directly inside `index.html` — typically right before `</head>`.
|
|
|
|
### Testing
|
|
|
|
```bash
|
|
./tests/schema-test.sh
|
|
```
|
|
|
|
Renders fixture files in `tests/fixtures/` and validates that JSON-LD is well-formed, has the correct `@context`/`@type`, and that sites without `schema:` produce no script tag.
|
|
|
|
For Schema.org-validator checks (recommended for any new live site that uses the slot), paste the rendered `<script type="application/ld+json">` block into <https://validator.schema.org/>.
|
|
|
|
## Related
|
|
|
|
- Issue #341: Onepager Mono-Repo
|
|
- Issue #335: Container consolidation
|