fluxplugin 1.0.1 → 1.0.3
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 +22 -9
- package/dist/{node/chunks/chunk-XPLGAEBH.js → browser/chunks/chunk-TL63576R.js} +106 -81
- package/dist/browser/chunks/{chunk-ZZ25CRMR.js → chunk-VXQJIDXW.js} +479 -6
- package/dist/browser/index.js +5 -1
- package/dist/browser/manager-ui.js +93 -18
- package/dist/browser/react.js +34 -4
- package/dist/cli.js +869 -174
- package/dist/node/chunks/chunk-3FH6NAJG.js +38 -0
- package/dist/node/chunks/{chunk-BZ7NZF7I.js → chunk-C7VWZZOX.js} +259 -44
- package/dist/{browser/chunks/chunk-Q75AOCXD.js → node/chunks/chunk-EVX2O65A.js} +185 -2
- package/dist/node/chunks/chunk-WSFCRVEQ.js +9 -0
- package/dist/node/chunks/tailwind-TJQVTBG5.js +9 -0
- package/dist/node/cli-api.js +562 -129
- package/dist/node/index.js +6 -1
- package/dist/node/main.js +19 -2
- package/dist/node/preload.js +2 -1
- package/dist/types/cli/build.d.ts +1 -1
- package/dist/types/cli/config.d.ts +3 -0
- package/dist/types/cli/host-files.generated.d.ts +1 -0
- package/dist/types/cli/host-templates.d.ts +3 -0
- package/dist/types/cli/host.d.ts +8 -0
- package/dist/types/cli/package.d.ts +18 -0
- package/dist/types/cli/publish.d.ts +23 -0
- package/dist/types/cli/store.d.ts +7 -0
- package/dist/types/cli/tailwind.d.ts +10 -0
- package/dist/types/cli/templates.d.ts +2 -0
- package/dist/types/core/index.d.ts +1 -0
- package/dist/types/core/manager.d.ts +2 -0
- package/dist/types/core/manifest.d.ts +9 -0
- package/dist/types/core/notifications.d.ts +48 -0
- package/dist/types/core/plugin.d.ts +7 -0
- package/dist/types/core/protocol.d.ts +27 -0
- package/dist/types/main/framework.d.ts +7 -1
- package/dist/types/main/github-registry.d.ts +49 -0
- package/dist/types/main/index.d.ts +2 -0
- package/dist/types/main/registry.d.ts +30 -0
- package/dist/types/main/stores.d.ts +29 -0
- package/dist/types/react/base-css.d.ts +1 -1
- package/dist/types/react/icons.d.ts +12 -0
- package/dist/types/react/index.d.ts +5 -0
- package/dist/types/react/markdown.d.ts +8 -0
- package/dist/types/react/os.d.ts +5 -0
- package/dist/types/react/runtime.d.ts +2 -1
- package/dist/types/react/theme.d.ts +53 -0
- package/dist/types/react/titlebar.d.ts +28 -0
- package/docs/CUSTOMIZING.md +257 -0
- package/docs/PLUGIN-AUTHORS.md +36 -9
- package/docs/RELEASE.md +1 -1
- package/docs/SECURITY.md +5 -0
- package/docs/STORE.md +123 -0
- package/docs/TROUBLESHOOTING.md +35 -0
- package/docs/screenshots/command-palette.png +0 -0
- package/docs/screenshots/dashboard.png +0 -0
- package/docs/screenshots/electron-plugin-page.png +0 -0
- package/docs/screenshots/electron-titlebar.png +0 -0
- package/docs/screenshots/plugin-details.png +0 -0
- package/docs/screenshots/plugin-manager.png +0 -0
- package/docs/screenshots/plugin-video.png +0 -0
- package/docs/screenshots/stats.png +0 -0
- package/docs/screenshots/store-available.png +0 -0
- package/docs/screenshots/tailwind-dark.png +0 -0
- package/package.json +1 -1
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
PluginManager,
|
|
5
5
|
errorMessage,
|
|
6
6
|
normalizePath,
|
|
7
|
+
s,
|
|
7
8
|
scopeCss
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TL63576R.js";
|
|
9
10
|
|
|
10
11
|
// src/react/runtime.ts
|
|
11
12
|
var RemoteError = class extends Error {
|
|
@@ -44,6 +45,7 @@ var PluginsClient = class {
|
|
|
44
45
|
configReset = (id) => this.call(MGMT.configReset, { id });
|
|
45
46
|
configSchema = (id) => this.call(MGMT.configSchema, { id });
|
|
46
47
|
logs = (id) => this.call(MGMT.logs, { id });
|
|
48
|
+
details = (id) => this.call(MGMT.details, { id });
|
|
47
49
|
diagnostics = (id) => this.call(MGMT.diagnostics, { id });
|
|
48
50
|
};
|
|
49
51
|
var asDefinition = (mod) => {
|
|
@@ -107,6 +109,7 @@ var RendererFramework = class {
|
|
|
107
109
|
this.bridge.on(MGMT.changed, () => {
|
|
108
110
|
void this.sync().catch((e) => console.error("[fluxplugin] sync failed", e));
|
|
109
111
|
}),
|
|
112
|
+
this.bridge.on("flux.notification", (n) => void this.manager.notifications.push(n, n?.owner ?? "main")),
|
|
110
113
|
this.bridge.on("flux.event.plugin.hotreload", ({ id } = {}) => void this.hotReload(id))
|
|
111
114
|
);
|
|
112
115
|
}
|
|
@@ -422,8 +425,8 @@ function PluginSlot({ name, children, props = {} }) {
|
|
|
422
425
|
}
|
|
423
426
|
function useExtensionItems(point, key) {
|
|
424
427
|
const fw = usePluginFramework();
|
|
425
|
-
useRegistryVersion(fw.manager.extensionPoints.subscribe, () => fw.manager.extensionPoints.version);
|
|
426
|
-
return fw.manager.extensionPoints.items(point, key);
|
|
428
|
+
const version = useRegistryVersion(fw.manager.extensionPoints.subscribe, () => fw.manager.extensionPoints.version);
|
|
429
|
+
return useMemo2(() => fw.manager.extensionPoints.items(point, key), [fw, point, key, version]);
|
|
427
430
|
}
|
|
428
431
|
function usePlugin(id) {
|
|
429
432
|
const fw = usePluginFramework();
|
|
@@ -459,7 +462,7 @@ function usePluginEvent(name, onEvent) {
|
|
|
459
462
|
};
|
|
460
463
|
const subs = [fw.manager.events.on(name, (p) => handle(p)), fw.bridge.on(name, handle), fw.bridge.on(`flux.event.${name}`, handle)];
|
|
461
464
|
return () => {
|
|
462
|
-
subs.forEach((
|
|
465
|
+
subs.forEach((s2) => typeof s2 === "function" ? s2() : s2.dispose());
|
|
463
466
|
};
|
|
464
467
|
}, [fw, name]);
|
|
465
468
|
return last;
|
|
@@ -487,7 +490,7 @@ function usePluginIPC(endpoint, opts = {}) {
|
|
|
487
490
|
useEffect2(() => () => void (alive.current = false), []);
|
|
488
491
|
const call = useCallback2(
|
|
489
492
|
async (input) => {
|
|
490
|
-
setState((
|
|
493
|
+
setState((s2) => ({ ...s2, loading: true, error: void 0 }));
|
|
491
494
|
try {
|
|
492
495
|
const data = await fw.bridge.invoke(name, input, opts.caller);
|
|
493
496
|
if (alive.current) setState({ data, error: void 0, loading: false });
|
|
@@ -572,6 +575,7 @@ function useKeybindings(opts = {}) {
|
|
|
572
575
|
useEffect3(() => {
|
|
573
576
|
if (opts.enabled === false) return;
|
|
574
577
|
const onKey = (e) => {
|
|
578
|
+
if (e.defaultPrevented) return;
|
|
575
579
|
const target = e.target;
|
|
576
580
|
if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) && !(e.ctrlKey || e.metaKey)) return;
|
|
577
581
|
const parts = [];
|
|
@@ -673,6 +677,38 @@ var baseCss = `
|
|
|
673
677
|
.flux-palette-item.is-active{background:var(--flux-accent);color:var(--flux-accent-fg)}
|
|
674
678
|
.flux-palette-cat{opacity:.65}.flux-palette-empty{padding:14px;color:var(--flux-muted);font-size:14px}
|
|
675
679
|
.flux-palette kbd{font:11px ui-monospace,monospace;padding:2px 6px;border:1px solid currentColor;border-radius:5px;opacity:.7}
|
|
680
|
+
|
|
681
|
+
:root[data-theme="dark"]{--flux-bg:#0b1020;--flux-fg:#e5e7eb;--flux-muted:#94a3b8;--flux-border:#1f2a44;--flux-surface:#111936}
|
|
682
|
+
:root[data-theme="light"]{--flux-bg:#fff;--flux-fg:#0f172a;--flux-muted:#64748b;--flux-border:#e2e8f0;--flux-surface:#f8fafc}
|
|
683
|
+
.flux-icon{flex:none;vertical-align:middle}
|
|
684
|
+
.flux-titlebar{--flux-titlebar-h:40px;height:var(--flux-titlebar-h);box-sizing:border-box;display:grid;grid-template-columns:1fr minmax(160px,400px) 1fr;align-items:center;gap:8px;padding:0 8px;background:var(--flux-surface);border-bottom:1px solid var(--flux-border);color:var(--flux-fg);-webkit-app-region:drag;user-select:none;position:relative;z-index:50}
|
|
685
|
+
.flux-titlebar[data-electron][data-os="mac"]{padding-left:82px}
|
|
686
|
+
.flux-titlebar[data-electron][data-os="windows"],.flux-titlebar[data-electron][data-os="linux"]{padding-right:calc(100vw - env(titlebar-area-x,0px) - env(titlebar-area-width,100vw) + 8px)}
|
|
687
|
+
.flux-titlebar button,.flux-titlebar input,.flux-titlebar select,.flux-titlebar .flux-dropdown{-webkit-app-region:no-drag}
|
|
688
|
+
.flux-tb-left,.flux-tb-right{display:flex;align-items:center;gap:4px;min-width:0}.flux-tb-right{justify-content:flex-end}
|
|
689
|
+
.flux-brand{display:flex;align-items:center;gap:8px;font-weight:600;margin-right:8px;white-space:nowrap}
|
|
690
|
+
.flux-tb-btn{display:inline-flex;align-items:center;gap:6px;border:0;background:transparent;color:inherit;border-radius:6px;padding:5px 9px;font:inherit;cursor:pointer;position:relative}
|
|
691
|
+
.flux-tb-btn:hover,.flux-tb-btn.is-open{background:var(--flux-border)}
|
|
692
|
+
.flux-menubar{display:flex}.flux-menu{position:relative}
|
|
693
|
+
.flux-dropdown{position:absolute;top:calc(100% + 4px);left:0;min-width:220px;max-width:360px;margin:0;padding:6px;list-style:none;background:var(--flux-bg);color:var(--flux-fg);border:1px solid var(--flux-border);border-radius:10px;box-shadow:0 14px 36px rgba(0,0,0,.28);z-index:60}
|
|
694
|
+
.flux-dd-item{display:flex;justify-content:space-between;align-items:center;gap:16px;width:100%;border:0;background:transparent;color:inherit;font:inherit;text-align:left;padding:7px 10px;border-radius:7px;cursor:pointer}
|
|
695
|
+
.flux-dd-item:hover,.flux-dd-item.is-active{background:var(--flux-accent);color:var(--flux-accent-fg)}
|
|
696
|
+
.flux-dd-item kbd,.flux-dd-item small{opacity:.65;font:11px ui-monospace,monospace}.flux-sep{height:1px;background:var(--flux-border);margin:5px 4px}
|
|
697
|
+
.flux-search{position:relative;display:flex;align-items:center;gap:8px;background:var(--flux-bg);border:1px solid var(--flux-border);border-radius:8px;padding:0 10px;height:28px;color:var(--flux-muted)}
|
|
698
|
+
.flux-search input{flex:1;min-width:0;border:0;background:transparent;color:var(--flux-fg);font:inherit;outline:none}
|
|
699
|
+
.flux-search-results{left:0;right:0;max-width:none;top:calc(100% + 6px)}.flux-group{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--flux-muted);padding:6px 10px 2px}
|
|
700
|
+
.flux-empty{padding:12px;color:var(--flux-muted);font-size:13px}.flux-select{margin-left:4px;background:var(--flux-bg);color:inherit;border:1px solid var(--flux-border);border-radius:6px;padding:3px 4px;font:inherit}
|
|
701
|
+
.flux-bell{position:relative}.flux-badge{position:absolute;top:0;right:0;min-width:15px;height:15px;border-radius:99px;background:var(--flux-danger);color:#fff;font-size:10px;line-height:15px;text-align:center}
|
|
702
|
+
.flux-notif-panel{left:auto;right:0;width:340px;max-height:420px;overflow:auto;padding:0}.flux-notif-head{display:flex;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--flux-border)}
|
|
703
|
+
.flux-notif{display:flex;justify-content:space-between;gap:10px;padding:10px 12px;border-bottom:1px solid var(--flux-border);border-left:3px solid var(--flux-accent)}
|
|
704
|
+
.flux-notif.flux-success{border-left-color:var(--flux-ok)}.flux-notif.flux-warning{border-left-color:var(--flux-warn)}.flux-notif.flux-error{border-left-color:var(--flux-danger)}
|
|
705
|
+
.flux-notif p{margin:2px 0 4px;font-size:13px}.flux-notif small{color:var(--flux-muted)}.flux-notif-actions{display:flex;flex-direction:column;align-items:flex-end;gap:4px}
|
|
706
|
+
.flux-link{background:none;border:0;color:var(--flux-accent);cursor:pointer;font:inherit;font-size:12px;padding:0}
|
|
707
|
+
.flux-toasts{position:fixed;top:48px;right:12px;display:flex;flex-direction:column;gap:8px;z-index:40;pointer-events:none}
|
|
708
|
+
.flux-toast{pointer-events:auto;background:var(--flux-bg);color:var(--flux-fg);border:1px solid var(--flux-border);border-left:4px solid var(--flux-accent);border-radius:10px;padding:10px 14px;box-shadow:0 10px 28px rgba(0,0,0,.25);max-width:340px;font-size:13px}
|
|
709
|
+
.flux-toast.flux-success{border-left-color:var(--flux-ok)}.flux-toast.flux-warning{border-left-color:var(--flux-warn)}.flux-toast.flux-error{border-left-color:var(--flux-danger)}
|
|
710
|
+
.flux-md{line-height:1.6}.flux-md h2,.flux-md h3,.flux-md h4,.flux-md h5{margin:1.1em 0 .4em}.flux-md pre{background:var(--flux-surface);padding:10px;border-radius:8px;overflow:auto}
|
|
711
|
+
.flux-md code{background:var(--flux-surface);padding:1px 5px;border-radius:4px;font-size:.92em}.flux-md pre code{padding:0;background:none}.flux-md table{border-collapse:collapse;margin:8px 0;font-size:13px}.flux-md th,.flux-md td{border:1px solid var(--flux-border);padding:5px 10px;text-align:left}.flux-md th{background:var(--flux-surface)}.flux-md blockquote{margin:8px 0;padding:2px 12px;border-left:3px solid var(--flux-border);color:var(--flux-muted)}
|
|
676
712
|
`;
|
|
677
713
|
|
|
678
714
|
// src/react/http-bridge.ts
|
|
@@ -721,6 +757,428 @@ function createHttpBridge(baseUrl = "") {
|
|
|
721
757
|
};
|
|
722
758
|
}
|
|
723
759
|
|
|
760
|
+
// src/react/os.ts
|
|
761
|
+
import { useMemo as useMemo4 } from "react";
|
|
762
|
+
function detectOS(ua = typeof navigator === "undefined" ? "" : navigator.userAgent) {
|
|
763
|
+
if (/Mac|iPhone|iPad/i.test(ua)) return "mac";
|
|
764
|
+
if (/Windows/i.test(ua)) return "windows";
|
|
765
|
+
if (/Linux|X11|CrOS/i.test(ua)) return "linux";
|
|
766
|
+
return "other";
|
|
767
|
+
}
|
|
768
|
+
var useOS = () => useMemo4(() => detectOS(), []);
|
|
769
|
+
function formatShortcut(binding, os = detectOS()) {
|
|
770
|
+
const mac = os === "mac";
|
|
771
|
+
const map = mac ? { mod: "\u2318", ctrl: "\u2303", shift: "\u21E7", alt: "\u2325" } : { mod: "Ctrl", ctrl: "Ctrl", shift: "Shift", alt: "Alt" };
|
|
772
|
+
const parts = binding.split("+").map((p) => map[p.toLowerCase()] ?? (p.length === 1 ? p.toUpperCase() : p));
|
|
773
|
+
return mac ? parts.join("") : parts.join("+");
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/react/icons.tsx
|
|
777
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
778
|
+
var PATHS = {
|
|
779
|
+
search: "M11 4a7 7 0 105.2 11.7l3.5 3.5 1.4-1.4-3.5-3.5A7 7 0 0011 4zm0 2a5 5 0 110 10 5 5 0 010-10z",
|
|
780
|
+
bell: "M12 3a6 6 0 00-6 6v3.6L4.3 15.3A1 1 0 005 17h14a1 1 0 00.7-1.7L18 12.6V9a6 6 0 00-6-6zm-2 16a2 2 0 004 0h-4z",
|
|
781
|
+
sun: "M12 7a5 5 0 100 10 5 5 0 000-10zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM1 11h3v2H1v-2zm19 0h3v2h-3v-2zM4.2 5.6l1.4-1.4 2.1 2.1-1.4 1.4-2.1-2.1zm12.1 12.1l1.4-1.4 2.1 2.1-1.4 1.4-2.1-2.1zM5.6 19.8l-1.4-1.4 2.1-2.1 1.4 1.4-2.1 2.1zM18.4 7.7l-1.4-1.4 2.1-2.1 1.4 1.4-2.1 2.1z",
|
|
782
|
+
moon: "M20 14.5A8.5 8.5 0 019.5 4a8.5 8.5 0 1010.5 10.5z",
|
|
783
|
+
plug: "M9 2v5H7v3a5 5 0 004 4.9V19H8v2h8v-2h-3v-4.1A5 5 0 0017 10V7h-2V2h-2v5h-2V2H9z",
|
|
784
|
+
settings: "M12 8a4 4 0 100 8 4 4 0 000-8zm8.9 5l1.7 1.3-2 3.4-2-.8a7.6 7.6 0 01-1.7 1l-.3 2.1h-4l-.3-2.1a7.6 7.6 0 01-1.7-1l-2 .8-2-3.4L5.3 13a7 7 0 010-2L3.6 9.7l2-3.4 2 .8a7.6 7.6 0 011.7-1L9.6 4h4l.3 2.1a7.6 7.6 0 011.7 1l2-.8 2 3.4L17.9 11a7 7 0 010 2z",
|
|
785
|
+
check: "M9 16.2l-3.5-3.5L4 14.2l5 5 11-11-1.5-1.5L9 16.2z",
|
|
786
|
+
close: "M6.4 5l-1.4 1.4L10.6 12 5 17.6 6.4 19l5.6-5.6 5.6 5.6 1.4-1.4-5.6-5.6L19 6.4 17.6 5 12 10.6 6.4 5z",
|
|
787
|
+
chevron: "M7 10l5 5 5-5H7z",
|
|
788
|
+
play: "M8 5v14l11-7L8 5z",
|
|
789
|
+
image: "M4 5h16a1 1 0 011 1v12a1 1 0 01-1 1H4a1 1 0 01-1-1V6a1 1 0 011-1zm3 3a2 2 0 100 4 2 2 0 000-4zm-3 9h16v-3l-4-4-5 5-3-3-4 4v1z",
|
|
790
|
+
command: "M7 3a4 4 0 00-1 7.9v2.2A4 4 0 107 21a4 4 0 004-4h2a4 4 0 104-4 4 4 0 00-1-.1V10.9A4 4 0 1017 3a4 4 0 00-4 4h-2a4 4 0 00-4-4zm4 9H9V10h2v2zm4 0h-2V10h2v2z"
|
|
791
|
+
};
|
|
792
|
+
function Icon({ name, d, size = 16, title }) {
|
|
793
|
+
const path = d ?? (name ? PATHS[name] : void 0) ?? PATHS["plug"];
|
|
794
|
+
return /* @__PURE__ */ jsxs4("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": title ? void 0 : true, role: title ? "img" : void 0, className: "flux-icon", children: [
|
|
795
|
+
title && /* @__PURE__ */ jsx4("title", { children: title }),
|
|
796
|
+
/* @__PURE__ */ jsx4("path", { d: path })
|
|
797
|
+
] });
|
|
798
|
+
}
|
|
799
|
+
var iconNames = Object.keys(PATHS);
|
|
800
|
+
|
|
801
|
+
// src/react/markdown.tsx
|
|
802
|
+
import React4 from "react";
|
|
803
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
804
|
+
var safeHref = (h) => /^https:\/\/[^\s]+$/i.test(h) || h.startsWith("#") ? h : void 0;
|
|
805
|
+
function inline(src, key = 0) {
|
|
806
|
+
const out = [];
|
|
807
|
+
const re = /(`[^`]+`)|(\*\*[^*]+\*\*)|(\*[^*\s][^*]*\*)|(\[[^\]]+\]\([^)\s]+\))/g;
|
|
808
|
+
let last = 0;
|
|
809
|
+
let m;
|
|
810
|
+
let i = 0;
|
|
811
|
+
while (m = re.exec(src)) {
|
|
812
|
+
if (m.index > last) out.push(src.slice(last, m.index));
|
|
813
|
+
const tok = m[0];
|
|
814
|
+
const k = `${key}-${i++}`;
|
|
815
|
+
if (tok.startsWith("`")) out.push(/* @__PURE__ */ jsx5("code", { children: tok.slice(1, -1) }, k));
|
|
816
|
+
else if (tok.startsWith("**")) out.push(/* @__PURE__ */ jsx5("strong", { children: tok.slice(2, -2) }, k));
|
|
817
|
+
else if (tok.startsWith("*")) out.push(/* @__PURE__ */ jsx5("em", { children: tok.slice(1, -1) }, k));
|
|
818
|
+
else {
|
|
819
|
+
const mm = /^\[([^\]]+)\]\(([^)\s]+)\)$/.exec(tok);
|
|
820
|
+
const href = safeHref(mm[2]);
|
|
821
|
+
out.push(href ? /* @__PURE__ */ jsx5("a", { href, target: "_blank", rel: "noopener noreferrer", children: mm[1] }, k) : mm[1]);
|
|
822
|
+
}
|
|
823
|
+
last = m.index + tok.length;
|
|
824
|
+
}
|
|
825
|
+
if (last < src.length) out.push(src.slice(last));
|
|
826
|
+
return out;
|
|
827
|
+
}
|
|
828
|
+
function Markdown({ source }) {
|
|
829
|
+
const lines = source.replace(/\r\n/g, "\n").split("\n");
|
|
830
|
+
const blocks = [];
|
|
831
|
+
let i = 0;
|
|
832
|
+
let k = 0;
|
|
833
|
+
while (i < lines.length) {
|
|
834
|
+
const line = lines[i];
|
|
835
|
+
if (!line.trim()) {
|
|
836
|
+
i++;
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
if (line.startsWith("```")) {
|
|
840
|
+
const buf2 = [];
|
|
841
|
+
i++;
|
|
842
|
+
while (i < lines.length && !lines[i].startsWith("```")) buf2.push(lines[i++]);
|
|
843
|
+
i++;
|
|
844
|
+
blocks.push(/* @__PURE__ */ jsx5("pre", { children: /* @__PURE__ */ jsx5("code", { children: buf2.join("\n") }) }, k++));
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
const h = /^(#{1,4})\s+(.*)$/.exec(line);
|
|
848
|
+
if (h) {
|
|
849
|
+
const L = `h${h[1].length + 1}`;
|
|
850
|
+
blocks.push(React4.createElement(L, { key: k++ }, inline(h[2])));
|
|
851
|
+
i++;
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
if (/^(-{3,}|\*{3,})$/.test(line.trim())) {
|
|
855
|
+
blocks.push(/* @__PURE__ */ jsx5("hr", {}, k++));
|
|
856
|
+
i++;
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
if (line.startsWith(">")) {
|
|
860
|
+
const buf2 = [];
|
|
861
|
+
while (i < lines.length && lines[i].startsWith(">")) buf2.push(lines[i++].replace(/^>\s?/, ""));
|
|
862
|
+
blocks.push(/* @__PURE__ */ jsx5("blockquote", { children: inline(buf2.join(" ")) }, k++));
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
if (line.includes("|") && /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(lines[i + 1] ?? "")) {
|
|
866
|
+
const cells = (l) => l.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
867
|
+
const head = cells(line);
|
|
868
|
+
i += 2;
|
|
869
|
+
const rows = [];
|
|
870
|
+
while (i < lines.length && lines[i].includes("|") && lines[i].trim()) rows.push(cells(lines[i++]));
|
|
871
|
+
blocks.push(
|
|
872
|
+
/* @__PURE__ */ jsxs5("table", { children: [
|
|
873
|
+
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsx5("tr", { children: head.map((c, j) => /* @__PURE__ */ jsx5("th", { children: inline(c) }, j)) }) }),
|
|
874
|
+
/* @__PURE__ */ jsx5("tbody", { children: rows.map((r, ri) => /* @__PURE__ */ jsx5("tr", { children: r.map((c, j) => /* @__PURE__ */ jsx5("td", { children: inline(c) }, j)) }, ri)) })
|
|
875
|
+
] }, k++)
|
|
876
|
+
);
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
const li = /^(\s*)([-*]|\d+\.)\s+/;
|
|
880
|
+
if (li.test(line)) {
|
|
881
|
+
const ordered = /^\s*\d+\./.test(line);
|
|
882
|
+
const items = [];
|
|
883
|
+
while (i < lines.length && li.test(lines[i])) items.push(/* @__PURE__ */ jsx5("li", { children: inline(lines[i++].replace(li, "")) }, items.length));
|
|
884
|
+
blocks.push(ordered ? /* @__PURE__ */ jsx5("ol", { children: items }, k++) : /* @__PURE__ */ jsx5("ul", { children: items }, k++));
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
const buf = [];
|
|
888
|
+
while (i < lines.length && lines[i].trim() && !/^(#{1,4}\s|```|>|\s*([-*]|\d+\.)\s)/.test(lines[i]) && !(lines[i].includes("|") && /^\s*\|?\s*:?-{2,}/.test(lines[i + 1] ?? ""))) buf.push(lines[i++]);
|
|
889
|
+
blocks.push(/* @__PURE__ */ jsx5("p", { children: inline(buf.join(" ")) }, k++));
|
|
890
|
+
}
|
|
891
|
+
return /* @__PURE__ */ jsx5("div", { className: "flux-md", children: blocks });
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// src/react/theme.tsx
|
|
895
|
+
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo5, useState as useState4 } from "react";
|
|
896
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
897
|
+
function declareHostPoints(framework) {
|
|
898
|
+
const ep = framework.manager.extensionPoints;
|
|
899
|
+
if (!ep.definition("theme")) {
|
|
900
|
+
ep.declare({ name: "theme", contributions: { themes: s.object({ id: s.string(), label: s.string(), dark: s.boolean().optional(), tokens: s.record(s.string()) }) } });
|
|
901
|
+
}
|
|
902
|
+
if (!ep.definition("titlebar")) {
|
|
903
|
+
ep.declare({ name: "titlebar", contributions: { searchProviders: s.object({ id: s.string(), label: s.string(), search: s.fn() }) } });
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
var Ctx = createContext2(null);
|
|
907
|
+
var read = (k) => {
|
|
908
|
+
try {
|
|
909
|
+
return localStorage.getItem(k);
|
|
910
|
+
} catch {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
var write = (k, v) => {
|
|
915
|
+
try {
|
|
916
|
+
v === void 0 ? localStorage.removeItem(k) : localStorage.setItem(k, v);
|
|
917
|
+
} catch {
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
function ThemeProvider({ children, storageKey = "fluxplugin.theme", onResolved }) {
|
|
921
|
+
const themes = useExtensionItems("theme", "themes");
|
|
922
|
+
const [mode, setModeState] = useState4(() => read(storageKey + ".mode") || "system");
|
|
923
|
+
const [themeId, setThemeIdState] = useState4(() => read(storageKey + ".id") ?? void 0);
|
|
924
|
+
const [systemDark, setSystemDark] = useState4(() => typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches);
|
|
925
|
+
useEffect4(() => {
|
|
926
|
+
if (typeof matchMedia === "undefined") return;
|
|
927
|
+
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
928
|
+
const l = (e) => setSystemDark(e.matches);
|
|
929
|
+
mq.addEventListener("change", l);
|
|
930
|
+
return () => mq.removeEventListener("change", l);
|
|
931
|
+
}, []);
|
|
932
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
933
|
+
const resolved = theme ? theme.dark ? "dark" : "light" : mode === "system" ? systemDark ? "dark" : "light" : mode;
|
|
934
|
+
useEffect4(() => {
|
|
935
|
+
const root = document.documentElement;
|
|
936
|
+
root.setAttribute("data-theme", resolved);
|
|
937
|
+
const applied = Object.entries(theme?.tokens ?? {}).filter(([k]) => /^--[\w-]+$/.test(k));
|
|
938
|
+
for (const [k, v] of applied) root.style.setProperty(k, v);
|
|
939
|
+
const cs = getComputedStyle(root);
|
|
940
|
+
onResolved?.({ dark: resolved === "dark", bg: cs.getPropertyValue("--flux-bg").trim(), fg: cs.getPropertyValue("--flux-fg").trim(), surface: cs.getPropertyValue("--flux-surface").trim() });
|
|
941
|
+
return () => applied.forEach(([k]) => root.style.removeProperty(k));
|
|
942
|
+
}, [resolved, theme]);
|
|
943
|
+
const setMode = useCallback3((m) => (setModeState(m), setThemeIdState(void 0), write(storageKey + ".mode", m), write(storageKey + ".id", void 0)), [storageKey]);
|
|
944
|
+
const setThemeId = useCallback3((id) => (setThemeIdState(id), write(storageKey + ".id", id)), [storageKey]);
|
|
945
|
+
const value = useMemo5(() => ({ mode, setMode, themeId, setThemeId, resolved, themes, toggle: () => setMode(resolved === "dark" ? "light" : "dark") }), [mode, setMode, themeId, setThemeId, resolved, themes]);
|
|
946
|
+
return /* @__PURE__ */ jsx6(Ctx.Provider, { value, children });
|
|
947
|
+
}
|
|
948
|
+
function useTheme() {
|
|
949
|
+
const c = useContext2(Ctx);
|
|
950
|
+
if (!c) throw new Error("useTheme must be used inside <ThemeProvider>");
|
|
951
|
+
return c;
|
|
952
|
+
}
|
|
953
|
+
function ThemeSwitcher() {
|
|
954
|
+
const { resolved, toggle, themes, themeId, setThemeId, mode, setMode } = useTheme();
|
|
955
|
+
usePluginFramework();
|
|
956
|
+
return /* @__PURE__ */ jsxs6("span", { className: "flux-theme-switch", children: [
|
|
957
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "flux-tb-btn", onClick: toggle, title: `Theme: ${resolved} (click to switch)`, "aria-label": "Toggle theme", "data-testid": "theme-toggle", children: /* @__PURE__ */ jsx6(Icon, { name: resolved === "dark" ? "moon" : "sun" }) }),
|
|
958
|
+
themes.length > 0 && /* @__PURE__ */ jsxs6("select", { className: "flux-select", "aria-label": "Theme", value: themeId ?? `mode:${mode}`, onChange: (e) => e.target.value.startsWith("mode:") ? setMode(e.target.value.slice(5)) : setThemeId(e.target.value), children: [
|
|
959
|
+
/* @__PURE__ */ jsx6("option", { value: "mode:system", children: "System" }),
|
|
960
|
+
/* @__PURE__ */ jsx6("option", { value: "mode:light", children: "Light" }),
|
|
961
|
+
/* @__PURE__ */ jsx6("option", { value: "mode:dark", children: "Dark" }),
|
|
962
|
+
themes.map((t) => /* @__PURE__ */ jsx6("option", { value: t.id, children: t.label }, t.id))
|
|
963
|
+
] })
|
|
964
|
+
] });
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/react/titlebar.tsx
|
|
968
|
+
import { useEffect as useEffect5, useMemo as useMemo6, useRef as useRef3, useState as useState5, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
969
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
970
|
+
function AppMenuBar() {
|
|
971
|
+
const fw = usePluginFramework();
|
|
972
|
+
const os = useOS();
|
|
973
|
+
const menus = fw.manager.menus;
|
|
974
|
+
useSyncExternalStore4(menus.subscribe, () => menus.version, () => menus.version);
|
|
975
|
+
const [open, setOpen] = useState5(null);
|
|
976
|
+
const ref = useRef3(null);
|
|
977
|
+
useEffect5(() => {
|
|
978
|
+
const off = (e) => ref.current && !ref.current.contains(e.target) && setOpen(null);
|
|
979
|
+
const key = (e) => e.key === "Escape" && setOpen(null);
|
|
980
|
+
window.addEventListener("mousedown", off);
|
|
981
|
+
window.addEventListener("keydown", key);
|
|
982
|
+
return () => (window.removeEventListener("mousedown", off), window.removeEventListener("keydown", key));
|
|
983
|
+
}, []);
|
|
984
|
+
const top = menus.items("application");
|
|
985
|
+
if (!top.length) return null;
|
|
986
|
+
const run = (item) => {
|
|
987
|
+
setOpen(null);
|
|
988
|
+
if (item.command) void fw.manager.commands.execute(item.command, ...item.args ?? []).catch((e) => fw.manager.logs.logger("host").error(String(e)));
|
|
989
|
+
else if (item.path) navigate(item.path);
|
|
990
|
+
};
|
|
991
|
+
const shortcut = (item) => {
|
|
992
|
+
const k = item.command ? fw.manager.commands.get(item.command)?.keybinding : void 0;
|
|
993
|
+
return k ? formatShortcut(k, os) : "";
|
|
994
|
+
};
|
|
995
|
+
return /* @__PURE__ */ jsx7("div", { className: "flux-menubar", role: "menubar", ref, children: top.map((m) => /* @__PURE__ */ jsxs7("div", { className: "flux-menu", children: [
|
|
996
|
+
/* @__PURE__ */ jsx7(
|
|
997
|
+
"button",
|
|
998
|
+
{
|
|
999
|
+
type: "button",
|
|
1000
|
+
role: "menuitem",
|
|
1001
|
+
className: "flux-tb-btn" + (open === m.id ? " is-open" : ""),
|
|
1002
|
+
"aria-haspopup": !!m.children?.length,
|
|
1003
|
+
"aria-expanded": open === m.id,
|
|
1004
|
+
onClick: () => m.children?.length ? setOpen(open === m.id ? null : m.id) : run(m),
|
|
1005
|
+
onMouseEnter: () => open && m.children?.length && setOpen(m.id),
|
|
1006
|
+
children: m.label
|
|
1007
|
+
}
|
|
1008
|
+
),
|
|
1009
|
+
open === m.id && m.children && /* @__PURE__ */ jsx7("ul", { className: "flux-dropdown", role: "menu", children: m.children.map(
|
|
1010
|
+
(c) => c.separator ? /* @__PURE__ */ jsx7("li", { className: "flux-sep", role: "separator" }, c.id) : /* @__PURE__ */ jsx7("li", { role: "none", children: /* @__PURE__ */ jsxs7("button", { type: "button", role: "menuitem", className: "flux-dd-item", onClick: () => run(c), children: [
|
|
1011
|
+
/* @__PURE__ */ jsx7("span", { children: c.label }),
|
|
1012
|
+
/* @__PURE__ */ jsx7("kbd", { children: shortcut(c) })
|
|
1013
|
+
] }) }, c.id)
|
|
1014
|
+
) })
|
|
1015
|
+
] }, m.id)) });
|
|
1016
|
+
}
|
|
1017
|
+
function SearchBox({ placeholder = "Search\u2026" }) {
|
|
1018
|
+
const fw = usePluginFramework();
|
|
1019
|
+
const providers = useExtensionItems("titlebar", "searchProviders");
|
|
1020
|
+
const [q, setQ] = useState5("");
|
|
1021
|
+
const [results, setResults] = useState5([]);
|
|
1022
|
+
const [idx, setIdx] = useState5(0);
|
|
1023
|
+
const [focus, setFocus] = useState5(false);
|
|
1024
|
+
const input = useRef3(null);
|
|
1025
|
+
useEffect5(() => {
|
|
1026
|
+
const k = (e) => (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "f" && !e.shiftKey && (e.preventDefault(), input.current?.focus());
|
|
1027
|
+
window.addEventListener("keydown", k);
|
|
1028
|
+
return () => window.removeEventListener("keydown", k);
|
|
1029
|
+
}, []);
|
|
1030
|
+
useEffect5(() => {
|
|
1031
|
+
const query = q.trim();
|
|
1032
|
+
if (!query) return setResults((prev) => prev.length ? [] : prev);
|
|
1033
|
+
let live = true;
|
|
1034
|
+
(async () => {
|
|
1035
|
+
const lower = query.toLowerCase();
|
|
1036
|
+
const own = [
|
|
1037
|
+
...fw.manager.commands.palette(query).slice(0, 5).map((c) => ({ id: "cmd:" + c.id, title: c.title, subtitle: c.category, group: "Commands", run: () => void fw.manager.commands.execute(c.id) })),
|
|
1038
|
+
...fw.manager.menus.items("sidebar").filter((m) => m.path && m.label.toLowerCase().includes(lower)).map((m) => ({ id: "page:" + m.id, title: m.label, group: "Pages", run: () => navigate(m.path) }))
|
|
1039
|
+
];
|
|
1040
|
+
const extra = await Promise.all(providers.map(async (p) => {
|
|
1041
|
+
try {
|
|
1042
|
+
return (await p.search(query) ?? []).map((r) => ({ ...r, group: r.group ?? p.label }));
|
|
1043
|
+
} catch {
|
|
1044
|
+
return [];
|
|
1045
|
+
}
|
|
1046
|
+
}));
|
|
1047
|
+
if (live) setResults([...own, ...extra.flat()].slice(0, 12)), setIdx(0);
|
|
1048
|
+
})();
|
|
1049
|
+
return () => {
|
|
1050
|
+
live = false;
|
|
1051
|
+
};
|
|
1052
|
+
}, [q, fw, providers]);
|
|
1053
|
+
const go = (r) => {
|
|
1054
|
+
if (!r) return;
|
|
1055
|
+
setQ("");
|
|
1056
|
+
input.current?.blur();
|
|
1057
|
+
void r.run();
|
|
1058
|
+
};
|
|
1059
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flux-search", "data-testid": "searchbox", children: [
|
|
1060
|
+
/* @__PURE__ */ jsx7(Icon, { name: "search" }),
|
|
1061
|
+
/* @__PURE__ */ jsx7(
|
|
1062
|
+
"input",
|
|
1063
|
+
{
|
|
1064
|
+
ref: input,
|
|
1065
|
+
value: q,
|
|
1066
|
+
placeholder,
|
|
1067
|
+
"aria-label": "Search",
|
|
1068
|
+
onChange: (e) => setQ(e.target.value),
|
|
1069
|
+
onFocus: () => setFocus(true),
|
|
1070
|
+
onBlur: () => setTimeout(() => setFocus(false), 120),
|
|
1071
|
+
onKeyDown: (e) => {
|
|
1072
|
+
if (e.key === "ArrowDown") e.preventDefault(), setIdx((i) => Math.min(i + 1, results.length - 1));
|
|
1073
|
+
else if (e.key === "ArrowUp") e.preventDefault(), setIdx((i) => Math.max(i - 1, 0));
|
|
1074
|
+
else if (e.key === "Enter") go(results[idx]);
|
|
1075
|
+
else if (e.key === "Escape") setQ(""), input.current?.blur();
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
),
|
|
1079
|
+
focus && q.trim() && /* @__PURE__ */ jsxs7("ul", { className: "flux-dropdown flux-search-results", role: "listbox", children: [
|
|
1080
|
+
results.length === 0 && /* @__PURE__ */ jsx7("li", { className: "flux-empty", children: "No results" }),
|
|
1081
|
+
results.map((r, i) => /* @__PURE__ */ jsxs7("li", { role: "option", "aria-selected": i === idx, children: [
|
|
1082
|
+
(i === 0 || results[i - 1].group !== r.group) && /* @__PURE__ */ jsx7("div", { className: "flux-group", children: r.group }),
|
|
1083
|
+
/* @__PURE__ */ jsxs7("button", { type: "button", className: "flux-dd-item" + (i === idx ? " is-active" : ""), onMouseDown: (e) => (e.preventDefault(), go(r)), children: [
|
|
1084
|
+
/* @__PURE__ */ jsx7("span", { children: r.title }),
|
|
1085
|
+
r.subtitle && /* @__PURE__ */ jsx7("small", { children: r.subtitle })
|
|
1086
|
+
] })
|
|
1087
|
+
] }, r.id))
|
|
1088
|
+
] })
|
|
1089
|
+
] });
|
|
1090
|
+
}
|
|
1091
|
+
function useNotifications() {
|
|
1092
|
+
const { manager } = usePluginFramework();
|
|
1093
|
+
const n = manager.notifications;
|
|
1094
|
+
useSyncExternalStore4(n.subscribe, () => n.version, () => n.version);
|
|
1095
|
+
return n;
|
|
1096
|
+
}
|
|
1097
|
+
function NotificationBell() {
|
|
1098
|
+
const fw = usePluginFramework();
|
|
1099
|
+
const center = useNotifications();
|
|
1100
|
+
const [open, setOpen] = useState5(false);
|
|
1101
|
+
const ref = useRef3(null);
|
|
1102
|
+
useEffect5(() => {
|
|
1103
|
+
const off = (e) => ref.current && !ref.current.contains(e.target) && setOpen(false);
|
|
1104
|
+
window.addEventListener("mousedown", off);
|
|
1105
|
+
return () => window.removeEventListener("mousedown", off);
|
|
1106
|
+
}, []);
|
|
1107
|
+
const unread = center.unread;
|
|
1108
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flux-bell", ref, children: [
|
|
1109
|
+
/* @__PURE__ */ jsxs7("button", { type: "button", className: "flux-tb-btn", "aria-label": "Notifications", "data-testid": "bell", onClick: () => (setOpen(!open), !open && center.markRead()), children: [
|
|
1110
|
+
/* @__PURE__ */ jsx7(Icon, { name: "bell" }),
|
|
1111
|
+
unread > 0 && /* @__PURE__ */ jsx7("span", { className: "flux-badge", "data-testid": "bell-count", children: unread })
|
|
1112
|
+
] }),
|
|
1113
|
+
open && /* @__PURE__ */ jsxs7("div", { className: "flux-dropdown flux-notif-panel", role: "dialog", "aria-label": "Notifications", children: [
|
|
1114
|
+
/* @__PURE__ */ jsxs7("div", { className: "flux-notif-head", children: [
|
|
1115
|
+
/* @__PURE__ */ jsx7("strong", { children: "Notifications" }),
|
|
1116
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "flux-link", onClick: () => center.clear(), children: "Clear all" })
|
|
1117
|
+
] }),
|
|
1118
|
+
center.list().length === 0 && /* @__PURE__ */ jsx7("div", { className: "flux-empty", children: "You're all caught up" }),
|
|
1119
|
+
center.list().map((n) => /* @__PURE__ */ jsxs7("div", { className: "flux-notif flux-" + n.level, children: [
|
|
1120
|
+
/* @__PURE__ */ jsxs7("div", { className: "flux-notif-main", children: [
|
|
1121
|
+
/* @__PURE__ */ jsx7("strong", { children: n.title }),
|
|
1122
|
+
n.body && /* @__PURE__ */ jsx7("p", { children: n.body }),
|
|
1123
|
+
/* @__PURE__ */ jsxs7("small", { children: [
|
|
1124
|
+
n.owner,
|
|
1125
|
+
" \xB7 ",
|
|
1126
|
+
new Date(n.time).toLocaleTimeString()
|
|
1127
|
+
] })
|
|
1128
|
+
] }),
|
|
1129
|
+
/* @__PURE__ */ jsxs7("div", { className: "flux-notif-actions", children: [
|
|
1130
|
+
n.actions.map((a) => /* @__PURE__ */ jsx7("button", { type: "button", className: "flux-link", onClick: () => void fw.manager.commands.execute(a.command, ...a.args ?? []), children: a.label }, a.label)),
|
|
1131
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "flux-link", "aria-label": "Dismiss", onClick: () => center.dismiss(n.id), children: /* @__PURE__ */ jsx7(Icon, { name: "close", size: 12 }) })
|
|
1132
|
+
] })
|
|
1133
|
+
] }, n.id))
|
|
1134
|
+
] })
|
|
1135
|
+
] });
|
|
1136
|
+
}
|
|
1137
|
+
function ToastHost() {
|
|
1138
|
+
const { manager } = usePluginFramework();
|
|
1139
|
+
const [toasts, setToasts] = useState5([]);
|
|
1140
|
+
useEffect5(() => {
|
|
1141
|
+
const timers = [];
|
|
1142
|
+
const show = (n, remaining = n.timeoutMs) => {
|
|
1143
|
+
if (n.timeoutMs <= 0 || remaining <= 0) return;
|
|
1144
|
+
setToasts((t) => [n, ...t.filter((x) => x.id !== n.id)].slice(0, 4));
|
|
1145
|
+
timers.push(setTimeout(() => setToasts((t) => t.filter((x) => x.id !== n.id)), remaining));
|
|
1146
|
+
};
|
|
1147
|
+
for (const n of [...manager.notifications.list()].reverse()) if (!n.read) show(n, n.timeoutMs - (Date.now() - n.time));
|
|
1148
|
+
const sub = manager.notifications.onPush((n) => show(n));
|
|
1149
|
+
return () => (sub.dispose(), timers.forEach(clearTimeout));
|
|
1150
|
+
}, [manager]);
|
|
1151
|
+
return /* @__PURE__ */ jsx7("div", { className: "flux-toasts", "aria-live": "polite", "data-testid": "toasts", children: toasts.map((n) => /* @__PURE__ */ jsxs7("div", { className: "flux-toast flux-" + n.level, role: "status", children: [
|
|
1152
|
+
/* @__PURE__ */ jsx7("strong", { children: n.title }),
|
|
1153
|
+
n.body && /* @__PURE__ */ jsxs7("span", { children: [
|
|
1154
|
+
" ",
|
|
1155
|
+
n.body
|
|
1156
|
+
] })
|
|
1157
|
+
] }, n.id)) });
|
|
1158
|
+
}
|
|
1159
|
+
function TitleBar({ title, logo, searchPlaceholder, show }) {
|
|
1160
|
+
const os = useOS();
|
|
1161
|
+
const electron = typeof window !== "undefined" && !!window.__fluxplugin;
|
|
1162
|
+
const s2 = { menu: true, search: true, notifications: true, theme: true, ...show };
|
|
1163
|
+
const brand = useMemo6(() => /* @__PURE__ */ jsxs7("div", { className: "flux-brand", children: [
|
|
1164
|
+
logo,
|
|
1165
|
+
title && /* @__PURE__ */ jsx7("span", { children: title })
|
|
1166
|
+
] }), [logo, title]);
|
|
1167
|
+
return /* @__PURE__ */ jsxs7("header", { className: "flux-titlebar", "data-os": os, "data-electron": electron || void 0, "data-testid": "titlebar", children: [
|
|
1168
|
+
/* @__PURE__ */ jsxs7("div", { className: "flux-tb-left", children: [
|
|
1169
|
+
brand,
|
|
1170
|
+
s2.menu && /* @__PURE__ */ jsx7(AppMenuBar, {}),
|
|
1171
|
+
/* @__PURE__ */ jsx7(PluginSlot, { name: "titlebar.left" })
|
|
1172
|
+
] }),
|
|
1173
|
+
/* @__PURE__ */ jsx7("div", { className: "flux-tb-center", children: s2.search && /* @__PURE__ */ jsx7(SearchBox, { placeholder: searchPlaceholder }) }),
|
|
1174
|
+
/* @__PURE__ */ jsxs7("div", { className: "flux-tb-right", children: [
|
|
1175
|
+
/* @__PURE__ */ jsx7(PluginSlot, { name: "titlebar.right" }),
|
|
1176
|
+
s2.theme && /* @__PURE__ */ jsx7(ThemeSwitcher, {}),
|
|
1177
|
+
s2.notifications && /* @__PURE__ */ jsx7(NotificationBell, {})
|
|
1178
|
+
] })
|
|
1179
|
+
] });
|
|
1180
|
+
}
|
|
1181
|
+
|
|
724
1182
|
export {
|
|
725
1183
|
RemoteError,
|
|
726
1184
|
PluginsClient,
|
|
@@ -755,5 +1213,20 @@ export {
|
|
|
755
1213
|
CommandPalette,
|
|
756
1214
|
baseCss,
|
|
757
1215
|
HttpBridgeError,
|
|
758
|
-
createHttpBridge
|
|
1216
|
+
createHttpBridge,
|
|
1217
|
+
detectOS,
|
|
1218
|
+
useOS,
|
|
1219
|
+
formatShortcut,
|
|
1220
|
+
Icon,
|
|
1221
|
+
iconNames,
|
|
1222
|
+
Markdown,
|
|
1223
|
+
declareHostPoints,
|
|
1224
|
+
ThemeProvider,
|
|
1225
|
+
useTheme,
|
|
1226
|
+
ThemeSwitcher,
|
|
1227
|
+
AppMenuBar,
|
|
1228
|
+
SearchBox,
|
|
1229
|
+
NotificationBell,
|
|
1230
|
+
ToastHost,
|
|
1231
|
+
TitleBar
|
|
759
1232
|
};
|
package/dist/browser/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
MGMT,
|
|
18
18
|
MemoryStorageBackend,
|
|
19
19
|
MenuRegistry,
|
|
20
|
+
NotificationCenter,
|
|
20
21
|
PermissionDeniedError,
|
|
21
22
|
PermissionManager,
|
|
22
23
|
PluginManager,
|
|
@@ -65,8 +66,9 @@ import {
|
|
|
65
66
|
serializeError,
|
|
66
67
|
toDisposable,
|
|
67
68
|
validateManifest,
|
|
69
|
+
videoEmbedUrl,
|
|
68
70
|
withTimeout
|
|
69
|
-
} from "./chunks/chunk-
|
|
71
|
+
} from "./chunks/chunk-TL63576R.js";
|
|
70
72
|
export {
|
|
71
73
|
BUILTIN_PERMISSIONS,
|
|
72
74
|
CHANNELS,
|
|
@@ -86,6 +88,7 @@ export {
|
|
|
86
88
|
MGMT,
|
|
87
89
|
MemoryStorageBackend,
|
|
88
90
|
MenuRegistry,
|
|
91
|
+
NotificationCenter,
|
|
89
92
|
PermissionDeniedError,
|
|
90
93
|
PermissionManager,
|
|
91
94
|
PluginManager,
|
|
@@ -134,5 +137,6 @@ export {
|
|
|
134
137
|
serializeError,
|
|
135
138
|
toDisposable,
|
|
136
139
|
validateManifest,
|
|
140
|
+
videoEmbedUrl,
|
|
137
141
|
withTimeout
|
|
138
142
|
};
|