updates 33.2 112
This commit is contained in:
93
docs/data/en/artery-plexuses.md
Normal file
93
docs/data/en/artery-plexuses.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Plexuses
|
||||
|
||||
A **plexus** is a full app — the vocabulary has always said so
|
||||
(*"full app with backend, frontend and DB"*). What was missing is that a plexus
|
||||
is **exported, not served**. It is compiled to a distributable file the way vite
|
||||
builds for production, and that compile is the whole point of the format.
|
||||
|
||||
```bash
|
||||
make dist # compile the plexus UIs for standalone
|
||||
make dist sample # for a named room
|
||||
```
|
||||
|
||||
Output is one `index.html` per plexus under `gen/<room>/plexuses/<name>/`,
|
||||
carrying its theme, its data and its diagrams inline. No server, no node, no
|
||||
network. Zip it, mail it, double-click it.
|
||||
|
||||
`make build` runs the same step as part of a room build. `make dist` exists for
|
||||
the loop where the UI is what you are working on — rebuilding a whole room to
|
||||
see a CSS change is a slow way to iterate.
|
||||
|
||||
## The constraint that shapes it
|
||||
|
||||
It has to open from a **double-clicked file on a machine with no egress**. That
|
||||
is the state a regulated Windows box is usually in, and it rules out three
|
||||
things a normal web app does:
|
||||
|
||||
| Ruled out | Because |
|
||||
| --- | --- |
|
||||
| `fetch("bundle.json")` | `file://` treats every sibling file as cross-origin |
|
||||
| `<link href="/theme.css">` | an absolute path assumes a server at the root |
|
||||
| a webfont `@import` | a blocked stylesheet is a stall, not a fallback |
|
||||
|
||||
So the data is a JS object, the theme is inlined at compile time, and the fonts
|
||||
are stacks. The test that matters is opening the output with the network off and
|
||||
seeing zero failed requests — everything else is cosmetic.
|
||||
|
||||
## Declaring one
|
||||
|
||||
A room opts in through `cfg/<room>/data/plexuses.json`, the same shape and the
|
||||
same place as its sibling `data/*.json` files:
|
||||
|
||||
```json
|
||||
{ "items": [ { "name": "bundle" } ] }
|
||||
```
|
||||
|
||||
A room may override anything the plexus declares — most usefully the theme:
|
||||
|
||||
```json
|
||||
{ "items": [ { "name": "bundle", "theme": "mcrn" } ] }
|
||||
```
|
||||
|
||||
## Writing one
|
||||
|
||||
```
|
||||
soleprint/artery/plexuses/<name>/
|
||||
plexus.json identity, theme, the data the page renders
|
||||
app/index.html the template
|
||||
```
|
||||
|
||||
`build.py` fills these placeholders and writes one file:
|
||||
|
||||
| Placeholder | Becomes |
|
||||
| --- | --- |
|
||||
| `%%THEME_CSS%%` | tokens plus every theme, so the switcher has something to switch to |
|
||||
| `%%BUNDLE%%` | `plexus.json` as a JS object |
|
||||
| `%%GRAPH%%` | a rendered SVG from `docs/graphs/`, inlined |
|
||||
| `%%TITLE%%` `%%DESCRIPTION%%` `%%DEFAULT_THEME%%` `%%BUILT%%` | from the manifest |
|
||||
|
||||
Anything else in `app/` is copied alongside, for a plexus that outgrows one file.
|
||||
|
||||
## The bundle plexus
|
||||
|
||||
The one that ships. It answers "what does a rig installation have at its
|
||||
disposal" — tools, cabinets, veins, themes — and embeds the system diagram.
|
||||
|
||||
Because the SVG is **inlined** rather than `<img>`-linked, the theme switch
|
||||
recolours the diagram too: graphviz writes `class="node accent"` into the SVG,
|
||||
and CSS outranks the presentation attributes it bakes in. Switching to `lucid`
|
||||
turns both the page and the diagram into something printable, which is the
|
||||
demonstration the format exists for.
|
||||
|
||||
## Not the same as rig's bundle
|
||||
|
||||
Two artifacts, both called bundle, generated by different repos:
|
||||
|
||||
| | soleprint | rig |
|
||||
| --- | --- | --- |
|
||||
| Command | `make dist` | `make manifest` in `sample-rig` |
|
||||
| Artifact | `plexuses/<name>/index.html` | `generated/<slug>.yaml` |
|
||||
| Needs | nothing | kind + MetalLB |
|
||||
| Answers | what shipped, on any machine | whether this cluster install is sound |
|
||||
|
||||
Complementary. One proves the environment, the other travels.
|
||||
@@ -19,6 +19,8 @@ make start # run it
|
||||
| Command | Runs | Does |
|
||||
| --- | --- | --- |
|
||||
| `make build [<room>\|all\|models]` | `ctrl/build.sh` | compile a room into `gen/` |
|
||||
| `make dist [<room>]` | `ctrl/dist.sh` | compile just the plexus UIs to single files |
|
||||
| `make docs [serve\|graphs]` | `ctrl/docs.sh` | serve the docs, or re-render the diagrams |
|
||||
| `make start [<room>] [-d]` | `ctrl/start.sh` | run a built room's compose stack |
|
||||
| `make stop [<room>]` | `ctrl/stop.sh` | stop it |
|
||||
| `make cluster [up\|down\|status]` | `ctrl/cluster.sh` | the shared kind cluster |
|
||||
@@ -50,9 +52,12 @@ make component ARGS="publish soleprint-ui /tmp/out --dist"
|
||||
4. **Compose cabinets.** The dependency containers the room declared in
|
||||
`data/cabinets.json` are merged into its `docker-compose.yml`. See
|
||||
[Cabinets](#station-cabinets).
|
||||
5. **Generate models.** modelgen reads the room's `config.json` and writes
|
||||
5. **Export plexuses.** Each plexus the room declared in `data/plexuses.json` is
|
||||
compiled to a single self-contained `index.html` — theme, data and diagrams
|
||||
inlined, so it opens with no server. See [Plexuses](#artery-plexuses).
|
||||
6. **Generate models.** modelgen reads the room's `config.json` and writes
|
||||
`models/pydantic/__init__.py`.
|
||||
6. **Render k8s** (optional). When the room's config enables it,
|
||||
7. **Render k8s** (optional). When the room's config enables it,
|
||||
`soleprint/ctrl/k8s/` writes manifests and lifecycle scripts.
|
||||
|
||||
## What comes out
|
||||
@@ -66,6 +71,7 @@ gen/standalone/
|
||||
cfg/config.json
|
||||
data/*.json
|
||||
models/pydantic/
|
||||
plexuses/<name>/index.html # one file each, opens with no server
|
||||
```
|
||||
|
||||
A **managed** room — one that wraps an existing application — is three folders
|
||||
@@ -122,3 +128,17 @@ the far side. `.env` is excluded, so server secrets stay on the server.
|
||||
default) straight from the source tree. It is for developing the framework
|
||||
itself; a room's `cfg/config.json` does not exist there, so the landing pages
|
||||
fall back to their defaults. Rooms use docker.
|
||||
|
||||
## Diagrams
|
||||
|
||||
The `.dot` sources under `docs/graphs/` carry structure; the palette lives in
|
||||
`docs/graphs/themes/*.gvpr` and is applied at render time, so one source renders
|
||||
in every theme.
|
||||
|
||||
```bash
|
||||
make docs graphs # every graph, every theme
|
||||
make docs graphs lucid # one theme
|
||||
```
|
||||
|
||||
`<name>.svg` is the dark default the docs link to; other themes write
|
||||
`<name>.<theme>.svg`. See [Themes](#themes).
|
||||
|
||||
110
docs/data/en/themes.md
Normal file
110
docs/data/en/themes.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Themes
|
||||
|
||||
Three themes ship, and the same palettes drive the diagrams as well as the
|
||||
pages. `soleprint` is the default; the others are switched to on purpose.
|
||||
|
||||
| Theme | Reads as | For |
|
||||
| --- | --- | --- |
|
||||
| `soleprint` | dark, rounded, amber | the default — tools and dev chrome |
|
||||
| `mcrn` | dark, square, monospace, orange glow | the terminal look, matched to mariano.mcrn.ar |
|
||||
| `lucid` | light, hairline, printable | regulated documents, and sitting beside a real lucid.app export |
|
||||
|
||||
Switch with `?theme=lucid`, or the toggle in the corner. The choice persists.
|
||||
|
||||
## Where it lives
|
||||
|
||||
```
|
||||
soleprint/common/theme/
|
||||
tokens.css the vocabulary + neutral defaults
|
||||
themes/*.css one file per theme
|
||||
theme.js resolve, apply, remember
|
||||
bake.py inline the defaults into pages
|
||||
```
|
||||
|
||||
Served together at `/theme.css` — tokens first, then every theme, each scoped to
|
||||
`[data-theme="..."]`. Adding a theme is adding a file: `run.py` lists the
|
||||
directory rather than carrying a hardcoded list.
|
||||
|
||||
## Two naming families, one set of values
|
||||
|
||||
Both are answered, because both were already in use and renaming across a dozen
|
||||
templates would have been the larger change:
|
||||
|
||||
- `--bg` / `--surface` / `--border` / `--text` / `--muted` / `--accent` — the
|
||||
station tools and the docs site
|
||||
- `--surface-0..3` / `--text-primary` / `--panel-radius` — `common/ui`'s Vue
|
||||
components
|
||||
|
||||
The second family is derived from the first in `tokens.css`, so a page using
|
||||
either name gets the same colour and a theme author fills in one set.
|
||||
|
||||
## Order matters
|
||||
|
||||
```html
|
||||
<!-- baked defaults --> <style>:root { … }</style>
|
||||
<link rel="stylesheet" href="/theme.css">
|
||||
<style> …the page's own rules… </style>
|
||||
```
|
||||
|
||||
The theme has to load **before** the page's styles, so its element defaults
|
||||
underpin the page rather than override it. Get this backwards and
|
||||
`tokens.css`'s `body { background: var(--bg) }` flattens whatever the page
|
||||
wanted — which is exactly how artery, atlas and station briefly lost their
|
||||
coloured content columns.
|
||||
|
||||
## Baked defaults, and why
|
||||
|
||||
`/theme.css` is an absolute path, and soleprint is not always at the root — in a
|
||||
room's nginx it sits under `/spr/` while `location /` goes to the frontend. A
|
||||
page that says `background: var(--bg)` and never receives `--bg` does not fall
|
||||
back to something plainer: the declaration is invalid at computed-value time, so
|
||||
the background goes transparent and the text goes initial-black on a design that
|
||||
assumed dark. Unstyled, not merely unbranded.
|
||||
|
||||
So every page carries a generated `:root` block **before** the link. Both are
|
||||
`:root`, so document order decides: the served stylesheet wins when it loads,
|
||||
and the baked block is what is left when it does not.
|
||||
|
||||
```bash
|
||||
python3 common/theme/bake.py # regenerate
|
||||
python3 common/theme/bake.py --check # fail if a page is stale
|
||||
```
|
||||
|
||||
Only the variables a page actually uses are emitted, so the blocks stay small.
|
||||
|
||||
## No webfonts
|
||||
|
||||
The stacks name faces that exist on the target rather than fetching any:
|
||||
|
||||
```css
|
||||
--font-ui: "Segoe UI", Inter, system-ui, -apple-system, Arial, sans-serif;
|
||||
--font-mono: "Cascadia Mono", "JetBrains Mono", Consolas, "SF Mono", monospace;
|
||||
```
|
||||
|
||||
Segoe UI and Consolas ship with Windows. A regulated network blocks
|
||||
`fonts.googleapis.com` and `file://` stalls on it, and neither failure looks
|
||||
like a missing font — they look like a broken page.
|
||||
|
||||
## Diagrams follow
|
||||
|
||||
`docs/graphs/themes/*.gvpr` carry the same palettes for graphviz, so a diagram
|
||||
and the page around it are one visual language. See
|
||||
[the graphs README](https://git.mcrn.ar/mariano/soleprint/src/branch/main/docs/graphs/README.md)
|
||||
and [Export / Compile](#export).
|
||||
|
||||
```bash
|
||||
make docs graphs # every graph, every theme
|
||||
```
|
||||
|
||||
Diagrams are baked per theme rather than styled by CSS, because the docs embed
|
||||
them with `<img src=…>` — which makes the SVG a separate document the page's
|
||||
stylesheet cannot reach. A plexus that **inlines** the SVG can style it live,
|
||||
and the bundle plexus does exactly that.
|
||||
|
||||
## Contrast
|
||||
|
||||
`lucid` is the first light theme, and the palette was measured rather than
|
||||
guessed — against both `#ffffff` and the `#f5f7fa` panel, at the sizes actually
|
||||
used. `--dim` drives 11px notes and `--status-warn` drives 10px labels, so both
|
||||
need 4.5:1 rather than the 3:1 large text gets away with. The obvious lighter
|
||||
greys came in at 3.4–3.8 and were dropped for that reason.
|
||||
@@ -1,32 +1,188 @@
|
||||
[
|
||||
{"id": "intro", "title": {"en": "Introduction"}},
|
||||
{"id": "quickstart", "title": {"en": "Quick Start"}},
|
||||
{"id": "concepts", "title": {"en": "Concepts"}},
|
||||
{"id": "room-setup", "title": {"en": "↳ Room Setup"}, "sub": true},
|
||||
{"id": "standalone", "title": {"en": "↳ Standalone"}, "sub": true},
|
||||
{"id": "managed", "title": {"en": "↳ Managed"}, "sub": true},
|
||||
|
||||
{"id": "artery", "title": {"en": "Artery"}},
|
||||
{"id": "artery-jira", "title": {"en": "↳ Jira"}, "sub": true},
|
||||
{"id": "artery-google", "title": {"en": "↳ Google"}, "sub": true},
|
||||
{"id": "artery-slack", "title": {"en": "↳ Slack"}, "sub": true},
|
||||
{"id": "artery-ia", "title": {"en": "↳ IA"}, "sub": true},
|
||||
{"id": "artery-shunts", "title": {"en": "↳ Shunts"}, "sub": true},
|
||||
|
||||
{"id": "atlas", "title": {"en": "Atlas"}},
|
||||
{"id": "atlas-books", "title": {"en": "↳ Books"}, "sub": true},
|
||||
{"id": "atlas-templates", "title": {"en": "↳ Templates"}, "sub": true},
|
||||
|
||||
{"id": "station", "title": {"en": "Station"}},
|
||||
{"id": "station-tester", "title": {"en": "↳ Tester"}, "sub": true},
|
||||
{"id": "station-datagen", "title": {"en": "↳ Datagen"}, "sub": true},
|
||||
{"id": "station-modelgen", "title": {"en": "↳ Modelgen"}, "sub": true},
|
||||
{"id": "station-graphgen", "title": {"en": "↳ Graphgen"}, "sub": true},
|
||||
{"id": "station-shuntgen", "title": {"en": "↳ Shuntgen"}, "sub": true},
|
||||
{"id": "station-databrowse", "title": {"en": "↳ Databrowse"}, "sub": true},
|
||||
{"id": "station-cabinets", "title": {"en": "↳ Cabinets"}, "sub": true},
|
||||
|
||||
{"id": "components", "title": {"en": "Shared Components"}},
|
||||
{"id": "export", "title": {"en": "Export / Compile"}},
|
||||
{"id": "deployment", "title": {"en": "Deployment"}}
|
||||
{
|
||||
"id": "intro",
|
||||
"title": {
|
||||
"en": "Introduction"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "quickstart",
|
||||
"title": {
|
||||
"en": "Quick Start"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "concepts",
|
||||
"title": {
|
||||
"en": "Concepts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "room-setup",
|
||||
"title": {
|
||||
"en": "↳ Room Setup"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "standalone",
|
||||
"title": {
|
||||
"en": "↳ Standalone"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "managed",
|
||||
"title": {
|
||||
"en": "↳ Managed"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery",
|
||||
"title": {
|
||||
"en": "Artery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "artery-jira",
|
||||
"title": {
|
||||
"en": "↳ Jira"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery-google",
|
||||
"title": {
|
||||
"en": "↳ Google"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery-slack",
|
||||
"title": {
|
||||
"en": "↳ Slack"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery-ia",
|
||||
"title": {
|
||||
"en": "↳ IA"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery-shunts",
|
||||
"title": {
|
||||
"en": "↳ Shunts"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "artery-plexuses",
|
||||
"title": {
|
||||
"en": "↳ Plexuses"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "atlas",
|
||||
"title": {
|
||||
"en": "Atlas"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "atlas-books",
|
||||
"title": {
|
||||
"en": "↳ Books"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "atlas-templates",
|
||||
"title": {
|
||||
"en": "↳ Templates"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station",
|
||||
"title": {
|
||||
"en": "Station"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "station-tester",
|
||||
"title": {
|
||||
"en": "↳ Tester"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-datagen",
|
||||
"title": {
|
||||
"en": "↳ Datagen"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-modelgen",
|
||||
"title": {
|
||||
"en": "↳ Modelgen"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-graphgen",
|
||||
"title": {
|
||||
"en": "↳ Graphgen"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-shuntgen",
|
||||
"title": {
|
||||
"en": "↳ Shuntgen"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-databrowse",
|
||||
"title": {
|
||||
"en": "↳ Databrowse"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "station-cabinets",
|
||||
"title": {
|
||||
"en": "↳ Cabinets"
|
||||
},
|
||||
"sub": true
|
||||
},
|
||||
{
|
||||
"id": "components",
|
||||
"title": {
|
||||
"en": "Shared Components"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export",
|
||||
"title": {
|
||||
"en": "Export / Compile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "themes",
|
||||
"title": {
|
||||
"en": "Themes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deployment",
|
||||
"title": {
|
||||
"en": "Deployment"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user