retold-data-service 2.1.2 → 2.1.6

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.
Files changed (84) hide show
  1. package/.github/workflows/publish-image.yml +2 -2
  2. package/BUILDING-AND-PUBLISHING.md +6 -6
  3. package/CONTRIBUTING.md +1 -1
  4. package/Dockerfile +1 -1
  5. package/README.md +12 -27
  6. package/build-all.js +66 -0
  7. package/diagrams/architecture.excalidraw +2966 -0
  8. package/diagrams/architecture.mmd +17 -0
  9. package/diagrams/architecture.svg +2 -0
  10. package/docs/README.md +12 -12
  11. package/docs/_brand.json +18 -0
  12. package/docs/_cover.md +1 -1
  13. package/docs/_topbar.md +1 -1
  14. package/docs/_version.json +3 -3
  15. package/docs/api/reference.md +8 -8
  16. package/docs/architecture.md +6 -84
  17. package/docs/diagrams/component-diagram.excalidraw +2807 -0
  18. package/docs/diagrams/component-diagram.mmd +14 -0
  19. package/docs/diagrams/component-diagram.svg +2 -0
  20. package/docs/diagrams/component-stack.excalidraw +1169 -0
  21. package/docs/diagrams/component-stack.mmd +6 -0
  22. package/docs/diagrams/component-stack.svg +2 -0
  23. package/docs/diagrams/hook-execution-order.excalidraw +3230 -0
  24. package/docs/diagrams/hook-execution-order.mmd +19 -0
  25. package/docs/diagrams/hook-execution-order.svg +2 -0
  26. package/docs/diagrams/initialization-flow.excalidraw +1800 -0
  27. package/docs/diagrams/initialization-flow.mmd +22 -0
  28. package/docs/diagrams/initialization-flow.svg +2 -0
  29. package/docs/index.html +6 -7
  30. package/docs/lifecycle-hooks.md +2 -21
  31. package/docs/retold-catalog.json +141 -141
  32. package/docs/retold-keyword-index.json +6818 -1608
  33. package/package.json +130 -96
  34. package/source/services/RetoldDataService-Brand.js +13 -0
  35. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +65 -15
  36. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +28 -74
  37. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +17 -17
  38. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-SettingsPanel.js +62 -0
  39. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Shell.js +142 -0
  40. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusBar.js +125 -0
  41. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-StatusDetail.js +89 -0
  42. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-Nav.js +42 -0
  43. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-TopBar-User.js +48 -0
  44. package/source/services/comprehension-loader/web/comprehension-loader.js +5517 -6183
  45. package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -1
  46. package/source/services/comprehension-loader/web/comprehension-loader.min.js +75 -1
  47. package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -1
  48. package/source/services/comprehension-loader/web/favicons/favicon-dark.svg +13 -0
  49. package/source/services/comprehension-loader/web/favicons/favicon-light.svg +13 -0
  50. package/source/services/comprehension-loader/web/favicons/favicon.svg +13 -0
  51. package/source/services/comprehension-loader/web/index.html +3 -0
  52. package/source/services/comprehension-loader/web/pict.min.js +12 -0
  53. package/source/services/data-cloner/DataCloner-Command-Headless.js +102 -4
  54. package/source/services/data-cloner/DataCloner-Command-Schema.js +105 -8
  55. package/source/services/data-cloner/DataCloner-Command-Sync.js +111 -75
  56. package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +70 -47
  57. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +3 -3
  58. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +40 -86
  59. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-SettingsPanel.js +61 -0
  60. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Shell.js +136 -0
  61. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusBar.js +117 -0
  62. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-StatusDetail.js +81 -0
  63. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Sync.js +18 -18
  64. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-Nav.js +42 -0
  65. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-TopBar-User.js +48 -0
  66. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-ViewData.js +2 -2
  67. package/source/services/data-cloner/web/data-cloner.js +5874 -7986
  68. package/source/services/data-cloner/web/data-cloner.js.map +1 -1
  69. package/source/services/data-cloner/web/data-cloner.min.js +75 -1
  70. package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
  71. package/source/services/data-cloner/web/favicons/favicon-dark.svg +13 -0
  72. package/source/services/data-cloner/web/favicons/favicon-light.svg +13 -0
  73. package/source/services/data-cloner/web/favicons/favicon.svg +13 -0
  74. package/source/services/data-cloner/web/favicons/favicons/favicon-dark.svg +13 -0
  75. package/source/services/data-cloner/web/favicons/favicons/favicon-light.svg +13 -0
  76. package/source/services/data-cloner/web/favicons/favicons/favicon.svg +13 -0
  77. package/source/services/data-cloner/web/index.html +3 -0
  78. package/source/services/data-cloner/web/pict.min.js +12 -0
  79. package/test/Bundles_smoke_tests.js +43 -0
  80. package/test/ComprehensionLoader_smoke_tests.js +95 -0
  81. package/test/DataCloner-RuntimeOverrides_tests.js +344 -0
  82. package/test/DataCloner_smoke_tests.js +87 -0
  83. package/tools/smoke-converge-endpoint.js +190 -0
  84. package/docs/css/docuserve.css +0 -327
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Live smoke test for the DataCloner index-convergence endpoint.
5
+ *
6
+ * Spawns the REAL data-cloner service and drives the actual HTTP path a headless
7
+ * clone uses: configure connection → fetch schema → deploy → POST
8
+ * /clone/schema/indices/converge → converge again (idempotency). Asserts the
9
+ * operational indexes the policy declares are the ones the endpoint creates,
10
+ * that a table with neither Deleted nor GUID gets none, and that a second run is
11
+ * a no-op. Exercises the provider registry + RetoldDataServiceConnectionManager
12
+ * + IndexPolicy + IndexConvergence together — the production service path.
13
+ *
14
+ * Uses retold's own committed BookStore test model (no external data).
15
+ *
16
+ * Usage: node tools/smoke-converge-endpoint.js [SQLite|MSSQL] [port]
17
+ * SQLite (default): zero infra.
18
+ * MSSQL: runtime-configures the local meadow-connection-mssql-test container
19
+ * (localhost:21433 / sa / db clonesmoke) and adds an independent
20
+ * sqlcmd cross-check + a managed-prune-through-the-endpoint check.
21
+ */
22
+
23
+ const libChildProcess = require('child_process');
24
+ const libHttp = require('http');
25
+ const libPath = require('path');
26
+ const libOs = require('os');
27
+ const libFs = require('fs');
28
+
29
+ const libIndexPolicy = require('meadow-integration/source/services/clone/Meadow-Service-IndexPolicy.js');
30
+
31
+ const PROVIDER = process.argv[2] || 'SQLite';
32
+ const PORT = parseInt(process.argv[3], 10) || 9500;
33
+ const BASE = `http://localhost:${PORT}`;
34
+ const DEPLOY_TABLES = [ 'Book', 'Author', 'BookAuthorJoin' ]; // Book/Author: Deleted+GUID; join: neither
35
+ const MODEL = require('../test/model/MeadowModel-Extended.json');
36
+
37
+ const MSSQL_CONFIG = { server: 'localhost', port: 21433, user: 'sa', password: 'Retold1234567890!', database: 'clonesmoke', ConnectionPoolLimit: 5 };
38
+ const MSSQL_CONTAINER = 'meadow-connection-mssql-test';
39
+ const SQLCMD = '/opt/mssql-tools18/bin/sqlcmd';
40
+
41
+ let _pass = 0, _fail = 0;
42
+ function check(pCondition, pMessage)
43
+ {
44
+ if (pCondition) { _pass++; console.log(`[ok] ${pMessage}`); }
45
+ else { _fail++; console.log(`[fail] ${pMessage}`); }
46
+ }
47
+
48
+ // -- tiny HTTP JSON client (promise) --
49
+ function httpJSON(pMethod, pPath, pBody)
50
+ {
51
+ return new Promise((fResolve, fReject) =>
52
+ {
53
+ let tmpData = pBody ? JSON.stringify(pBody) : null;
54
+ let tmpReq = libHttp.request(`${BASE}${pPath}`,
55
+ { method: pMethod, headers: { 'Content-Type': 'application/json', 'Content-Length': tmpData ? Buffer.byteLength(tmpData) : 0 } },
56
+ (pRes) =>
57
+ {
58
+ let tmpChunks = '';
59
+ pRes.on('data', (pChunk) => { tmpChunks += pChunk; });
60
+ pRes.on('end', () =>
61
+ {
62
+ let tmpParsed;
63
+ try { tmpParsed = tmpChunks ? JSON.parse(tmpChunks) : {}; }
64
+ catch (e) { tmpParsed = { _raw: tmpChunks }; }
65
+ fResolve({ status: pRes.statusCode, body: tmpParsed });
66
+ });
67
+ });
68
+ tmpReq.on('error', fReject);
69
+ if (tmpData) { tmpReq.write(tmpData); }
70
+ tmpReq.end();
71
+ });
72
+ }
73
+
74
+ function sleep(pMs) { return new Promise((r) => setTimeout(r, pMs)); }
75
+
76
+ async function waitForHealth(pTimeoutMs)
77
+ {
78
+ let tmpDeadline = Date.now() + pTimeoutMs;
79
+ while (Date.now() < tmpDeadline)
80
+ {
81
+ try { let r = await httpJSON('GET', '/clone/sync/status', null); if (r.status === 200) { return true; } }
82
+ catch (e) { /* not up yet */ }
83
+ await sleep(250);
84
+ }
85
+ return false;
86
+ }
87
+
88
+ function sqlcmd(pSQL)
89
+ {
90
+ let tmpOut = libChildProcess.execFileSync('docker',
91
+ [ 'exec', MSSQL_CONTAINER, SQLCMD, '-S', 'localhost', '-U', 'sa', '-P', MSSQL_CONFIG.password, '-C', '-d', MSSQL_CONFIG.database, '-h', '-1', '-Q', pSQL ],
92
+ { encoding: 'utf8' });
93
+ return tmpOut;
94
+ }
95
+
96
+ // Expected operational index names for a table, straight from the policy.
97
+ function expectedIndexNames(pTableName)
98
+ {
99
+ return libIndexPolicy.resolveDesiredIndexes(MODEL.Tables[pTableName], {}).map((pIndex) => pIndex.Name);
100
+ }
101
+
102
+ async function main()
103
+ {
104
+ let tmpTempDir = libPath.join(libOs.tmpdir(), `rds-converge-smoke-${PORT}`);
105
+ libFs.rmSync(tmpTempDir, { recursive: true, force: true }); // fresh SQLite file per run
106
+ libFs.mkdirSync(tmpTempDir, { recursive: true });
107
+
108
+ console.log(`Spawning data-cloner on :${PORT} (provider target: ${PROVIDER})...\n`);
109
+ let tmpChild = libChildProcess.spawn('node',
110
+ [ libPath.resolve(__dirname, '..', 'bin', 'retold-data-service-clone.js'), '--port', String(PORT) ],
111
+ { cwd: tmpTempDir, env: process.env, stdio: [ 'ignore', 'ignore', 'pipe' ] });
112
+ let tmpStderr = '';
113
+ tmpChild.stderr.on('data', (d) => { tmpStderr += d.toString(); });
114
+
115
+ try
116
+ {
117
+ let tmpHealthy = await waitForHealth(20000);
118
+ check(tmpHealthy, 'service came up healthy (GET /clone/sync/status)');
119
+ if (!tmpHealthy) { if (tmpStderr) { console.log('--- stderr ---\n' + tmpStderr.slice(-1200)); } return; }
120
+
121
+ // -- (MSSQL only) fresh DB + runtime-configure the connection --
122
+ if (PROVIDER === 'MSSQL')
123
+ {
124
+ libChildProcess.execFileSync('docker', [ 'exec', MSSQL_CONTAINER, SQLCMD, '-S', 'localhost', '-U', 'sa', '-P', MSSQL_CONFIG.password, '-C', '-Q',
125
+ "IF DB_ID('clonesmoke') IS NOT NULL BEGIN ALTER DATABASE clonesmoke SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE clonesmoke; END; CREATE DATABASE clonesmoke;" ], { encoding: 'utf8' });
126
+ let tmpCfg = await httpJSON('POST', '/clone/connection/configure', { Provider: 'MSSQL', Config: MSSQL_CONFIG });
127
+ check(tmpCfg.status === 200 && tmpCfg.body.Success, 'configured MSSQL connection');
128
+ let tmpStatus = await httpJSON('GET', '/clone/connection/status', null);
129
+ check(tmpStatus.body.Provider === 'MSSQL', `active provider is MSSQL (got ${tmpStatus.body.Provider})`);
130
+ }
131
+
132
+ // -- fetch (raw schema object) → deploy --
133
+ let tmpFetch = await httpJSON('POST', '/clone/schema/fetch', { Schema: MODEL });
134
+ check(tmpFetch.status === 200 && tmpFetch.body.Success, `fetched schema (${tmpFetch.body.TableCount} tables)`);
135
+
136
+ let tmpDeploy = await httpJSON('POST', '/clone/schema/deploy', { Tables: DEPLOY_TABLES });
137
+ check(tmpDeploy.status === 200 && tmpDeploy.body.Success, 'deployed tables');
138
+ check(DEPLOY_TABLES.every((t) => (tmpDeploy.body.TablesDeployed || []).indexOf(t) > -1), `all ${DEPLOY_TABLES.length} tables deployed [${(tmpDeploy.body.TablesDeployed || []).join(', ')}]`);
139
+
140
+ // -- converge #1 --
141
+ let tmpConv1 = await httpJSON('POST', '/clone/schema/indices/converge', { Tables: DEPLOY_TABLES, IndexPolicy: { PruneScope: 'managed' } });
142
+ check(tmpConv1.status === 200 && tmpConv1.body.Success, 'converge #1 succeeded');
143
+
144
+ let tmpAllCreated = (tmpConv1.body.Results || []).reduce((pAcc, pR) => pAcc.concat(pR.created || []), []);
145
+ let tmpExpected = DEPLOY_TABLES.reduce((pAcc, t) => pAcc.concat(expectedIndexNames(t)), []);
146
+ console.log(` created: [${tmpAllCreated.join(', ')}]`);
147
+ check(tmpExpected.every((n) => tmpAllCreated.indexOf(n) > -1), `all policy-declared indexes created [${tmpExpected.join(', ')}]`);
148
+ check(tmpAllCreated.length === tmpExpected.length && tmpAllCreated.slice().sort().join(',') === tmpExpected.slice().sort().join(','),
149
+ `created set exactly matches the policy (${tmpAllCreated.length} indexes, no extras)`);
150
+ // Deleted-gated composite: BookAuthorJoin has a GUID column but no Deleted →
151
+ // it should get the GUID lookup index but NO (Deleted, ID) composite.
152
+ check(tmpAllCreated.indexOf('IX_M_SYNC_BookAuthorJoin_GUIDBookAuthorJoin') > -1, 'GUID-only join table got its GUID index');
153
+ check(!tmpAllCreated.some((n) => n.indexOf('IX_M_SYNC_BookAuthorJoin_Deleted_') === 0), 'GUID-only join table got NO composite (composite correctly gated on Deleted)');
154
+
155
+ // -- converge #2 (idempotency) --
156
+ let tmpConv2 = await httpJSON('POST', '/clone/schema/indices/converge', { Tables: DEPLOY_TABLES, IndexPolicy: { PruneScope: 'managed' } });
157
+ let tmpCreated2 = (tmpConv2.body.Results || []).reduce((pAcc, pR) => pAcc + (pR.created || []).length, 0);
158
+ let tmpDropped2 = (tmpConv2.body.Results || []).reduce((pAcc, pR) => pAcc + (pR.dropped || []).length, 0);
159
+ check(tmpConv2.body.Success && tmpCreated2 === 0 && tmpDropped2 === 0, `idempotent — converge #2 created ${tmpCreated2}, dropped ${tmpDropped2}`);
160
+
161
+ // -- MSSQL: independent sqlcmd cross-check + managed-prune-through-the-endpoint --
162
+ if (PROVIDER === 'MSSQL')
163
+ {
164
+ let tmpIdxRows = sqlcmd("SET NOCOUNT ON; SELECT i.name + '|' + CAST(i.is_unique AS VARCHAR) FROM sys.indexes i JOIN sys.tables t ON t.object_id=i.object_id WHERE t.name='Book' AND i.type>0 AND i.is_primary_key=0;");
165
+ let tmpNames = tmpIdxRows.split('\n').map((s) => s.trim()).filter(Boolean);
166
+ check(tmpNames.some((r) => r.startsWith('IX_M_SYNC_Book_Deleted_') && r.endsWith('|0')), `sqlcmd: Book composite present + NON-unique (${tmpNames.join(' ')})`);
167
+ check(tmpNames.some((r) => r === 'IX_M_SYNC_Book_GUIDBook|0'), 'sqlcmd: Book GUID index present + NON-unique');
168
+
169
+ // Seed a precursor [Deleted] single-column index out-of-band, then converge
170
+ // again — managed prune should drop it (it names a column) via the endpoint.
171
+ sqlcmd("IF NOT EXISTS(SELECT * FROM sys.indexes WHERE name='Deleted' AND object_id=OBJECT_ID('dbo.Book')) CREATE INDEX [Deleted] ON [dbo].[Book]([Deleted]);");
172
+ let tmpConv3 = await httpJSON('POST', '/clone/schema/indices/converge', { Tables: [ 'Book' ], IndexPolicy: { PruneScope: 'managed' } });
173
+ let tmpDropped3 = (tmpConv3.body.Results || []).reduce((pAcc, pR) => pAcc.concat(pR.dropped || []), []);
174
+ check(tmpConv3.body.Success && tmpDropped3.indexOf('Deleted') > -1, `managed prune via endpoint dropped precursor [Deleted] (dropped: [${tmpDropped3.join(', ')}])`);
175
+ let tmpAfter = sqlcmd("SET NOCOUNT ON; SELECT name FROM sys.indexes WHERE object_id=OBJECT_ID('dbo.Book') AND type>0 AND is_primary_key=0;").split('\n').map((s) => s.trim()).filter(Boolean);
176
+ check(tmpAfter.indexOf('Deleted') === -1 && tmpAfter.some((n) => n.indexOf('IX_M_SYNC_Book') === 0), `sqlcmd: precursor gone, operational indexes remain [${tmpAfter.join(', ')}]`);
177
+ }
178
+ }
179
+ finally
180
+ {
181
+ tmpChild.kill('SIGTERM');
182
+ await sleep(300);
183
+ try { tmpChild.kill('SIGKILL'); } catch (e) {}
184
+ }
185
+
186
+ console.log(`\n──────── ${_pass} ok, ${_fail} fail (${PROVIDER}) ────────`);
187
+ process.exit(_fail > 0 ? 1 : 0);
188
+ }
189
+
190
+ main().catch((pErr) => { console.error('harness error:', pErr); process.exit(2); });
@@ -1,327 +0,0 @@
1
- /* ============================================================================
2
- Pict Docuserve - Base Styles & Theme Variables
3
- ============================================================================ */
4
-
5
- /* ----------------------------------------------------------------------------
6
- Theme variables — light defaults on :root.
7
- Dark mode applies when either:
8
- (a) the user explicitly selected dark via <html data-theme="dark">
9
- (b) the user hasn't chosen anything AND the system prefers dark
10
- An explicit <html data-theme="light"> pins the light palette regardless.
11
- ---------------------------------------------------------------------------- */
12
-
13
- :root
14
- {
15
- /* Surfaces */
16
- --docuserve-bg: #FDFBF7;
17
- --docuserve-bg-elevated: #FFFFFF;
18
- --docuserve-border: #DDD6CA;
19
- --docuserve-border-soft: #EAE3D8;
20
-
21
- /* Text */
22
- --docuserve-text: #2A241E;
23
- --docuserve-text-strong: #3D3229;
24
- --docuserve-text-muted: #5E5549;
25
- --docuserve-text-dim: #8A7F72;
26
-
27
- /* Accent / links */
28
- --docuserve-accent: #2E7D74;
29
- --docuserve-accent-hover: #236660;
30
-
31
- /* Top bar */
32
- --docuserve-topbar-bg: #3D3229;
33
- --docuserve-topbar-text: #E8E0D4;
34
- --docuserve-topbar-text-muted: #B5AA9A;
35
- --docuserve-topbar-text-dim: #8A7F72;
36
- --docuserve-topbar-hover-bg: #524438;
37
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.06);
38
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.08);
39
- --docuserve-topbar-version-text: #B5AA9A;
40
-
41
- /* Sidebar */
42
- --docuserve-sidebar-bg: #FAF7F1;
43
- --docuserve-sidebar-border: #DDD6CA;
44
- --docuserve-sidebar-border-soft: #E5DED1;
45
- --docuserve-sidebar-text: #423D37;
46
- --docuserve-sidebar-group-title: #3D3229;
47
- --docuserve-sidebar-module-text: #5E5549;
48
- --docuserve-sidebar-hover-bg: #EAE3D8;
49
- --docuserve-sidebar-hover-text: #2E7D74;
50
- --docuserve-sidebar-active-bg: #E5DED1;
51
- --docuserve-sidebar-active-text: #2E7D74;
52
- --docuserve-sidebar-search-bg: #FFFFFF;
53
- --docuserve-sidebar-search-border: #DDD6CA;
54
-
55
- /* Inline code */
56
- --docuserve-inline-code-bg: #F0ECE4;
57
- --docuserve-inline-code-text: #9E3A50;
58
-
59
- /* Code block panel */
60
- --docuserve-code-bg: #F6F3EE;
61
- --docuserve-code-border: #E5DED1;
62
- --docuserve-code-gutter-bg: #EFEAE0;
63
- --docuserve-code-gutter-border: #DDD6CA;
64
- --docuserve-code-gutter-text: #A59986;
65
- --docuserve-code-text: #2A241E;
66
-
67
- /* Syntax tokens — low-chroma dark-on-light palette */
68
- --docuserve-tok-keyword: #A03472;
69
- --docuserve-tok-string: #1A6640;
70
- --docuserve-tok-number: #B25A00;
71
- --docuserve-tok-comment: #8A7F72;
72
- --docuserve-tok-operator: #2E7D74;
73
- --docuserve-tok-punctuation: #2A241E;
74
- --docuserve-tok-function: #2A5DB0;
75
- --docuserve-tok-property: #9E3A50;
76
- --docuserve-tok-tag: #9E3A50;
77
- --docuserve-tok-attr-name: #B25A00;
78
- --docuserve-tok-attr-value: #1A6640;
79
-
80
- /* Tables, blockquotes, mermaid */
81
- --docuserve-table-header-bg: #F5F0E8;
82
- --docuserve-table-row-alt-bg: #F9F6F0;
83
- --docuserve-blockquote-bg: #F7F5F0;
84
- --docuserve-blockquote-border: #2E7D74;
85
- --docuserve-blockquote-text: #5E5549;
86
- --docuserve-mermaid-bg: #FFFFFF;
87
-
88
- /* Scrollbars */
89
- --docuserve-scrollbar-track: #F5F0E8;
90
- --docuserve-scrollbar-thumb: #D4CCBE;
91
- --docuserve-scrollbar-thumb-hover: #B5AA9A;
92
- }
93
-
94
- @media (prefers-color-scheme: dark)
95
- {
96
- :root:not([data-theme="light"])
97
- {
98
- --docuserve-bg: #15120F;
99
- --docuserve-bg-elevated: #1B1814;
100
- --docuserve-border: #2F2823;
101
- --docuserve-border-soft: #26211C;
102
-
103
- --docuserve-text: #E8E0D4;
104
- --docuserve-text-strong: #F2ECE0;
105
- --docuserve-text-muted: #B5AA9A;
106
- --docuserve-text-dim: #7A6F62;
107
-
108
- --docuserve-accent: #5DB8A8;
109
- --docuserve-accent-hover: #7FCCB8;
110
-
111
- --docuserve-topbar-bg: #1A1612;
112
- --docuserve-topbar-text: #E8E0D4;
113
- --docuserve-topbar-text-muted: #B5AA9A;
114
- --docuserve-topbar-text-dim: #7A6F62;
115
- --docuserve-topbar-hover-bg: #2A241E;
116
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
117
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
118
- --docuserve-topbar-version-text: #B5AA9A;
119
-
120
- --docuserve-sidebar-bg: #1B1814;
121
- --docuserve-sidebar-border: #2F2823;
122
- --docuserve-sidebar-border-soft: #26211C;
123
- --docuserve-sidebar-text: #C9C0B3;
124
- --docuserve-sidebar-group-title: #F2ECE0;
125
- --docuserve-sidebar-module-text: #B5AA9A;
126
- --docuserve-sidebar-hover-bg: #2A241E;
127
- --docuserve-sidebar-hover-text: #7FCCB8;
128
- --docuserve-sidebar-active-bg: #2F2823;
129
- --docuserve-sidebar-active-text: #7FCCB8;
130
- --docuserve-sidebar-search-bg: #26211C;
131
- --docuserve-sidebar-search-border: #2F2823;
132
-
133
- --docuserve-inline-code-bg: #2A241E;
134
- --docuserve-inline-code-text: #E8B07A;
135
-
136
- --docuserve-code-bg: #1E1A17;
137
- --docuserve-code-border: #2F2823;
138
- --docuserve-code-gutter-bg: #17130F;
139
- --docuserve-code-gutter-border: #2F2823;
140
- --docuserve-code-gutter-text: #6A6052;
141
- --docuserve-code-text: #E8E0D4;
142
-
143
- --docuserve-tok-keyword: #C678DD;
144
- --docuserve-tok-string: #98C379;
145
- --docuserve-tok-number: #D19A66;
146
- --docuserve-tok-comment: #7F848E;
147
- --docuserve-tok-operator: #56B6C2;
148
- --docuserve-tok-punctuation: #E8E0D4;
149
- --docuserve-tok-function: #61AFEF;
150
- --docuserve-tok-property: #E06C75;
151
- --docuserve-tok-tag: #E06C75;
152
- --docuserve-tok-attr-name: #D19A66;
153
- --docuserve-tok-attr-value: #98C379;
154
-
155
- --docuserve-table-header-bg: #26211C;
156
- --docuserve-table-row-alt-bg: #1F1B17;
157
- --docuserve-blockquote-bg: #1F1B17;
158
- --docuserve-blockquote-border: #5DB8A8;
159
- --docuserve-blockquote-text: #C9C0B3;
160
- --docuserve-mermaid-bg: #E8E0D4;
161
-
162
- --docuserve-scrollbar-track: #1B1814;
163
- --docuserve-scrollbar-thumb: #3A322B;
164
- --docuserve-scrollbar-thumb-hover: #524438;
165
- }
166
- }
167
-
168
- :root[data-theme="dark"]
169
- {
170
- --docuserve-bg: #15120F;
171
- --docuserve-bg-elevated: #1B1814;
172
- --docuserve-border: #2F2823;
173
- --docuserve-border-soft: #26211C;
174
-
175
- --docuserve-text: #E8E0D4;
176
- --docuserve-text-strong: #F2ECE0;
177
- --docuserve-text-muted: #B5AA9A;
178
- --docuserve-text-dim: #7A6F62;
179
-
180
- --docuserve-accent: #5DB8A8;
181
- --docuserve-accent-hover: #7FCCB8;
182
-
183
- --docuserve-topbar-bg: #1A1612;
184
- --docuserve-topbar-text: #E8E0D4;
185
- --docuserve-topbar-text-muted: #B5AA9A;
186
- --docuserve-topbar-text-dim: #7A6F62;
187
- --docuserve-topbar-hover-bg: #2A241E;
188
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
189
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
190
- --docuserve-topbar-version-text: #B5AA9A;
191
-
192
- --docuserve-sidebar-bg: #1B1814;
193
- --docuserve-sidebar-border: #2F2823;
194
- --docuserve-sidebar-border-soft: #26211C;
195
- --docuserve-sidebar-text: #C9C0B3;
196
- --docuserve-sidebar-group-title: #F2ECE0;
197
- --docuserve-sidebar-module-text: #B5AA9A;
198
- --docuserve-sidebar-hover-bg: #2A241E;
199
- --docuserve-sidebar-hover-text: #7FCCB8;
200
- --docuserve-sidebar-active-bg: #2F2823;
201
- --docuserve-sidebar-active-text: #7FCCB8;
202
- --docuserve-sidebar-search-bg: #26211C;
203
- --docuserve-sidebar-search-border: #2F2823;
204
-
205
- --docuserve-inline-code-bg: #2A241E;
206
- --docuserve-inline-code-text: #E8B07A;
207
-
208
- --docuserve-code-bg: #1E1A17;
209
- --docuserve-code-border: #2F2823;
210
- --docuserve-code-gutter-bg: #17130F;
211
- --docuserve-code-gutter-border: #2F2823;
212
- --docuserve-code-gutter-text: #6A6052;
213
- --docuserve-code-text: #E8E0D4;
214
-
215
- --docuserve-tok-keyword: #C678DD;
216
- --docuserve-tok-string: #98C379;
217
- --docuserve-tok-number: #D19A66;
218
- --docuserve-tok-comment: #7F848E;
219
- --docuserve-tok-operator: #56B6C2;
220
- --docuserve-tok-punctuation: #E8E0D4;
221
- --docuserve-tok-function: #61AFEF;
222
- --docuserve-tok-property: #E06C75;
223
- --docuserve-tok-tag: #E06C75;
224
- --docuserve-tok-attr-name: #D19A66;
225
- --docuserve-tok-attr-value: #98C379;
226
-
227
- --docuserve-table-header-bg: #26211C;
228
- --docuserve-table-row-alt-bg: #1F1B17;
229
- --docuserve-blockquote-bg: #1F1B17;
230
- --docuserve-blockquote-border: #5DB8A8;
231
- --docuserve-blockquote-text: #C9C0B3;
232
- --docuserve-mermaid-bg: #E8E0D4;
233
-
234
- --docuserve-scrollbar-track: #1B1814;
235
- --docuserve-scrollbar-thumb: #3A322B;
236
- --docuserve-scrollbar-thumb-hover: #524438;
237
- }
238
-
239
- /* ----------------------------------------------------------------------------
240
- Reset and base
241
- ---------------------------------------------------------------------------- */
242
-
243
- *, *::before, *::after
244
- {
245
- box-sizing: border-box;
246
- }
247
-
248
- html, body
249
- {
250
- margin: 0;
251
- padding: 0;
252
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
253
- font-size: 16px;
254
- line-height: 1.5;
255
- color: var(--docuserve-text);
256
- background-color: var(--docuserve-bg);
257
- -webkit-font-smoothing: antialiased;
258
- -moz-osx-font-smoothing: grayscale;
259
- transition: background-color 0.15s ease, color 0.15s ease;
260
- }
261
-
262
- /* Typography */
263
- h1, h2, h3, h4, h5, h6
264
- {
265
- margin-top: 0;
266
- line-height: 1.3;
267
- color: var(--docuserve-text-strong);
268
- }
269
-
270
- a
271
- {
272
- color: var(--docuserve-accent);
273
- text-decoration: none;
274
- }
275
-
276
- a:hover
277
- {
278
- color: var(--docuserve-accent-hover);
279
- }
280
-
281
- /* Application container */
282
- #Docuserve-Application-Container
283
- {
284
- min-height: 100vh;
285
- }
286
-
287
- /* Utility: scrollbar styling */
288
- ::-webkit-scrollbar
289
- {
290
- width: 8px;
291
- height: 8px;
292
- }
293
-
294
- ::-webkit-scrollbar-track
295
- {
296
- background: var(--docuserve-scrollbar-track);
297
- }
298
-
299
- ::-webkit-scrollbar-thumb
300
- {
301
- background: var(--docuserve-scrollbar-thumb);
302
- border-radius: 4px;
303
- }
304
-
305
- ::-webkit-scrollbar-thumb:hover
306
- {
307
- background: var(--docuserve-scrollbar-thumb-hover);
308
- }
309
-
310
- /* Responsive adjustments */
311
- @media (max-width: 768px)
312
- {
313
- html
314
- {
315
- font-size: 14px;
316
- }
317
-
318
- #Docuserve-Sidebar-Container
319
- {
320
- display: none;
321
- }
322
-
323
- .docuserve-body
324
- {
325
- flex-direction: column;
326
- }
327
- }