@21stware/rpui 0.4.3 → 0.5.4
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/dist/core/live-render.d.ts +6 -0
- package/dist/core/theme.d.ts +6 -0
- package/dist/gallery.d.ts +4 -1
- package/dist/gallery.js +253 -87
- package/dist/gallery.js.map +1 -1
- package/dist/rpml-loader.js +70 -0
- package/dist/rpml-loader.js.map +1 -1
- package/dist/rpui.d.ts +2 -1
- package/dist/rpui.js +29 -0
- package/dist/rpui.js.map +1 -1
- package/dist/serve.js +48 -8
- package/package.json +2 -4
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const THEME_CSS = "\n:root {\n --rpml-gx-border:#e5e7eb; --rpml-gx-side-bg:#fff; --rpml-gx-main-bg:#f4f6f8;\n --rpml-gx-fg:#111827; --rpml-gx-muted:#6b7280; --rpml-gx-group:#9ca3af;\n --rpml-gx-hover:#f3f4f6; --rpml-gx-item:#374151; --rpml-gx-active-bg:#eff6ff;\n --rpml-gx-active-fg:#1d4ed8; --rpml-gx-copy-hover:#e5e7eb; --rpml-gx-ok:#059669;\n}\nhtml[data-rpml-theme=\"dark\"] {\n --rpml-gx-border:#2a3344; --rpml-gx-side-bg:#0f172a; --rpml-gx-main-bg:#0b1120;\n --rpml-gx-fg:#e2e8f0; --rpml-gx-muted:#94a3b8; --rpml-gx-group:#64748b;\n --rpml-gx-hover:#1e293b; --rpml-gx-item:#cbd5e1; --rpml-gx-active-bg:#1e3a5f;\n --rpml-gx-active-fg:#93c5fd; --rpml-gx-copy-hover:#334155; --rpml-gx-ok:#34d399;\n}\nhtml[data-rpml-theme=\"dark\"] body { background:#0b1120; }\n/* Invert the rendered prototype as a whole; hue-rotate keeps colors recognizable. */\nhtml[data-rpml-theme=\"dark\"] page-el { filter:invert(0.92) hue-rotate(180deg); }\n\n.rpml-theme-fab {\n position:fixed; top:12px; right:12px; z-index:50; display:flex; align-items:center;\n justify-content:center; width:34px; height:34px; padding:0; border:1px solid var(--rpml-gx-border);\n border-radius:9px; background:var(--rpml-gx-side-bg); color:var(--rpml-gx-fg); font-size:16px;\n line-height:1; cursor:pointer; box-shadow:0 1px 3px rgba(0,0,0,.12);\n}\n.rpml-theme-fab:hover { background:var(--rpml-gx-hover); }\n";
|
|
2
|
+
export declare function injectThemeStyle(): void;
|
|
3
|
+
export declare function currentTheme(): 'light' | 'dark';
|
|
4
|
+
export declare function setTheme(theme: 'light' | 'dark'): void;
|
|
5
|
+
export declare function initTheme(): void;
|
|
6
|
+
export declare function mountThemeFab(host?: HTMLElement): void;
|
package/dist/gallery.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ export interface RpmlDoc {
|
|
|
2
2
|
path: string;
|
|
3
3
|
source: string;
|
|
4
4
|
}
|
|
5
|
-
export
|
|
5
|
+
export interface GalleryController {
|
|
6
|
+
update(newDocs: RpmlDoc[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function mountGallery(docs: RpmlDoc[], host?: HTMLElement): GalleryController;
|
package/dist/gallery.js
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
function attr(el, name, fallback = "") {
|
|
5
|
+
return el.getAttribute(name) ?? fallback;
|
|
6
|
+
}
|
|
7
|
+
function intAttr(el, name, fallback) {
|
|
8
|
+
const raw = el.getAttribute(name);
|
|
9
|
+
const value = raw === null || raw === "" ? NaN : Number(raw);
|
|
10
|
+
return Number.isFinite(value) ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
function escapeHtml(value) {
|
|
13
|
+
return value.replace(/[&<>'"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[c] || c);
|
|
14
|
+
}
|
|
15
|
+
function csv(el, name, fallback) {
|
|
16
|
+
return attr(el, name, fallback).split(",").map((s) => s.trim()).filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
const deviceWidths = { web: 1440, ipad: 834, mobile: 390 };
|
|
19
|
+
function resolveWidth(el, fallback) {
|
|
20
|
+
const raw = el.getAttribute("width");
|
|
21
|
+
const width = raw === null || raw === "" ? NaN : Number(raw);
|
|
22
|
+
if (Number.isFinite(width)) return width;
|
|
23
|
+
return deviceWidths[attr(el, "device")] ?? fallback;
|
|
24
|
+
}
|
|
25
|
+
function hasExplicitNumericHeight(el) {
|
|
26
|
+
const raw = el.getAttribute("height");
|
|
27
|
+
return raw !== null && raw !== "" && Number.isFinite(Number(raw));
|
|
28
|
+
}
|
|
29
|
+
function usesAutoHeight(el) {
|
|
30
|
+
const raw = el.getAttribute("height");
|
|
31
|
+
return raw === "auto" || el.hasAttribute("auto-height") || !!el.getAttribute("device") && !hasExplicitNumericHeight(el);
|
|
32
|
+
}
|
|
33
|
+
function resolveHeight(el, fallback) {
|
|
34
|
+
const raw = el.getAttribute("height");
|
|
35
|
+
const height = raw === null || raw === "" ? NaN : Number(raw);
|
|
36
|
+
return Number.isFinite(height) ? height : fallback;
|
|
37
|
+
}
|
|
38
|
+
function isTopAnnotation(node) {
|
|
39
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
40
|
+
const tag = node.tagName.toLowerCase();
|
|
41
|
+
return tag === "annotation-el" || tag === "annotation-el";
|
|
42
|
+
}
|
|
43
|
+
function isGlobalAnnotation(node) {
|
|
44
|
+
return node instanceof HTMLElement && node.tagName.toLowerCase() === "annotation-global-el";
|
|
45
|
+
}
|
|
46
|
+
function isViewportNode(node) {
|
|
47
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
48
|
+
const tag = node.tagName.toLowerCase();
|
|
49
|
+
return tag === "viewport-el" || tag === "viewport-el";
|
|
50
|
+
}
|
|
51
|
+
function define(name, ctor) {
|
|
52
|
+
if (customElements.get(name)) return;
|
|
53
|
+
const Alias = class extends ctor {
|
|
54
|
+
};
|
|
55
|
+
customElements.define(name, Alias);
|
|
56
|
+
}
|
|
4
57
|
const PRIMITIVES = [
|
|
5
58
|
// layout
|
|
6
59
|
"viewport",
|
|
@@ -187,59 +240,6 @@ function parseToPage(source) {
|
|
|
187
240
|
if (!root) throw new Error("RPML parse error: no <page> root element found");
|
|
188
241
|
return root;
|
|
189
242
|
}
|
|
190
|
-
function attr(el, name, fallback = "") {
|
|
191
|
-
return el.getAttribute(name) ?? fallback;
|
|
192
|
-
}
|
|
193
|
-
function intAttr(el, name, fallback) {
|
|
194
|
-
const raw = el.getAttribute(name);
|
|
195
|
-
const value = raw === null || raw === "" ? NaN : Number(raw);
|
|
196
|
-
return Number.isFinite(value) ? value : fallback;
|
|
197
|
-
}
|
|
198
|
-
function escapeHtml(value) {
|
|
199
|
-
return value.replace(/[&<>'"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[c] || c);
|
|
200
|
-
}
|
|
201
|
-
function csv(el, name, fallback) {
|
|
202
|
-
return attr(el, name, fallback).split(",").map((s) => s.trim()).filter(Boolean);
|
|
203
|
-
}
|
|
204
|
-
const deviceWidths = { web: 1440, ipad: 834, mobile: 390 };
|
|
205
|
-
function resolveWidth(el, fallback) {
|
|
206
|
-
const raw = el.getAttribute("width");
|
|
207
|
-
const width = raw === null || raw === "" ? NaN : Number(raw);
|
|
208
|
-
if (Number.isFinite(width)) return width;
|
|
209
|
-
return deviceWidths[attr(el, "device")] ?? fallback;
|
|
210
|
-
}
|
|
211
|
-
function hasExplicitNumericHeight(el) {
|
|
212
|
-
const raw = el.getAttribute("height");
|
|
213
|
-
return raw !== null && raw !== "" && Number.isFinite(Number(raw));
|
|
214
|
-
}
|
|
215
|
-
function usesAutoHeight(el) {
|
|
216
|
-
const raw = el.getAttribute("height");
|
|
217
|
-
return raw === "auto" || el.hasAttribute("auto-height") || !!el.getAttribute("device") && !hasExplicitNumericHeight(el);
|
|
218
|
-
}
|
|
219
|
-
function resolveHeight(el, fallback) {
|
|
220
|
-
const raw = el.getAttribute("height");
|
|
221
|
-
const height = raw === null || raw === "" ? NaN : Number(raw);
|
|
222
|
-
return Number.isFinite(height) ? height : fallback;
|
|
223
|
-
}
|
|
224
|
-
function isTopAnnotation(node) {
|
|
225
|
-
if (!(node instanceof HTMLElement)) return false;
|
|
226
|
-
const tag = node.tagName.toLowerCase();
|
|
227
|
-
return tag === "annotation-el" || tag === "annotation-el";
|
|
228
|
-
}
|
|
229
|
-
function isGlobalAnnotation(node) {
|
|
230
|
-
return node instanceof HTMLElement && node.tagName.toLowerCase() === "annotation-global-el";
|
|
231
|
-
}
|
|
232
|
-
function isViewportNode(node) {
|
|
233
|
-
if (!(node instanceof HTMLElement)) return false;
|
|
234
|
-
const tag = node.tagName.toLowerCase();
|
|
235
|
-
return tag === "viewport-el" || tag === "viewport-el";
|
|
236
|
-
}
|
|
237
|
-
function define(name, ctor) {
|
|
238
|
-
if (customElements.get(name)) return;
|
|
239
|
-
const Alias = class extends ctor {
|
|
240
|
-
};
|
|
241
|
-
customElements.define(name, Alias);
|
|
242
|
-
}
|
|
243
243
|
const RPUI_STYLE_ID = "rpui-runtime-style";
|
|
244
244
|
const style = `
|
|
245
245
|
:root { --rp-bg:#f0f2f5; --rp-surface:#fff; --rp-surface-soft:#f9fafb; --rp-text:#111827; --rp-muted:#6b7280; --rp-border:#e5e7eb; --rp-border-strong:#d1d5db; --rp-primary:#2563eb; --rp-success:#059669; --rp-warning:#d97706; --rp-danger:#dc2626; --rp-purple:#7c3aed; --rp-radius-sm:4px; --rp-radius-md:8px; --rp-radius-lg:12px; --rp-shadow:0 8px 28px rgba(15,23,42,.08); --rp-font:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
|
|
@@ -868,6 +868,10 @@ class RpAnnotationGlobal extends HTMLElement {
|
|
|
868
868
|
this.dataset.rpReady = "true";
|
|
869
869
|
const existing = Array.from(this.childNodes);
|
|
870
870
|
const label = attr(this, "label", "全局说明");
|
|
871
|
+
const globalSiblings = this.parentElement ? Array.from(this.parentElement.children).filter(
|
|
872
|
+
(el) => el.tagName.toLowerCase() === "annotation-global-el"
|
|
873
|
+
) : [];
|
|
874
|
+
this.dataset.rpSection = `global-${globalSiblings.indexOf(this) + 1}`;
|
|
871
875
|
const marker = document.createElement("span");
|
|
872
876
|
marker.className = "annotation-el-marker global";
|
|
873
877
|
marker.innerHTML = "<span>★</span>";
|
|
@@ -99580,30 +99584,118 @@ function registerAll() {
|
|
|
99580
99584
|
define(toComponentTag(suffix), ctor);
|
|
99581
99585
|
}
|
|
99582
99586
|
}
|
|
99587
|
+
function liveRender(host, source, opts = {}) {
|
|
99588
|
+
const { scroller, preserve = true, onError } = opts;
|
|
99589
|
+
const sc = scroller ?? document.scrollingElement ?? document.documentElement;
|
|
99590
|
+
const pane = preserve ? host.querySelector(".annotation-el-pane") : null;
|
|
99591
|
+
const pos = preserve ? { x: sc.scrollLeft, y: sc.scrollTop, px: (pane == null ? void 0 : pane.scrollLeft) ?? 0, py: (pane == null ? void 0 : pane.scrollTop) ?? 0 } : null;
|
|
99592
|
+
try {
|
|
99593
|
+
host.replaceChildren(parseToPage(source));
|
|
99594
|
+
onError == null ? void 0 : onError(null);
|
|
99595
|
+
} catch (e) {
|
|
99596
|
+
onError == null ? void 0 : onError(e.message ?? String(e));
|
|
99597
|
+
return;
|
|
99598
|
+
}
|
|
99599
|
+
if (pos) {
|
|
99600
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
99601
|
+
sc.scrollLeft = pos.x;
|
|
99602
|
+
sc.scrollTop = pos.y;
|
|
99603
|
+
const newPane = host.querySelector(".annotation-el-pane");
|
|
99604
|
+
if (newPane) {
|
|
99605
|
+
newPane.scrollLeft = pos.px;
|
|
99606
|
+
newPane.scrollTop = pos.py;
|
|
99607
|
+
}
|
|
99608
|
+
}));
|
|
99609
|
+
}
|
|
99610
|
+
}
|
|
99583
99611
|
registerAll();
|
|
99612
|
+
const THEME_STYLE_ID = "rpml-theme-style";
|
|
99613
|
+
const ATTR = "data-rpml-theme";
|
|
99614
|
+
const THEME_CSS = `
|
|
99615
|
+
:root {
|
|
99616
|
+
--rpml-gx-border:#e5e7eb; --rpml-gx-side-bg:#fff; --rpml-gx-main-bg:#f4f6f8;
|
|
99617
|
+
--rpml-gx-fg:#111827; --rpml-gx-muted:#6b7280; --rpml-gx-group:#9ca3af;
|
|
99618
|
+
--rpml-gx-hover:#f3f4f6; --rpml-gx-item:#374151; --rpml-gx-active-bg:#eff6ff;
|
|
99619
|
+
--rpml-gx-active-fg:#1d4ed8; --rpml-gx-copy-hover:#e5e7eb; --rpml-gx-ok:#059669;
|
|
99620
|
+
}
|
|
99621
|
+
html[${ATTR}="dark"] {
|
|
99622
|
+
--rpml-gx-border:#2a3344; --rpml-gx-side-bg:#0f172a; --rpml-gx-main-bg:#0b1120;
|
|
99623
|
+
--rpml-gx-fg:#e2e8f0; --rpml-gx-muted:#94a3b8; --rpml-gx-group:#64748b;
|
|
99624
|
+
--rpml-gx-hover:#1e293b; --rpml-gx-item:#cbd5e1; --rpml-gx-active-bg:#1e3a5f;
|
|
99625
|
+
--rpml-gx-active-fg:#93c5fd; --rpml-gx-copy-hover:#334155; --rpml-gx-ok:#34d399;
|
|
99626
|
+
}
|
|
99627
|
+
html[${ATTR}="dark"] body { background:#0b1120; }
|
|
99628
|
+
/* Invert the rendered prototype as a whole; hue-rotate keeps colors recognizable. */
|
|
99629
|
+
html[${ATTR}="dark"] page-el { filter:invert(0.92) hue-rotate(180deg); }
|
|
99630
|
+
|
|
99631
|
+
.rpml-theme-fab {
|
|
99632
|
+
position:fixed; top:12px; right:12px; z-index:50; display:flex; align-items:center;
|
|
99633
|
+
justify-content:center; width:34px; height:34px; padding:0; border:1px solid var(--rpml-gx-border);
|
|
99634
|
+
border-radius:9px; background:var(--rpml-gx-side-bg); color:var(--rpml-gx-fg); font-size:16px;
|
|
99635
|
+
line-height:1; cursor:pointer; box-shadow:0 1px 3px rgba(0,0,0,.12);
|
|
99636
|
+
}
|
|
99637
|
+
.rpml-theme-fab:hover { background:var(--rpml-gx-hover); }
|
|
99638
|
+
`;
|
|
99639
|
+
function injectThemeStyle() {
|
|
99640
|
+
if (document.getElementById(THEME_STYLE_ID)) return;
|
|
99641
|
+
const s = document.createElement("style");
|
|
99642
|
+
s.id = THEME_STYLE_ID;
|
|
99643
|
+
s.textContent = THEME_CSS;
|
|
99644
|
+
document.head.appendChild(s);
|
|
99645
|
+
}
|
|
99646
|
+
function themeFromUrl() {
|
|
99647
|
+
const t = new URLSearchParams(location.search).get("theme");
|
|
99648
|
+
return t === "dark" || t === "light" ? t : null;
|
|
99649
|
+
}
|
|
99650
|
+
function currentTheme() {
|
|
99651
|
+
return document.documentElement.getAttribute(ATTR) === "dark" ? "dark" : "light";
|
|
99652
|
+
}
|
|
99653
|
+
function setTheme(theme) {
|
|
99654
|
+
document.documentElement.setAttribute(ATTR, theme);
|
|
99655
|
+
const url = new URL(location.href);
|
|
99656
|
+
url.searchParams.set("theme", theme);
|
|
99657
|
+
history.replaceState(history.state, "", url);
|
|
99658
|
+
}
|
|
99659
|
+
function initTheme() {
|
|
99660
|
+
const fromUrl = themeFromUrl();
|
|
99661
|
+
if (fromUrl) {
|
|
99662
|
+
document.documentElement.setAttribute(ATTR, fromUrl);
|
|
99663
|
+
return;
|
|
99664
|
+
}
|
|
99665
|
+
const prefersDark = typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
99666
|
+
document.documentElement.setAttribute(ATTR, prefersDark ? "dark" : "light");
|
|
99667
|
+
}
|
|
99584
99668
|
registerAll();
|
|
99585
99669
|
const CHROME_CSS = `
|
|
99586
99670
|
.rpml-gallery { display:grid; grid-template-columns:260px 1fr; height:100vh; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
|
|
99587
99671
|
.rpml-gallery.collapsed { grid-template-columns:1fr; }
|
|
99588
99672
|
.rpml-gallery.collapsed .rpml-gx-side { display:none; }
|
|
99589
|
-
.rpml-gx-side { display:flex; flex-direction:column; border-right:1px solid
|
|
99590
|
-
.rpml-gx-head { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; padding:16px; border-bottom:1px solid
|
|
99591
|
-
.rpml-gx-head small { display:block; margin-top:3px; font-size:11px; font-weight:400; color
|
|
99592
|
-
.rpml-gx-
|
|
99593
|
-
.rpml-gx-
|
|
99594
|
-
.rpml-gx-
|
|
99595
|
-
.rpml-gx-fab
|
|
99673
|
+
.rpml-gx-side { display:flex; flex-direction:column; border-right:1px solid var(--rpml-gx-border,#e5e7eb); background:var(--rpml-gx-side-bg,#fff); min-height:0; }
|
|
99674
|
+
.rpml-gx-head { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; padding:16px; border-bottom:1px solid var(--rpml-gx-border,#e5e7eb); font-size:14px; font-weight:700; color:var(--rpml-gx-fg,#111827); }
|
|
99675
|
+
.rpml-gx-head small { display:block; margin-top:3px; font-size:11px; font-weight:400; color:var(--rpml-gx-muted,#6b7280); }
|
|
99676
|
+
.rpml-gx-head-actions { flex:none; display:flex; gap:6px; margin:-3px -3px 0 0; }
|
|
99677
|
+
.rpml-gx-btn { display:flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; border:1px solid var(--rpml-gx-border,#e5e7eb); border-radius:7px; background:var(--rpml-gx-side-bg,#fff); color:var(--rpml-gx-muted,#6b7280); font-size:15px; line-height:1; cursor:pointer; }
|
|
99678
|
+
.rpml-gx-btn:hover { background:var(--rpml-gx-hover,#f3f4f6); color:var(--rpml-gx-fg,#111827); }
|
|
99679
|
+
.rpml-gx-fab { position:fixed; top:12px; left:12px; z-index:50; display:none; align-items:center; justify-content:center; width:34px; height:34px; padding:0; border:1px solid var(--rpml-gx-border,#e5e7eb); border-radius:9px; background:var(--rpml-gx-side-bg,#fff); color:var(--rpml-gx-fg,#374151); font-size:17px; line-height:1; cursor:pointer; box-shadow:0 1px 3px rgba(0,0,0,.12); }
|
|
99680
|
+
.rpml-gx-fab:hover { background:var(--rpml-gx-hover,#f3f4f6); }
|
|
99596
99681
|
.rpml-gallery.collapsed .rpml-gx-fab { display:flex; }
|
|
99597
99682
|
.rpml-gx-nav { flex:1; overflow-y:auto; padding:8px; }
|
|
99598
|
-
.rpml-gx-group { padding:10px 8px 3px; font-size:11px; font-weight:700; color
|
|
99599
|
-
.rpml-gx-
|
|
99600
|
-
.rpml-gx-
|
|
99601
|
-
.rpml-gx-
|
|
99602
|
-
.rpml-gx-
|
|
99603
|
-
.rpml-gx-
|
|
99683
|
+
.rpml-gx-group { padding:10px 8px 3px; font-size:11px; font-weight:700; color:var(--rpml-gx-group,#9ca3af); text-transform:uppercase; letter-spacing:.04em; }
|
|
99684
|
+
.rpml-gx-row { display:flex; align-items:center; border-radius:7px; }
|
|
99685
|
+
.rpml-gx-row:hover { background:var(--rpml-gx-hover,#f3f4f6); }
|
|
99686
|
+
.rpml-gx-row.active { background:var(--rpml-gx-active-bg,#eff6ff); }
|
|
99687
|
+
.rpml-gx-item { flex:1; min-width:0; display:block; padding:6px 10px; font-size:13px; color:var(--rpml-gx-item,#374151); text-decoration:none; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
99688
|
+
.rpml-gx-row.active .rpml-gx-item { color:var(--rpml-gx-active-fg,#1d4ed8); font-weight:650; }
|
|
99689
|
+
.rpml-gx-indent .rpml-gx-item { padding-left:22px; }
|
|
99690
|
+
.rpml-gx-copy { flex:none; margin-right:6px; padding:3px 7px; border:1px solid var(--rpml-gx-border,#e5e7eb); border-radius:6px; background:transparent; color:var(--rpml-gx-muted,#9ca3af); font-size:11px; line-height:1.4; cursor:pointer; opacity:0; transition:opacity .12s; }
|
|
99691
|
+
.rpml-gx-row:hover .rpml-gx-copy { opacity:1; }
|
|
99692
|
+
.rpml-gx-copy:hover { background:var(--rpml-gx-copy-hover,#e5e7eb); color:var(--rpml-gx-fg,#111827); }
|
|
99693
|
+
.rpml-gx-copy.copied { opacity:1; color:var(--rpml-gx-ok,#059669); border-color:var(--rpml-gx-ok,#059669); }
|
|
99694
|
+
.rpml-gx-main { overflow:auto; min-height:0; background:var(--rpml-gx-main-bg,#f4f6f8); }
|
|
99604
99695
|
.rpml-gx-err { padding:40px; color:#dc2626; font-family:ui-monospace,Menlo,monospace; }
|
|
99605
99696
|
`;
|
|
99606
99697
|
function injectChrome() {
|
|
99698
|
+
injectThemeStyle();
|
|
99607
99699
|
if (document.getElementById("rpml-gallery-style")) return;
|
|
99608
99700
|
const s = document.createElement("style");
|
|
99609
99701
|
s.id = "rpml-gallery-style";
|
|
@@ -99653,14 +99745,13 @@ function resolveAnchorTarget(to, fromPath, paths) {
|
|
|
99653
99745
|
}
|
|
99654
99746
|
function mountGallery(docs, host = document.body) {
|
|
99655
99747
|
injectChrome();
|
|
99656
|
-
|
|
99657
|
-
|
|
99748
|
+
let byPath = new Map(docs.map((d) => [d.path, d]));
|
|
99749
|
+
let tree = buildTree(docs);
|
|
99658
99750
|
const root = document.createElement("div");
|
|
99659
99751
|
root.className = "rpml-gallery";
|
|
99660
99752
|
const side = document.createElement("aside");
|
|
99661
99753
|
side.className = "rpml-gx-side";
|
|
99662
|
-
|
|
99663
|
-
side.innerHTML = `<div class="rpml-gx-head"><span>RPML 文档<small>${count} 个文件</small></span><button class="rpml-gx-toggle" type="button" title="收起侧边栏" aria-label="收起侧边栏">«</button></div>`;
|
|
99754
|
+
side.innerHTML = `<div class="rpml-gx-head"><span>RPML 文档<small>${docs.length} 个文件</small></span><div class="rpml-gx-head-actions"><button class="rpml-gx-btn rpml-gx-theme" type="button" title="切换亮色/暗色" aria-label="切换亮色/暗色">◑</button><button class="rpml-gx-btn rpml-gx-toggle" type="button" title="收起侧边栏" aria-label="收起侧边栏">«</button></div></div>`;
|
|
99664
99755
|
const nav = document.createElement("nav");
|
|
99665
99756
|
nav.className = "rpml-gx-nav";
|
|
99666
99757
|
side.appendChild(nav);
|
|
@@ -99677,18 +99768,32 @@ function mountGallery(docs, host = document.body) {
|
|
|
99677
99768
|
host.appendChild(root);
|
|
99678
99769
|
side.querySelector(".rpml-gx-toggle").addEventListener("click", () => root.classList.add("collapsed"));
|
|
99679
99770
|
fab.addEventListener("click", () => root.classList.remove("collapsed"));
|
|
99771
|
+
initTheme();
|
|
99772
|
+
side.querySelector(".rpml-gx-theme").addEventListener("click", () => {
|
|
99773
|
+
setTheme(currentTheme() === "dark" ? "light" : "dark");
|
|
99774
|
+
});
|
|
99680
99775
|
const links = /* @__PURE__ */ new Map();
|
|
99681
99776
|
function renderNav(node, depth) {
|
|
99682
99777
|
const entries = [...node.children.values()];
|
|
99683
99778
|
const leaves = entries.filter((e) => e.path).sort((a, b) => a.name.localeCompare(b.name));
|
|
99684
99779
|
const folders = entries.filter((e) => !e.path).sort((a, b) => a.name.localeCompare(b.name));
|
|
99685
99780
|
for (const leaf of leaves) {
|
|
99781
|
+
const row = document.createElement("div");
|
|
99782
|
+
row.className = depth > 0 ? "rpml-gx-row rpml-gx-indent" : "rpml-gx-row";
|
|
99686
99783
|
const a = document.createElement("a");
|
|
99687
|
-
a.className =
|
|
99784
|
+
a.className = "rpml-gx-item";
|
|
99688
99785
|
a.textContent = leaf.title || leaf.name;
|
|
99689
99786
|
a.href = `#${leaf.path}`;
|
|
99690
|
-
|
|
99691
|
-
|
|
99787
|
+
const copy = document.createElement("button");
|
|
99788
|
+
copy.className = "rpml-gx-copy";
|
|
99789
|
+
copy.type = "button";
|
|
99790
|
+
copy.title = "复制此页全部内容";
|
|
99791
|
+
copy.setAttribute("aria-label", "复制此页全部内容");
|
|
99792
|
+
copy.dataset.copyPath = leaf.path;
|
|
99793
|
+
copy.textContent = "copy";
|
|
99794
|
+
row.append(a, copy);
|
|
99795
|
+
links.set(leaf.path, row);
|
|
99796
|
+
nav.appendChild(row);
|
|
99692
99797
|
}
|
|
99693
99798
|
for (const folder of folders) {
|
|
99694
99799
|
const g = document.createElement("div");
|
|
@@ -99699,25 +99804,34 @@ function mountGallery(docs, host = document.body) {
|
|
|
99699
99804
|
}
|
|
99700
99805
|
}
|
|
99701
99806
|
renderNav(tree, 0);
|
|
99807
|
+
function rebuildNav(newDocs) {
|
|
99808
|
+
nav.innerHTML = "";
|
|
99809
|
+
links.clear();
|
|
99810
|
+
tree = buildTree(newDocs);
|
|
99811
|
+
renderNav(tree, 0);
|
|
99812
|
+
side.querySelector(".rpml-gx-head small").textContent = `${newDocs.length} 个文件`;
|
|
99813
|
+
}
|
|
99702
99814
|
function pickDefault() {
|
|
99703
|
-
const
|
|
99704
|
-
|
|
99815
|
+
const cur = [...byPath.values()];
|
|
99816
|
+
const idx = cur.find((d) => basename(d.path).replace(/\.rpml$/i, "").toLowerCase() === "index");
|
|
99817
|
+
return (idx ?? cur[0]).path;
|
|
99705
99818
|
}
|
|
99706
99819
|
let currentPath = "";
|
|
99707
|
-
function show(path, section) {
|
|
99820
|
+
function show(path, section, preserve = false) {
|
|
99708
99821
|
const doc = byPath.get(path);
|
|
99709
99822
|
if (!doc) {
|
|
99710
99823
|
main.innerHTML = `<div class="rpml-gx-err">未找到文档:${path}</div>`;
|
|
99711
99824
|
return;
|
|
99712
99825
|
}
|
|
99713
|
-
|
|
99714
|
-
main
|
|
99715
|
-
|
|
99716
|
-
|
|
99717
|
-
|
|
99718
|
-
|
|
99719
|
-
}
|
|
99720
|
-
|
|
99826
|
+
liveRender(main, doc.source, {
|
|
99827
|
+
scroller: main,
|
|
99828
|
+
preserve,
|
|
99829
|
+
onError: (msg) => {
|
|
99830
|
+
if (msg) main.innerHTML = `<div class="rpml-gx-err">RPML 解析错误:${msg}</div>`;
|
|
99831
|
+
}
|
|
99832
|
+
});
|
|
99833
|
+
currentPath = path;
|
|
99834
|
+
links.forEach((row, p) => row.classList.toggle("active", p === path));
|
|
99721
99835
|
if (section) {
|
|
99722
99836
|
requestAnimationFrame(() => requestAnimationFrame(() => window.dispatchEvent(new CustomEvent("rp-section", { detail: section }))));
|
|
99723
99837
|
}
|
|
@@ -99735,7 +99849,24 @@ function mountGallery(docs, host = document.body) {
|
|
|
99735
99849
|
show(target, section);
|
|
99736
99850
|
});
|
|
99737
99851
|
nav.addEventListener("click", (e) => {
|
|
99738
|
-
|
|
99852
|
+
var _a2;
|
|
99853
|
+
const el = e.target;
|
|
99854
|
+
const copyBtn = el.closest(".rpml-gx-copy");
|
|
99855
|
+
if (copyBtn) {
|
|
99856
|
+
e.preventDefault();
|
|
99857
|
+
const doc = byPath.get(copyBtn.dataset.copyPath);
|
|
99858
|
+
if (!doc) return;
|
|
99859
|
+
void ((_a2 = navigator.clipboard) == null ? void 0 : _a2.writeText(doc.source).then(() => {
|
|
99860
|
+
copyBtn.classList.add("copied");
|
|
99861
|
+
copyBtn.textContent = "已复制";
|
|
99862
|
+
setTimeout(() => {
|
|
99863
|
+
copyBtn.classList.remove("copied");
|
|
99864
|
+
copyBtn.textContent = "copy";
|
|
99865
|
+
}, 1500);
|
|
99866
|
+
}));
|
|
99867
|
+
return;
|
|
99868
|
+
}
|
|
99869
|
+
const a = el.closest("a.rpml-gx-item");
|
|
99739
99870
|
if (!a) return;
|
|
99740
99871
|
e.preventDefault();
|
|
99741
99872
|
const path = decodeURIComponent(a.hash.slice(1));
|
|
@@ -99744,11 +99875,46 @@ function mountGallery(docs, host = document.body) {
|
|
|
99744
99875
|
});
|
|
99745
99876
|
window.addEventListener("popstate", route);
|
|
99746
99877
|
route();
|
|
99878
|
+
const controller = {
|
|
99879
|
+
update(newDocs) {
|
|
99880
|
+
var _a2;
|
|
99881
|
+
const prevSource = (_a2 = byPath.get(currentPath)) == null ? void 0 : _a2.source;
|
|
99882
|
+
byPath = new Map(newDocs.map((d) => [d.path, d]));
|
|
99883
|
+
const newPaths = newDocs.map((d) => d.path).sort().join("\0");
|
|
99884
|
+
const oldPaths = [...links.keys()].sort().join("\0");
|
|
99885
|
+
if (newPaths !== oldPaths) rebuildNav(newDocs);
|
|
99886
|
+
const curr = byPath.get(currentPath);
|
|
99887
|
+
if (curr) {
|
|
99888
|
+
if (curr.source !== prevSource) show(currentPath, void 0, true);
|
|
99889
|
+
else links.forEach((row, p) => row.classList.toggle("active", p === currentPath));
|
|
99890
|
+
} else if (newDocs.length) {
|
|
99891
|
+
const def = pickDefault();
|
|
99892
|
+
history.replaceState(null, "", `#${def}`);
|
|
99893
|
+
show(def);
|
|
99894
|
+
}
|
|
99895
|
+
}
|
|
99896
|
+
};
|
|
99897
|
+
globalThis.__RPML_GALLERY__ = controller;
|
|
99898
|
+
return controller;
|
|
99747
99899
|
}
|
|
99748
99900
|
const inlined = globalThis.__RPML_DOCS__;
|
|
99749
99901
|
if (inlined && Array.isArray(inlined) && inlined.length) {
|
|
99750
|
-
|
|
99751
|
-
|
|
99902
|
+
const mount = () => {
|
|
99903
|
+
mountGallery(inlined);
|
|
99904
|
+
if (globalThis.__RPML_LIVE__) {
|
|
99905
|
+
const es = new EventSource("/~live");
|
|
99906
|
+
es.onmessage = (ev) => {
|
|
99907
|
+
var _a2;
|
|
99908
|
+
try {
|
|
99909
|
+
const docs = JSON.parse(ev.data);
|
|
99910
|
+
(_a2 = globalThis.__RPML_GALLERY__) == null ? void 0 : _a2.update(docs);
|
|
99911
|
+
} catch {
|
|
99912
|
+
}
|
|
99913
|
+
};
|
|
99914
|
+
}
|
|
99915
|
+
};
|
|
99916
|
+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", mount);
|
|
99917
|
+
else mount();
|
|
99752
99918
|
}
|
|
99753
99919
|
export {
|
|
99754
99920
|
mountGallery
|