@rettangoli/sites 1.0.0-rc5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,7 +71,8 @@ build:
71
71
  keepMarkdownFiles: false
72
72
  imports:
73
73
  templates:
74
- docs/documentation: https://example.com/templates/docs-documentation.yaml
74
+ base: https://example.com/templates/base.yaml
75
+ docs: https://example.com/templates/docs.yaml
75
76
  partials:
76
77
  docs/nav: https://example.com/partials/docs-nav.yaml
77
78
  ```
@@ -93,7 +94,7 @@ Example mappings:
93
94
  - `pages/docs/intro.md` -> `_site/docs/intro/index.html` and `_site/docs/intro.md`
94
95
 
95
96
  `imports` lets you map aliases to remote YAML files (HTTP/HTTPS only). Use aliases in pages/templates:
96
- - page frontmatter: `template: docs/documentation`
97
+ - page frontmatter: `template: base` or `template: docs`
97
98
  - template/page content: `$partial: docs/nav`
98
99
 
99
100
  Imported files are cached on disk under `.rettangoli/sites/imports/{templates|partials}/` (hashed filenames).
@@ -104,16 +105,43 @@ When an alias exists both remotely and locally, local files under `templates/` a
104
105
 
105
106
  If you want to publish a manual `llms.txt`, place it in `static/llms.txt`; it will be copied to `_site/llms.txt`.
106
107
 
107
- ## Pre-published Import Assets
108
+ ## System Frontmatter
108
109
 
109
- `@rettangoli/sites` publishes reusable template/partial YAML assets under `sites/` for URL imports.
110
+ Use `_bind` to map global data keys into page-local variables.
110
111
 
111
- - Docs template: `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/docs/documentation.yaml`
112
- - Docs partial: `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/partials/docs/mobile-nav.yaml`
113
- - Rettangoli.dev shells: `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/*.yaml`
114
- - Default scaffold base: `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/default/base.yaml`
112
+ Example:
113
+
114
+ ```yaml
115
+ ---
116
+ template: base
117
+ _bind:
118
+ docs: feDocs
119
+ ---
120
+ ```
121
+
122
+ This resolves `docs` from `data/feDocs.yaml` for that page.
123
+ `_bind` is a system property and is not exposed to templates directly.
124
+
125
+ Rules:
126
+
127
+ - `_bind` must be an object
128
+ - each `_bind` value must be a non-empty string
129
+ - each `_bind` value must point to an existing `data/*.yaml` key
130
+ - `_bind` is removed from public frontmatter before rendering/collections
131
+
132
+ Binding order:
115
133
 
116
- See `sites/README.md` for full alias examples and required data contract.
134
+ 1. build page context from `deepMerge(globalData, frontmatterWithoutSystemKeys)`
135
+ 2. apply `_bind` aliases on top (alias wins for that key)
136
+
137
+ ## Reusable Asset Package
138
+
139
+ `@rettangoli/sites` is the engine only.
140
+
141
+ Reusable themes, templates, partials, helper assets, schemas, and VT coverage now live in `packages/rettangoli-sitekit/` and publish from `@rettangoli/sitekit`.
142
+
143
+ Use `@rettangoli/sitekit` when you want curated importable site assets.
144
+ Keep `@rettangoli/sites` for build/watch/init behavior.
117
145
 
118
146
  ## Template Authoring Pattern
119
147
 
@@ -159,12 +187,14 @@ Available in YAML templates/pages without extra setup:
159
187
  - `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
160
188
  - `now(format = "YYYYMMDDHHmmss", useUtc = true)`
161
189
  - `sort(list, key, order = "asc")`
190
+ - `chunk(list, size = 1, pad = false, fillValue = null)`
162
191
  - `md(content)`
163
192
  - `toQueryString(object)`
164
193
 
165
- `formatDate` tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
194
+ `formatDate` tokens: `YYYY`, `MMM`, `MM`, `DD`, `D`, `HH`, `mm`, `ss`.
166
195
  `decodeURI`/`decodeURIComponent` return the original input when decoding fails.
167
196
  `sort` supports `order` as `asc` or `desc` (default: `asc`), accepts dot-path keys (for example `data.date`), and returns a new array.
197
+ `chunk` splits arrays into rows of `size`; with `pad = true`, the last row is padded with `fillValue`.
168
198
  `md` returns raw rendered HTML from Markdown for template insertion.
169
199
 
170
200
  ## Screenshots
@@ -177,6 +207,16 @@ Use VT against your generated site:
177
207
  2. Add `vt` config in `rettangoli.config.yaml`.
178
208
  3. Run `rtgl vt generate`, `rtgl vt report`, and `rtgl vt accept`.
179
209
 
210
+ Docker runtime (recommended for stable Playwright/browser versions):
211
+
212
+ ```bash
213
+ IMAGE="han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.0.5"
214
+ docker pull "$IMAGE"
215
+ docker run --rm -v "$PWD:/workspace" -w /workspace "$IMAGE" rtgl vt screenshot
216
+ docker run --rm -v "$PWD:/workspace" -w /workspace "$IMAGE" rtgl vt report
217
+ docker run --rm -v "$PWD:/workspace" -w /workspace "$IMAGE" rtgl vt accept
218
+ ```
219
+
180
220
  Example:
181
221
 
182
222
  ```yaml
@@ -200,6 +240,8 @@ url: /
200
240
 
201
241
  `bun run preview` (or any equivalent local server command) must serve your built site on `vt.url` (for example serving `_site/` on port `4173`).
202
242
 
243
+ For a maintained example asset pack and VT lab, see `packages/rettangoli-sitekit/`.
244
+
203
245
  ## Full Architecture And Analysis
204
246
 
205
247
  See `docs/architecture-and-analysis.md` for:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/sites",
3
- "version": "1.0.0-rc5",
3
+ "version": "1.0.1",
4
4
  "description": "Generate static sites using Markdown and YAML for docs, blogs, and marketing sites.",
5
5
  "author": {
6
6
  "name": "Luciano Hanyon Wu",
@@ -14,8 +14,7 @@
14
14
  "files": [
15
15
  "src",
16
16
  "components",
17
- "templates",
18
- "sites"
17
+ "templates"
19
18
  ],
20
19
  "dependencies": {
21
20
  "gray-matter": "^4.0.3",
@@ -49,6 +48,11 @@
49
48
  "admin",
50
49
  "dashboard"
51
50
  ],
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/yuusoft-org/rettangoli",
54
+ "directory": "packages/rettangoli-sites"
55
+ },
52
56
  "bugs": {
53
57
  "url": "https://github.com/yuusoft-org/rettangoli/issues"
54
58
  },
@@ -25,16 +25,20 @@ function formatDateImpl(value, format = 'YYYYMMDDHHmmss', useUtc = true) {
25
25
  }
26
26
 
27
27
  const read = (localGetter, utcGetter) => (useUtc ? utcGetter.call(date) : localGetter.call(date));
28
+ const monthIndex = read(date.getMonth, date.getUTCMonth);
29
+ const day = read(date.getDate, date.getUTCDate);
28
30
  const tokens = {
29
31
  YYYY: String(read(date.getFullYear, date.getUTCFullYear)),
30
- MM: pad2(read(date.getMonth, date.getUTCMonth) + 1),
31
- DD: pad2(read(date.getDate, date.getUTCDate)),
32
+ MMM: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][monthIndex],
33
+ MM: pad2(monthIndex + 1),
34
+ DD: pad2(day),
35
+ D: String(day),
32
36
  HH: pad2(read(date.getHours, date.getUTCHours)),
33
37
  mm: pad2(read(date.getMinutes, date.getUTCMinutes)),
34
38
  ss: pad2(read(date.getSeconds, date.getUTCSeconds)),
35
39
  };
36
40
 
37
- return String(format).replace(/YYYY|MM|DD|HH|mm|ss/g, (token) => tokens[token]);
41
+ return String(format).replace(/YYYY|MMM|MM|DD|D|HH|mm|ss/g, (token) => tokens[token]);
38
42
  }
39
43
 
40
44
  function jsonStringify(value, space = 0) {
@@ -141,6 +145,32 @@ function sortImpl(value, key, order = 'asc') {
141
145
  });
142
146
  }
143
147
 
148
+ function chunkImpl(value, size = 1, pad = false, fillValue = null) {
149
+ if (!Array.isArray(value)) {
150
+ return [];
151
+ }
152
+
153
+ const parsedSize = Number(size);
154
+ if (!Number.isFinite(parsedSize) || parsedSize <= 0) {
155
+ return [];
156
+ }
157
+
158
+ const chunkSize = Math.max(1, Math.trunc(parsedSize));
159
+ const rows = [];
160
+ for (let index = 0; index < value.length; index += chunkSize) {
161
+ rows.push(value.slice(index, index + chunkSize));
162
+ }
163
+
164
+ if (pad && rows.length > 0) {
165
+ const lastRow = rows[rows.length - 1];
166
+ while (lastRow.length < chunkSize) {
167
+ lastRow.push(fillValue);
168
+ }
169
+ }
170
+
171
+ return rows;
172
+ }
173
+
144
174
  function mdImpl(content) {
145
175
  return {
146
176
  __html: markdownRenderer.render(String(content ?? '')),
@@ -156,6 +186,7 @@ export const builtinTemplateFunctions = {
156
186
  formatDate: formatDateImpl,
157
187
  now: (format = 'YYYYMMDDHHmmss', useUtc = true) => formatDateImpl(new Date(), format, useUtc),
158
188
  sort: sortImpl,
189
+ chunk: chunkImpl,
159
190
  md: mdImpl,
160
191
  toQueryString,
161
192
  };
package/src/cli/watch.js CHANGED
@@ -7,6 +7,14 @@ import { loadSiteConfig } from '../utils/loadSiteConfig.js';
7
7
 
8
8
  const RELOAD_MODES = new Set(['body', 'full']);
9
9
 
10
+ function normalizePort(port) {
11
+ const normalizedPort = Number(port);
12
+ if (!Number.isInteger(normalizedPort) || normalizedPort < 1 || normalizedPort > 65535) {
13
+ throw new Error(`Invalid port "${port}". Allowed values: integers from 1 to 65535.`);
14
+ }
15
+ return normalizedPort;
16
+ }
17
+
10
18
  export function createClientScript(reloadMode = 'body') {
11
19
  const shouldUseBodyReplacement = reloadMode === 'body';
12
20
  const reloadSnippet = shouldUseBodyReplacement
@@ -332,6 +340,7 @@ const watchSite = async (options = {}) => {
332
340
  quiet = false,
333
341
  reloadMode = 'body'
334
342
  } = options;
343
+ const normalizedPort = normalizePort(port);
335
344
  const normalizedReloadMode = String(reloadMode).toLowerCase();
336
345
  if (!RELOAD_MODES.has(normalizedReloadMode)) {
337
346
  throw new Error(`Invalid reload mode "${reloadMode}". Allowed values: body, full.`);
@@ -347,7 +356,7 @@ const watchSite = async (options = {}) => {
347
356
  logger.log('Initial build complete');
348
357
 
349
358
  // Start custom dev server
350
- const server = new DevServer(port, path.resolve(rootDir, outputPath), logger, normalizedReloadMode);
359
+ const server = new DevServer(normalizedPort, path.resolve(rootDir, outputPath), logger, normalizedReloadMode);
351
360
  server.start();
352
361
 
353
362
  // Watch all relevant directories
@@ -40,6 +40,41 @@ function isObject(item) {
40
40
  return item && typeof item === 'object' && !Array.isArray(item);
41
41
  }
42
42
 
43
+ function splitSystemFrontmatter(frontmatter, globalData, pagePath) {
44
+ const normalized = isObject(frontmatter) ? { ...frontmatter } : {};
45
+ const bindConfig = normalized._bind;
46
+ delete normalized._bind;
47
+
48
+ if (bindConfig === undefined) {
49
+ return { frontmatter: normalized, bindings: {} };
50
+ }
51
+
52
+ if (!isObject(bindConfig)) {
53
+ throw new Error(`Invalid _bind in ${pagePath}: expected an object mapping local names to global data keys.`);
54
+ }
55
+
56
+ const bindings = {};
57
+ for (const [rawLocalKey, rawSourceKey] of Object.entries(bindConfig)) {
58
+ const localKey = String(rawLocalKey).trim();
59
+ if (localKey === '') {
60
+ throw new Error(`Invalid _bind in ${pagePath}: local key names must be non-empty.`);
61
+ }
62
+
63
+ if (typeof rawSourceKey !== 'string' || rawSourceKey.trim() === '') {
64
+ throw new Error(`Invalid _bind in ${pagePath} for "${localKey}": expected a non-empty global data key string.`);
65
+ }
66
+
67
+ const sourceKey = rawSourceKey.trim();
68
+ if (!Object.prototype.hasOwnProperty.call(globalData, sourceKey)) {
69
+ throw new Error(`Invalid _bind in ${pagePath} for "${localKey}": global data key "${sourceKey}" not found.`);
70
+ }
71
+
72
+ bindings[localKey] = globalData[sourceKey];
73
+ }
74
+
75
+ return { frontmatter: normalized, bindings };
76
+ }
77
+
43
78
  function parseYamlWithContext(content, contextLabel) {
44
79
  try {
45
80
  return yaml.load(content, { schema: yaml.JSON_SCHEMA });
@@ -157,6 +192,39 @@ function readImportedYamlFromCache(fs, cachePath, aliasLabel) {
157
192
  return parseYamlWithContext(content, `${aliasLabel} (cache: ${cachePath})`);
158
193
  }
159
194
 
195
+ function resolveDirentKind(fs, itemPath, item) {
196
+ if (item.isDirectory()) {
197
+ return 'directory';
198
+ }
199
+
200
+ if (item.isFile()) {
201
+ return 'file';
202
+ }
203
+
204
+ if (typeof item.isSymbolicLink === 'function' && item.isSymbolicLink()) {
205
+ let stats;
206
+ try {
207
+ stats = fs.statSync(itemPath);
208
+ } catch (error) {
209
+ throw new Error(`Broken symbolic link at "${itemPath}": ${error.message}`);
210
+ }
211
+
212
+ if (stats.isDirectory()) {
213
+ return 'directory';
214
+ }
215
+
216
+ if (stats.isFile()) {
217
+ return 'file';
218
+ }
219
+ }
220
+
221
+ return null;
222
+ }
223
+
224
+ function isSchemaSidecarFile(fileName) {
225
+ return fileName.endsWith('.schema.yaml') || fileName.endsWith('.schema.yml');
226
+ }
227
+
160
228
  async function fetchRemoteYaml(url, fetchImpl, aliasLabel) {
161
229
  const effectiveFetch = fetchImpl || globalThis.fetch;
162
230
  if (typeof effectiveFetch !== 'function') {
@@ -315,13 +383,18 @@ export function createSiteBuilder({
315
383
  const items = fs.readdirSync(dir, { withFileTypes: true });
316
384
  items.forEach(item => {
317
385
  const itemPath = path.join(dir, item.name);
318
- if (item.isDirectory()) {
386
+ const itemKind = resolveDirentKind(fs, itemPath, item);
387
+ if (itemKind === 'directory') {
319
388
  const newBasePath = basePath ? `${basePath}/${item.name}` : item.name;
320
389
  readPartialsRecursively(itemPath, newBasePath);
321
390
  return;
322
391
  }
323
392
 
324
- if (!item.isFile() || (!item.name.endsWith('.yaml') && !item.name.endsWith('.yml'))) {
393
+ if (
394
+ itemKind !== 'file' ||
395
+ (!item.name.endsWith('.yaml') && !item.name.endsWith('.yml')) ||
396
+ isSchemaSidecarFile(item.name)
397
+ ) {
325
398
  return;
326
399
  }
327
400
 
@@ -364,12 +437,17 @@ export function createSiteBuilder({
364
437
 
365
438
  items.forEach(item => {
366
439
  const itemPath = path.join(dir, item.name);
440
+ const itemKind = resolveDirentKind(fs, itemPath, item);
367
441
 
368
- if (item.isDirectory()) {
442
+ if (itemKind === 'directory') {
369
443
  // Recursively read subdirectories
370
444
  const newBasePath = basePath ? `${basePath}/${item.name}` : item.name;
371
445
  readTemplatesRecursively(itemPath, newBasePath);
372
- } else if (item.isFile() && (item.name.endsWith('.yaml') || item.name.endsWith('.yml'))) {
446
+ } else if (
447
+ itemKind === 'file' &&
448
+ (item.name.endsWith('.yaml') || item.name.endsWith('.yml')) &&
449
+ !isSchemaSidecarFile(item.name)
450
+ ) {
373
451
  // Read and convert YAML file
374
452
  const fileContent = fs.readFileSync(itemPath, 'utf8');
375
453
  const nameWithoutExt = path.basename(item.name, path.extname(item.name));
@@ -411,13 +489,15 @@ export function createSiteBuilder({
411
489
  for (const item of items) {
412
490
  const itemPath = path.join(fullDir, item.name);
413
491
  const relativePath = basePath ? path.join(basePath, item.name) : item.name;
492
+ const itemKind = resolveDirentKind(fs, itemPath, item);
414
493
 
415
- if (item.isDirectory()) {
494
+ if (itemKind === 'directory') {
416
495
  // Recursively scan subdirectories
417
496
  scanPages(dir, relativePath);
418
- } else if (item.isFile() && (item.name.endsWith('.yaml') || item.name.endsWith('.yml') || item.name.endsWith('.md'))) {
497
+ } else if (itemKind === 'file' && (item.name.endsWith('.yaml') || item.name.endsWith('.yml') || item.name.endsWith('.md'))) {
419
498
  // Extract frontmatter and content
420
499
  const { frontmatter, content } = extractFrontmatterAndContent(itemPath);
500
+ const { frontmatter: publicFrontmatter } = splitSystemFrontmatter(frontmatter, globalData, itemPath);
421
501
 
422
502
  // Calculate URL
423
503
  const baseFileName = item.name.replace(/\.(yaml|yml|md)$/, '');
@@ -435,9 +515,9 @@ export function createSiteBuilder({
435
515
  }
436
516
 
437
517
  // Process tags
438
- if (frontmatter.tags) {
518
+ if (publicFrontmatter.tags) {
439
519
  // Normalize tags to array
440
- const tags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [frontmatter.tags];
520
+ const tags = Array.isArray(publicFrontmatter.tags) ? publicFrontmatter.tags : [publicFrontmatter.tags];
441
521
 
442
522
  // Add to collections
443
523
  tags.forEach(tag => {
@@ -447,7 +527,7 @@ export function createSiteBuilder({
447
527
  collections[trimmedTag] = [];
448
528
  }
449
529
  collections[trimmedTag].push({
450
- data: frontmatter,
530
+ data: publicFrontmatter,
451
531
  url: url,
452
532
  content: content
453
533
  });
@@ -471,6 +551,7 @@ export function createSiteBuilder({
471
551
  if (!quiet) console.log(`Processing ${pagePath}...`);
472
552
 
473
553
  const { frontmatter, content: rawContent } = extractFrontmatterAndContent(pagePath);
554
+ const { frontmatter: publicFrontmatter, bindings: boundData } = splitSystemFrontmatter(frontmatter, globalData, pagePath);
474
555
 
475
556
  // Calculate URL for current page
476
557
  let url;
@@ -489,7 +570,8 @@ export function createSiteBuilder({
489
570
  }
490
571
 
491
572
  // Deep merge global data with frontmatter and collections for the page context
492
- const pageData = deepMerge(globalData, frontmatter);
573
+ const pageData = deepMerge(globalData, publicFrontmatter);
574
+ Object.assign(pageData, boundData);
493
575
  pageData.collections = collections;
494
576
  pageData.page = { url };
495
577
  pageData.build = { isScreenshotMode };
@@ -521,11 +603,11 @@ export function createSiteBuilder({
521
603
 
522
604
  // Find the template specified in frontmatter
523
605
  let templateToUse = null;
524
- if (frontmatter.template) {
606
+ if (publicFrontmatter.template) {
525
607
  // Look up template by exact path
526
- templateToUse = templates[frontmatter.template];
608
+ templateToUse = templates[publicFrontmatter.template];
527
609
  if (!templateToUse) {
528
- throw new Error(`Template "${frontmatter.template}" not found in ${pagePath}. Available templates: ${Object.keys(templates).join(', ')}`);
610
+ throw new Error(`Template "${publicFrontmatter.template}" not found in ${pagePath}. Available templates: ${Object.keys(templates).join(', ')}`);
529
611
  }
530
612
  }
531
613
 
@@ -617,11 +699,12 @@ export function createSiteBuilder({
617
699
  for (const item of items) {
618
700
  const itemPath = path.join(fullDir, item.name);
619
701
  const relativePath = basePath ? path.join(basePath, item.name) : item.name;
702
+ const itemKind = resolveDirentKind(fs, itemPath, item);
620
703
 
621
- if (item.isDirectory()) {
704
+ if (itemKind === 'directory') {
622
705
  // Recursively process subdirectories
623
706
  await processAllPages(dir, relativePath);
624
- } else if (item.isFile()) {
707
+ } else if (itemKind === 'file') {
625
708
  if (item.name.endsWith('.yaml') || item.name.endsWith('.yml')) {
626
709
  // Process YAML file
627
710
  const outputFileName = item.name.replace(/\.(yaml|yml)$/, '.html');
@@ -228,12 +228,14 @@ Use these directly in `${...}` expressions:
228
228
  - `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
229
229
  - `now(format = "YYYYMMDDHHmmss", useUtc = true)`
230
230
  - `sort(list, key, order = "asc")`
231
+ - `chunk(list, size = 1, pad = false, fillValue = null)`
231
232
  - `md(content)`
232
233
  - `toQueryString(object)`
233
234
 
234
- Date format tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
235
+ Date format tokens: `YYYY`, `MMM`, `MM`, `DD`, `D`, `HH`, `mm`, `ss`.
235
236
  `decodeURI`/`decodeURIComponent` return the original input when decoding fails.
236
237
  `sort` supports `order` as `asc` or `desc` (default: `asc`), accepts dot-path keys (for example `data.date`), and returns a new array.
238
+ `chunk` splits arrays into rows of `size`; with `pad = true`, the last row is padded with `fillValue`.
237
239
  `md` returns raw rendered HTML from Markdown for template insertion.
238
240
 
239
241
  ## Static Files
@@ -242,3 +244,22 @@ Everything in `static/` is copied to `_site/`:
242
244
 
243
245
  - `static/css/theme.css` → `_site/css/theme.css`
244
246
  - `static/images/logo.png` → `_site/images/logo.png`
247
+
248
+ ## Theme Classes
249
+
250
+ `static/css/theme.css` now includes multiple themes in one file.
251
+ Set exactly one class on `body` (or `html`) to choose the active palette.
252
+
253
+ Examples:
254
+ - `slate-dark` (default in starter templates)
255
+ - `slate-light`
256
+ - `mono-dark`
257
+ - `mono-light`
258
+ - `catppuccin-mocha`
259
+ - `catppuccin-macchiato`
260
+ - `catppuccin-frappe`
261
+ - `catppuccin-latte`
262
+ - `github-dark`
263
+ - `github-light`
264
+ - `nord-dark`
265
+ - `nord-light`
@@ -23,7 +23,7 @@ body {
23
23
  height: 100%;
24
24
  width: 100%;
25
25
  margin: 0;
26
- font-family: system-ui, -apple-system, "Helvetica Neue", sans-serif;
26
+ font-family: var(--font-family-sans);
27
27
  display: flex;
28
28
  flex-direction: column;
29
29
  background-color: var(--background);
@@ -34,14 +34,16 @@ body {
34
34
  }
35
35
 
36
36
  a {
37
- color: inherit;
38
- text-decoration: underline;
37
+ color: var(--anchor-color);
38
+ text-decoration: var(--anchor-text-decoration);
39
39
  text-decoration-thickness: 1px;
40
40
  text-underline-offset: 4px;
41
41
  text-decoration-color: var(--muted-foreground);
42
42
  }
43
43
 
44
44
  a:hover {
45
+ color: var(--anchor-color-hover);
46
+ text-decoration: var(--anchor-text-decoration-hover);
45
47
  text-decoration-color: var(--foreground);
46
48
  }
47
49
 
@@ -51,6 +53,7 @@ a:hover {
51
53
 
52
54
  :root {
53
55
  --width-stretch: 100%;
56
+ --font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
54
57
 
55
58
  --spacing-xs: 2px;
56
59
  --spacing-sm: 4px;
@@ -64,6 +67,7 @@ a:hover {
64
67
  --border-radius-lg: 8px;
65
68
  --border-radius-xl: 16px;
66
69
  --border-radius-f: 50%;
70
+ --border-radius-full: 9999px;
67
71
 
68
72
  --border-width-xs: 1px;
69
73
  --border-width-sm: 2px;
@@ -71,9 +75,9 @@ a:hover {
71
75
  --border-width-lg: 8px;
72
76
  --border-width-xl: 16px;
73
77
 
74
- --shadow-sm: 0px 2px 6px rgba(0, 0, 0, .45);
75
- --shadow-md: 0px 5px 12px rgba(0, 0, 0, .45);
76
- --shadow-lg: 0px 10px 24px rgba(0, 0, 0, .45);
78
+ --shadow-sm: 0px 2px 6px rgba(0, 0, 0, .45), 0px 3px 5px rgba(0, 0, 0, .35), inset 0px .5px 0px rgba(255, 255, 255, .08), inset 0px 0px .5px rgba(255, 255, 255, .35);
79
+ --shadow-md: 0px 5px 12px rgba(0, 0, 0, .45), 0px 3px 5px rgba(0, 0, 0, .35), inset 0px .5px 0px rgba(255, 255, 255, .08), inset 0px 0px .5px rgba(255, 255, 255, .35);
80
+ --shadow-lg: 0px 10px 24px rgba(0, 0, 0, .45), 0px 3px 5px rgba(0, 0, 0, .35), inset 0px .5px 0px rgba(255, 255, 255, .08), inset 0px 0px .5px rgba(255, 255, 255, .35);
77
81
 
78
82
  --h1-font-size: 3rem;
79
83
  --h1-font-weight: 600;
@@ -115,10 +119,74 @@ a:hover {
115
119
  --xs-line-height: 1;
116
120
  --xs-letter-spacing: normal;
117
121
 
122
+ --anchor-color: inherit;
123
+ --anchor-color-hover: inherit;
124
+ --anchor-text-decoration: underline;
125
+ --anchor-text-decoration-hover: underline;
126
+
127
+ /* Sensible fallback in case no theme class is set. */
128
+ --primary: oklch(0.922 0 0);
129
+ --primary-foreground: oklch(0.305 0 0);
130
+ --secondary: oklch(0.269 0 0);
131
+ --secondary-foreground: oklch(0.985 0 0);
132
+ --destructive: oklch(0.704 0.191 22.216);
133
+ --destructive-foreground: oklch(0.985 0 0);
134
+ --background: rgb(29 29 29);
135
+ --foreground: rgb(242 242 242);
136
+ --muted: oklch(0.269 0 0);
137
+ --muted-foreground: oklch(0.708 0 0);
138
+ --accent: oklch(0.371 0 0);
139
+ --accent-foreground: oklch(0.985 0 0);
140
+ --border: oklch(1 0 0 / 10%);
141
+ --input: oklch(1 0 0 / 15%);
142
+ --ring: oklch(0.556 0 0);
143
+ }
144
+
145
+ /* rtgl mono */
146
+ .mono-light {
147
+ --primary: #171717;
148
+ --primary-foreground: #fafafa;
149
+ --secondary: #f5f5f5;
150
+ --secondary-foreground: #171717;
151
+ --destructive: #e40014;
152
+ --destructive-foreground: #fcf3f3;
153
+ --background: #ffffff;
154
+ --foreground: #0a0a0a;
155
+ --muted: #f5f5f5;
156
+ --muted-foreground: #737373;
157
+ --accent: #f5f5f5;
158
+ --accent-foreground: #171717;
159
+ --border: #e5e5e5;
160
+ --input: #e5e5e5;
161
+ --ring: #a1a1a1;
162
+ }
163
+
164
+ .mono-dark {
165
+ --background: #0a0a0a;
166
+ --foreground: #fafafa;
167
+ --primary: #e5e5e5;
168
+ --primary-foreground: #171717;
169
+ --secondary: #262626;
170
+ --secondary-foreground: #fafafa;
171
+ --muted: #262626;
172
+ --muted-foreground: #a1a1a1;
173
+ --accent: #404040;
174
+ --accent-foreground: #fafafa;
175
+ --destructive: #ff6568;
176
+ --destructive-foreground: #df2225;
177
+ --border: #ffffff1a;
178
+ --input: #ffffff26;
179
+ --ring: #737373;
180
+ }
181
+
182
+ /* rtgl slate */
183
+ .slate-light {
118
184
  --primary: oklch(0.205 0 0);
119
185
  --primary-foreground: oklch(0.985 0 0);
120
186
  --secondary: oklch(0.97 0 0);
121
187
  --secondary-foreground: oklch(0.205 0 0);
188
+ --destructive: oklch(0.577 0.245 27.325);
189
+ --destructive-foreground: oklch(0.145 0 0);
122
190
  --background: oklch(1 0 0);
123
191
  --foreground: oklch(0.145 0 0);
124
192
  --muted: oklch(0.97 0 0);
@@ -130,9 +198,9 @@ a:hover {
130
198
  --ring: oklch(0.708 0 0);
131
199
  }
132
200
 
133
- .dark {
134
- --background: oklch(0.145 0 0);
135
- --foreground: oklch(0.985 0 0);
201
+ .slate-dark {
202
+ --background: rgb(29 29 29);
203
+ --foreground: rgb(242 242 242);
136
204
  --primary: oklch(0.922 0 0);
137
205
  --primary-foreground: oklch(0.305 0 0);
138
206
  --secondary: oklch(0.269 0 0);
@@ -141,11 +209,160 @@ a:hover {
141
209
  --muted-foreground: oklch(0.708 0 0);
142
210
  --accent: oklch(0.371 0 0);
143
211
  --accent-foreground: oklch(0.985 0 0);
212
+ --destructive: oklch(0.704 0.191 22.216);
213
+ --destructive-foreground: oklch(0.985 0 0);
144
214
  --border: oklch(1 0 0 / 10%);
145
215
  --input: oklch(1 0 0 / 15%);
146
216
  --ring: oklch(0.556 0 0);
147
217
  }
148
218
 
219
+ /* catppuccin */
220
+ .catppuccin-latte {
221
+ --primary: #1e66f5;
222
+ --primary-foreground: #eff1f5;
223
+ --secondary: #ccd0da;
224
+ --secondary-foreground: #4c4f69;
225
+ --destructive: #d20f39;
226
+ --destructive-foreground: #eff1f5;
227
+ --background: #eff1f5;
228
+ --foreground: #4c4f69;
229
+ --muted: #e6e9ef;
230
+ --muted-foreground: #6c6f85;
231
+ --accent: #dce0e8;
232
+ --accent-foreground: #4c4f69;
233
+ --border: #bcc0cc;
234
+ --input: #ccd0da;
235
+ --ring: #7287fd;
236
+ }
237
+
238
+ .catppuccin-frappe {
239
+ --primary: #8caaee;
240
+ --primary-foreground: #303446;
241
+ --secondary: #414559;
242
+ --secondary-foreground: #c6d0f5;
243
+ --destructive: #e78284;
244
+ --destructive-foreground: #303446;
245
+ --background: #303446;
246
+ --foreground: #c6d0f5;
247
+ --muted: #414559;
248
+ --muted-foreground: #a5adce;
249
+ --accent: #51576d;
250
+ --accent-foreground: #c6d0f5;
251
+ --border: #626880;
252
+ --input: #51576d;
253
+ --ring: #babbf1;
254
+ }
255
+
256
+ .catppuccin-macchiato {
257
+ --primary: #8aadf4;
258
+ --primary-foreground: #24273a;
259
+ --secondary: #363a4f;
260
+ --secondary-foreground: #cad3f5;
261
+ --destructive: #ed8796;
262
+ --destructive-foreground: #24273a;
263
+ --background: #24273a;
264
+ --foreground: #cad3f5;
265
+ --muted: #363a4f;
266
+ --muted-foreground: #a5adcb;
267
+ --accent: #494d64;
268
+ --accent-foreground: #cad3f5;
269
+ --border: #6e738d;
270
+ --input: #494d64;
271
+ --ring: #b7bdf8;
272
+ }
273
+
274
+ .catppuccin-mocha {
275
+ --background: #1e1e2e;
276
+ --foreground: #cdd6f4;
277
+ --primary: #89b4fa;
278
+ --primary-foreground: #1e1e2e;
279
+ --secondary: #313244;
280
+ --secondary-foreground: #cdd6f4;
281
+ --muted: #313244;
282
+ --muted-foreground: #a6adc8;
283
+ --accent: #45475a;
284
+ --accent-foreground: #cdd6f4;
285
+ --destructive: #f38ba8;
286
+ --destructive-foreground: #1e1e2e;
287
+ --border: #585b70;
288
+ --input: #45475a;
289
+ --ring: #b4befe;
290
+ }
291
+
292
+ /* common extras */
293
+ .github-light {
294
+ --background: #ffffff;
295
+ --foreground: #1f2328;
296
+ --primary: #0969da;
297
+ --primary-foreground: #ffffff;
298
+ --secondary: #f6f8fa;
299
+ --secondary-foreground: #24292f;
300
+ --muted: #f6f8fa;
301
+ --muted-foreground: #57606a;
302
+ --accent: #ddf4ff;
303
+ --accent-foreground: #0969da;
304
+ --destructive: #cf222e;
305
+ --destructive-foreground: #ffffff;
306
+ --border: #d0d7de;
307
+ --input: #d0d7de;
308
+ --ring: #0969da;
309
+ }
310
+
311
+ .github-dark {
312
+ --background: #0d1117;
313
+ --foreground: #c9d1d9;
314
+ --primary: #58a6ff;
315
+ --primary-foreground: #0d1117;
316
+ --secondary: #21262d;
317
+ --secondary-foreground: #c9d1d9;
318
+ --muted: #21262d;
319
+ --muted-foreground: #8b949e;
320
+ --accent: #30363d;
321
+ --accent-foreground: #c9d1d9;
322
+ --destructive: #f85149;
323
+ --destructive-foreground: #0d1117;
324
+ --border: #30363d;
325
+ --input: #30363d;
326
+ --ring: #58a6ff;
327
+ }
328
+
329
+ .nord-light {
330
+ --background: #eceff4;
331
+ --foreground: #2e3440;
332
+ --primary: #5e81ac;
333
+ --primary-foreground: #eceff4;
334
+ --secondary: #e5e9f0;
335
+ --secondary-foreground: #2e3440;
336
+ --muted: #e5e9f0;
337
+ --muted-foreground: #4c566a;
338
+ --accent: #d8dee9;
339
+ --accent-foreground: #2e3440;
340
+ --destructive: #bf616a;
341
+ --destructive-foreground: #eceff4;
342
+ --border: #d8dee9;
343
+ --input: #d8dee9;
344
+ --ring: #81a1c1;
345
+ }
346
+
347
+ .nord-dark {
348
+ --background: #2e3440;
349
+ --foreground: #eceff4;
350
+ --primary: #88c0d0;
351
+ --primary-foreground: #2e3440;
352
+ --secondary: #3b4252;
353
+ --secondary-foreground: #eceff4;
354
+ --muted: #3b4252;
355
+ --muted-foreground: #d8dee9;
356
+ --accent: #434c5e;
357
+ --accent-foreground: #eceff4;
358
+ --destructive: #bf616a;
359
+ --destructive-foreground: #eceff4;
360
+ --border: #4c566a;
361
+ --input: #4c566a;
362
+ --ring: #88c0d0;
363
+ }
364
+
365
+
149
366
  h1 {
150
367
  font-size: var(--h1-font-size);
151
368
  font-weight: var(--h1-font-weight);
@@ -7,8 +7,8 @@
7
7
  - $if site.assets.loadConstructStyleSheetsPolyfill:
8
8
  - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
9
  - $if site.assets.loadUiFromCdn:
10
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
11
- - body.dark:
10
+ - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/rettangoli-iife-ui.min.js":
11
+ - body.slate-dark:
12
12
  - rtgl-view w="f":
13
13
  - rtgl-view h="64":
14
14
  - rtgl-view w="f" ah="c":
@@ -7,8 +7,8 @@
7
7
  - $if site.assets.loadConstructStyleSheetsPolyfill:
8
8
  - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
9
  - $if site.assets.loadUiFromCdn:
10
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
11
- - body.dark:
10
+ - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc15/dist/rettangoli-iife-ui.min.js":
11
+ - body.slate-dark:
12
12
  - rtgl-view h="64":
13
13
  - rtgl-view w="f" ah="c":
14
14
  - rtgl-view d="h" g="xl" pb="lg" md-w="100vw" lg-w="768" w="1024" ph="lg":
package/sites/README.md DELETED
@@ -1,107 +0,0 @@
1
- # Rettangoli Sites Import Assets
2
-
3
- This folder contains publish-only YAML templates/partials for `@rettangoli/sites` URL imports.
4
- These files are distribution assets, not `@rettangoli/sites` runtime source code.
5
-
6
- ## Docs Bundle
7
-
8
- Template URL:
9
-
10
- `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/docs/documentation.yaml`
11
-
12
- Partial URL:
13
-
14
- `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/partials/docs/mobile-nav.yaml`
15
-
16
- `sites.config.yaml` example:
17
-
18
- ```yaml
19
- imports:
20
- templates:
21
- docs/documentation: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/docs/documentation.yaml
22
- partials:
23
- docs/mobile-nav: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/partials/docs/mobile-nav.yaml
24
- ```
25
-
26
- Page frontmatter example:
27
-
28
- ```yaml
29
- ---
30
- template: docs/documentation
31
- title: Getting Started
32
- sidebarId: intro
33
- ---
34
- ```
35
-
36
- Required template data:
37
-
38
- - `title`
39
- - `docsLayout.sidebar.header` (object for sidebar header)
40
- - `docsLayout.sidebar.items` (sidebar items)
41
- - `docsLayout.assets.stylesheets` (array of stylesheet URLs)
42
- - `docsLayout.assets.scripts` (array of script URLs)
43
-
44
- Optional data:
45
-
46
- - `docsLayout.metaDescription`
47
- - `docsLayout.canonicalUrl`
48
-
49
- Create `data/docsLayout.yaml`:
50
-
51
- ```yaml
52
- assets:
53
- stylesheets:
54
- - https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc14/dist/themes/base.css
55
- - https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc14/dist/themes/theme-rtgl-slate.css
56
- scripts:
57
- - https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js
58
- - https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc14/dist/rettangoli-iife-ui.min.js
59
-
60
- metaDescription: Documentation portal
61
- canonicalUrl: https://example.com/docs/getting-started/
62
-
63
- sidebar:
64
- header:
65
- label: Docs
66
- href: /
67
- items:
68
- - title: Introduction
69
- type: groupLabel
70
- items:
71
- - id: intro
72
- title: Introduction
73
- href: /docs/introduction/
74
- ```
75
-
76
- ## Rettangoli.dev Shell Templates
77
-
78
- These templates mirror `apps/rettangoli.dev/templates/*` so the app can consume
79
- them via URL imports instead of local template files.
80
-
81
- Template URLs:
82
-
83
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/base.yaml`
84
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/documentation.yaml`
85
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/fe-documentation.yaml`
86
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/sites-documentation.yaml`
87
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/vt-documentation.yaml`
88
-
89
- `sites.config.yaml` alias example:
90
-
91
- ```yaml
92
- imports:
93
- templates:
94
- base: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/base.yaml
95
- documentation: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/documentation.yaml
96
- fe-documentation: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/fe-documentation.yaml
97
- sites-documentation: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/sites-documentation.yaml
98
- vt-documentation: https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/rettangoli-dev/vt-documentation.yaml
99
- ```
100
-
101
- ## Default Scaffold Base Template
102
-
103
- This template mirrors `packages/rettangoli-sites/templates/default/templates/base.yaml`.
104
-
105
- Template URL:
106
-
107
- - `https://cdn.jsdelivr.net/npm/@rettangoli/sites@<version>/sites/templates/default/base.yaml`
@@ -1,7 +0,0 @@
1
- - $if docsLayout && docsLayout.sidebar && docsLayout.sidebar.header && docsLayout.sidebar.items:
2
- - 'rtgl-view hide md-show w=f d=v bgc=bg':
3
- - 'rtgl-view pos=fix w=f h=56 bgc=bg av=c ph=lg bwb=xs z=10 style="top:0;left:0"':
4
- - 'a href="${docsLayout.sidebar.header.href}" style="text-decoration:none;display:contents;color:inherit;"':
5
- - rtgl-text s=md: ${docsLayout.sidebar.header.label}
6
- - rtgl-view h=56:
7
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(docsLayout.sidebar.header))}" items="${encodeURIComponent(jsonStringify(docsLayout.sidebar.items))}" w=f:
@@ -1,20 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - meta charset="utf-8":
4
- - meta name="viewport" content="width=device-width,initial-scale=1":
5
- - title: ${title} - ${site.name}
6
- - link rel="stylesheet" href="/css/theme.css":
7
- - $if site.assets.loadConstructStyleSheetsPolyfill:
8
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
- - $if site.assets.loadUiFromCdn:
10
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
11
- - body.dark:
12
- - rtgl-view w="f":
13
- - rtgl-view h="64":
14
- - rtgl-view w="f" ah="c":
15
- - rtgl-view w="f" ph="lg" pb="lg" ah="c" md-w="100vw" lg-w="768" w="1024":
16
- - "${content}"
17
- - rtgl-view h="30vh":
18
- - $partial: footer
19
- - rtgl-view pos="abs" edge="t" ah="c" bgc="bg":
20
- - $partial: header
@@ -1,34 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - meta charset="utf-8":
4
- - meta name="viewport" content="width=device-width,initial-scale=1":
5
- - title: ${title}
6
- - $if docsLayout && docsLayout.metaDescription:
7
- - meta name="description" content="${docsLayout.metaDescription}":
8
- - $if docsLayout && docsLayout.canonicalUrl:
9
- - link rel="canonical" href="${docsLayout.canonicalUrl}":
10
- - $if docsLayout && docsLayout.assets && docsLayout.assets.stylesheets:
11
- - $for href in docsLayout.assets.stylesheets:
12
- - link rel="stylesheet" href="${href}":
13
- - $if docsLayout && docsLayout.assets && docsLayout.assets.scripts:
14
- - $for src in docsLayout.assets.scripts:
15
- - script src="${src}":
16
-
17
- - body.dark:
18
- - $partial: docs/mobile-nav
19
- docsLayout: ${docsLayout}
20
- sidebarId: ${sidebarId}
21
-
22
- - rtgl-view bgc="bg" w="f" d=h:
23
- - $if docsLayout && docsLayout.sidebar && docsLayout.sidebar.header && docsLayout.sidebar.items:
24
- - 'rtgl-view md-hide pos=fix h=100vh bgc=bg style="left: 0"':
25
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(docsLayout.sidebar.header))}" items="${encodeURIComponent(jsonStringify(docsLayout.sidebar.items))}":
26
- - rtgl-view md-hide xl-show hide w=272:
27
- - rtgl-view w="1fg" ah=c:
28
- - rtgl-view pv="lg" lg-w="100vw" w="720" ph="lg" sv id="content-container":
29
- - rtgl-view hide md-show h=56:
30
- - rtgl-text s="h1" mb="lg": ${title}
31
- - "${content}"
32
- - rtgl-view h=200:
33
- - 'rtgl-view xl-hide style="position: fixed; right: 0"':
34
- - rtgl-page-outline id="page-outline" target-id="content-container" scroll-container-id="window" offset-top="80":
@@ -1,24 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - $partial: seo1
4
- page: ${page}
5
- seo: ${seo}
6
- title: ${title}
7
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/base.css":
8
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/theme-rtgl-slate.css":
9
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
10
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
11
- - script src="/public/rtgl-icons.js":
12
-
13
- - body.dark:
14
- - rtgl-view:
15
- - rtgl-view pos="abs" edge="t" ah="c" bgc="bg":
16
- - $partial: navbar1
17
- title: ${site.navbar.title}
18
- cta: ${site.navbar.cta}
19
- - rtgl-view w=f:
20
- - rtgl-view h="48":
21
- - rtgl-view w="f" ah="c":
22
- - rtgl-view w=f ph="lg" pb="lg" ah=c:
23
- - "${content}"
24
- - script src="/public/mobile-nav.js":
@@ -1,33 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - $partial: seo1
4
- page: ${page}
5
- seo: ${seo}
6
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/base.css":
7
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/theme-rtgl-slate.css":
8
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
10
- - script src="/public/rtgl-icons.js":
11
-
12
- - body.dark:
13
- - $partial: mobile-nav1
14
- headerLabel: ${docs.header.label}
15
- headerHref: ${docs.header.href}
16
- header: ${docs.header}
17
- items: ${docs.items}
18
- sidebarId: ${sidebarId}
19
-
20
- - rtgl-view bgc="bg" w="f" d=h:
21
- - 'rtgl-view md-hide pos=fix h=100vh bgc=bg style="left: 0"':
22
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(docs.header))}" items="${encodeURIComponent(jsonStringify(docs.items))}":
23
- - rtgl-view md-hide xl-show hide w=272:
24
- - rtgl-view w="1fg" ah=c:
25
- - rtgl-view pv="lg" lg-w="100vw" w="720" ph="lg" sv id="content-container":
26
- - rtgl-view hide md-show h=56:
27
- - rtgl-text s="h1" mb="lg": ${title}
28
- - "${content}"
29
- - rtgl-view h=200:
30
- - 'rtgl-view xl-hide style="position: fixed; right: 0"':
31
- - rtgl-page-outline id="page-outline" target-id="content-container" scroll-container-id="window" offset-top="80":
32
-
33
- - script src="/public/mobile-nav.js":
@@ -1,33 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - $partial: seo1
4
- page: ${page}
5
- seo: ${seo}
6
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/base.css":
7
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/theme-rtgl-slate.css":
8
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
10
- - script src="/public/rtgl-icons.js":
11
-
12
- - body.dark:
13
- - $partial: mobile-nav1
14
- headerLabel: ${feDocs.header.label}
15
- headerHref: ${feDocs.header.href}
16
- header: ${feDocs.header}
17
- items: ${feDocs.items}
18
- sidebarId: ${sidebarId}
19
-
20
- - rtgl-view bgc="bg" w="f" d=h:
21
- - 'rtgl-view md-hide pos=fix h=100vh bgc=bg style="left: 0"':
22
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(feDocs.header))}" items="${encodeURIComponent(jsonStringify(feDocs.items))}":
23
- - rtgl-view md-hide xl-show hide w=272:
24
- - rtgl-view w="1fg" ah=c:
25
- - rtgl-view pv="lg" lg-w="100vw" w="720" ph="lg" sv id="content-container":
26
- - rtgl-view hide md-show h=56:
27
- - rtgl-text s="h1" mb="lg": ${title}
28
- - "${content}"
29
- - rtgl-view h=200:
30
- - 'rtgl-view xl-hide style="position: fixed; right: 0"':
31
- - rtgl-page-outline id="page-outline" target-id="content-container" scroll-container-id="window" offset-top="80":
32
-
33
- - script src="/public/mobile-nav.js":
@@ -1,33 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - $partial: seo1
4
- page: ${page}
5
- seo: ${seo}
6
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/base.css":
7
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/theme-rtgl-slate.css":
8
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
10
- - script src="/public/rtgl-icons.js":
11
-
12
- - body.dark:
13
- - $partial: mobile-nav1
14
- headerLabel: ${sitesDocs.header.label}
15
- headerHref: ${sitesDocs.header.href}
16
- header: ${sitesDocs.header}
17
- items: ${sitesDocs.items}
18
- sidebarId: ${sidebarId}
19
-
20
- - rtgl-view bgc="bg" w="f" d=h:
21
- - 'rtgl-view md-hide pos=fix h=100vh bgc=bg style="left: 0"':
22
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(sitesDocs.header))}" items="${encodeURIComponent(jsonStringify(sitesDocs.items))}":
23
- - rtgl-view md-hide xl-show hide w=272:
24
- - rtgl-view w="1fg" ah=c:
25
- - rtgl-view pv="lg" lg-w="100vw" w="720" ph="lg" sv id="content-container":
26
- - rtgl-view hide md-show h=56:
27
- - rtgl-text s="h1" mb="lg": ${title}
28
- - "${content}"
29
- - rtgl-view h=200:
30
- - 'rtgl-view xl-hide style="position: fixed; right: 0"':
31
- - rtgl-page-outline id="page-outline" target-id="content-container" scroll-container-id="window" offset-top="80":
32
-
33
- - script src="/public/mobile-nav.js":
@@ -1,33 +0,0 @@
1
- - html lang="en":
2
- - head:
3
- - $partial: seo1
4
- page: ${page}
5
- seo: ${seo}
6
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/base.css":
7
- - link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/themes/theme-rtgl-slate.css":
8
- - script src="https://cdn.jsdelivr.net/npm/construct-style-sheets-polyfill@3.1.0/dist/adoptedStyleSheets.min.js":
9
- - script src="https://cdn.jsdelivr.net/npm/@rettangoli/ui@1.0.0-rc13/dist/rettangoli-iife-ui.min.js":
10
- - script src="/public/rtgl-icons.js":
11
-
12
- - body.dark:
13
- - $partial: mobile-nav1
14
- headerLabel: ${vtDocs.header.label}
15
- headerHref: ${vtDocs.header.href}
16
- header: ${vtDocs.header}
17
- items: ${vtDocs.items}
18
- sidebarId: ${sidebarId}
19
-
20
- - rtgl-view bgc="bg" w="f" d=h:
21
- - 'rtgl-view md-hide pos=fix h=100vh bgc=bg style="left: 0"':
22
- - rtgl-sidebar selected-item-id=${sidebarId} header="${encodeURIComponent(jsonStringify(vtDocs.header))}" items="${encodeURIComponent(jsonStringify(vtDocs.items))}":
23
- - rtgl-view md-hide xl-show hide w=272:
24
- - rtgl-view w="1fg" ah=c:
25
- - rtgl-view pv="lg" lg-w="100vw" w="720" ph="lg" sv id="content-container":
26
- - rtgl-view hide md-show h=56:
27
- - rtgl-text s="h1" mb="lg": ${title}
28
- - "${content}"
29
- - rtgl-view h=200:
30
- - 'rtgl-view xl-hide style="position: fixed; right: 0"':
31
- - rtgl-page-outline id="page-outline" target-id="content-container" scroll-container-id="window" offset-top="80":
32
-
33
- - script src="/public/mobile-nav.js":