minecodex 2.0.4 → 2.0.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.
- package/DESIGN.md +40 -1
- package/README.md +9 -3
- package/apps/dashboard/DESIGN.md +53 -31
- package/apps/dashboard/app.js +55 -39
- package/apps/dashboard/assets/OFL.txt +93 -0
- package/apps/dashboard/assets/info.svg +15 -0
- package/apps/dashboard/assets/moon.svg +13 -0
- package/apps/dashboard/assets/refresh-cw.svg +16 -0
- package/apps/dashboard/assets/silkscreen.ttf +0 -0
- package/apps/dashboard/assets/sun.svg +21 -0
- package/apps/dashboard/assets/terrain.js +89 -0
- package/apps/dashboard/assets/triangle-alert.svg +15 -0
- package/apps/dashboard/favicon.svg +12 -17
- package/apps/dashboard/index.html +24 -18
- package/apps/dashboard/styles.css +147 -181
- package/assets/brand/README.md +19 -0
- package/assets/brand/minecodex-icon-dark.svg +9 -0
- package/assets/brand/minecodex-icon-light.svg +9 -0
- package/assets/brand/minecodex-icon.svg +8 -0
- package/assets/brand/references/lucide-LICENSE.txt +43 -0
- package/assets/readme/hero.svg +93 -0
- package/features/hide-upsell-banner/README.md +7 -5
- package/features/hide-upsell-banner/codex-feature.json +2 -2
- package/features/hide-upsell-banner/src/hide-upsell-banner.mjs +30 -12
- package/features/images/DESIGN.md +117 -41
- package/features/images/README.md +26 -16
- package/features/images/codex-feature.json +6 -3
- package/features/images/src/adapters/codex/image-prompt.mjs +24 -2
- package/features/images/src/adapters/codex/image-sources.mjs +19 -0
- package/features/images/src/adapters/codex/library-api.mjs +2 -0
- package/features/images/src/adapters/codex/library-viewer.mjs +26 -2
- package/features/images/src/adapters/codex/native-image-modules.mjs +211 -0
- package/features/images/src/adapters/codex/native-image-source.mjs +449 -0
- package/features/images/src/backend/local-image-source.mjs +138 -0
- package/features/images/src/frontend/cloud-image-actions.mjs +41 -0
- package/features/images/src/frontend/local-image-source.mjs +195 -0
- package/features/images/src/library-prompt-page.mjs +163 -53
- package/features/images/src/library-prompt-source.mjs +9 -3
- package/features/images/src/prompt-index.mjs +14 -2
- package/features/model-slider/DESIGN.md +2 -0
- package/features/model-slider/codex-feature.json +2 -2
- package/features/model-slider/src/frontend/install.mjs +78 -11
- package/features/notes/DESIGN.md +7 -3
- package/features/notes/codex-feature.json +2 -2
- package/features/notes/src/frontend/entry.mjs +26 -9
- package/features/session-status/DESIGN.md +4 -2
- package/features/session-status/codex-feature.json +2 -2
- package/features/session-status/src/adapters/codex/session-log.mjs +2 -1
- package/features/session-status/src/domain/session-stats.mjs +17 -9
- package/features/session-status/src/session-status.mjs +47 -11
- package/features/sidebar-focus/DESIGN.md +4 -4
- package/features/sidebar-focus/codex-feature.json +3 -2
- package/features/sidebar-focus/src/adapters/codex/renderer.mjs +1 -1
- package/features/sidebar-focus/src/sidebar-focus.mjs +9 -7
- package/features/sites/DESIGN.md +25 -3
- package/features/sites/README.md +6 -2
- package/features/sites/codex-feature.json +3 -2
- package/features/sites/src/adapters/codex/renderer.mjs +25 -4
- package/features/sites/src/backend/project-sites.mjs +18 -6
- package/features/sites/src/backend/sites-service.mjs +22 -10
- package/features/sites/src/domain/discovery-candidates.mjs +53 -0
- package/features/sites/src/frontend/entry.mjs +76 -38
- package/features/sites/src/frontend/styles.css +3 -3
- package/features/unread-inbox/DESIGN.md +24 -25
- package/features/unread-inbox/codex-feature.json +3 -2
- package/features/unread-inbox/src/adapters/codex/modules.mjs +52 -0
- package/features/unread-inbox/src/adapters/codex/renderer.mjs +90 -0
- package/features/unread-inbox/src/domain/notifications.mjs +21 -0
- package/features/unread-inbox/src/injection-source.mjs +5 -2
- package/features/unread-inbox/src/unread-inbox.mjs +212 -297
- package/features/usage-meter/codex-feature.json +2 -2
- package/package.json +11 -3
- package/packages/cli/native/MineCodex.app/Contents/Info.plist +4 -2
- package/packages/cli/native/MineCodex.app/Contents/MacOS/MineCodexServiceManager +0 -0
- package/packages/cli/native/MineCodex.app/Contents/Resources/MineCodex.icns +0 -0
- package/packages/cli/native/MineCodex.app/Contents/_CodeSignature/CodeResources +11 -0
- package/packages/cli/native/README.md +31 -0
- package/packages/cli/src/browser-control-panel.mjs +48 -0
- package/packages/cli/src/commands.mjs +3 -1
- package/packages/cli/src/control-server.mjs +6 -3
- package/packages/cli/src/platform.mjs +5 -0
- package/packages/codex-adapter/README.md +2 -1
- package/packages/codex-adapter/src/renderer/environment.mjs +24 -6
- package/packages/runtime-host/README.md +10 -5
- package/packages/runtime-host/src/codex-injection.mjs +13 -9
- package/packages/runtime-host/src/codex-runtime.mjs +26 -5
- package/packages/runtime-host/src/feature-registry.mjs +1 -0
- package/packages/ui/DESIGN.md +9 -2
- package/packages/ui/assets/arrow-up-right.svg +14 -0
- package/packages/ui/assets/lucide-LICENSE.txt +43 -0
- package/packages/ui/src/components/account-menu.mjs +74 -0
- package/packages/ui/src/components/button.mjs +2 -0
- package/packages/ui/src/components/navigation-rail.mjs +18 -10
- package/packages/ui/src/components/page.mjs +9 -2
- package/packages/ui/src/foundation/layers.mjs +1 -0
- package/packages/ui/src/install.mjs +6 -1
- package/packages/ui/src/native/account-menu.mjs +21 -0
- package/packages/ui/src/native/navigation-rail.mjs +6 -1
- package/packages/ui/src/native/page.mjs +38 -0
- package/packages/ui/src/native/tokens.mjs +4 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export function installAccountMenuEntry(signal, ui, native) {
|
|
2
|
+
function accountMenuEntry({ label, icon, externalIcon, onOpen }) {
|
|
3
|
+
const marker = "data-mcx-account-menu-entry";
|
|
4
|
+
let node, anchor, entryBindings, opening = false;
|
|
5
|
+
const bindings = new AbortController();
|
|
6
|
+
function svg(source, template = null) {
|
|
7
|
+
const result = new DOMParser().parseFromString(source, "image/svg+xml").documentElement;
|
|
8
|
+
result.setAttribute("aria-hidden", "true");
|
|
9
|
+
result.removeAttribute("role");
|
|
10
|
+
result.removeAttribute("aria-labelledby");
|
|
11
|
+
result.querySelectorAll("title, desc").forEach(n => n.remove());
|
|
12
|
+
result.setAttribute("class", template?.getAttribute("class") ?? "icon-xs shrink-0");
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
async function activate(event) {
|
|
16
|
+
event?.preventDefault();
|
|
17
|
+
event?.stopPropagation();
|
|
18
|
+
if (opening) return;
|
|
19
|
+
opening = true;
|
|
20
|
+
const close = anchor.close;
|
|
21
|
+
try { await onOpen(); close(); }
|
|
22
|
+
catch (error) { console.warn("[MineCodex] Control panel could not open", error); window.alert(error.message); }
|
|
23
|
+
finally { opening = false; }
|
|
24
|
+
}
|
|
25
|
+
function sync() {
|
|
26
|
+
if (signal.aborted) return;
|
|
27
|
+
const found = native.settings();
|
|
28
|
+
if (!found) { entryBindings?.abort(); node?.remove(); node = null; anchor = null; return; }
|
|
29
|
+
if (node?.isConnected && anchor.item === found.item) return;
|
|
30
|
+
entryBindings?.abort();
|
|
31
|
+
entryBindings = new AbortController();
|
|
32
|
+
node?.remove();
|
|
33
|
+
anchor = found;
|
|
34
|
+
// 只修改脱离 React 的副本,保留原生 Settings 节点及事件。
|
|
35
|
+
node = found.item.cloneNode(true);
|
|
36
|
+
for (const element of [node, ...node.querySelectorAll("*")]) {
|
|
37
|
+
for (const attr of [...element.attributes]) {
|
|
38
|
+
if (attr.name === "id" || attr.name === "title" || attr.name.startsWith("aria-")
|
|
39
|
+
|| attr.name.startsWith("data-")) element.removeAttribute(attr.name);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
node.setAttribute(marker, "");
|
|
43
|
+
node.setAttribute("role", "menuitem");
|
|
44
|
+
node.tabIndex = -1;
|
|
45
|
+
const [leading, title, trailing] = node.querySelector("div").children;
|
|
46
|
+
leading.replaceChildren(svg(icon, leading.querySelector("svg")));
|
|
47
|
+
title.textContent = label;
|
|
48
|
+
trailing.replaceChildren(svg(externalIcon));
|
|
49
|
+
node.addEventListener("click", activate, { signal:entryBindings.signal });
|
|
50
|
+
node.addEventListener("pointermove", () => node.focus({ preventScroll:true }), { signal:entryBindings.signal });
|
|
51
|
+
found.item.after(node);
|
|
52
|
+
}
|
|
53
|
+
function keyboard(event) {
|
|
54
|
+
if (!anchor || !node?.isConnected || !anchor.menu.contains(event.target)) return;
|
|
55
|
+
const current = event.target.closest('[role="menuitem"]');
|
|
56
|
+
let next;
|
|
57
|
+
if (current === anchor.item && event.key === "ArrowDown") next = node;
|
|
58
|
+
else if (current === node && event.key === "ArrowUp") next = anchor.item;
|
|
59
|
+
else if (current === node && event.key === "ArrowDown") {
|
|
60
|
+
const items = [...anchor.menu.querySelectorAll('[role="menuitem"]')];
|
|
61
|
+
next = items[items.indexOf(node) + 1] ?? items[0];
|
|
62
|
+
} else if (current === node && ["Enter", " "].includes(event.key)) { void activate(event); return; }
|
|
63
|
+
if (next) { event.preventDefault(); event.stopImmediatePropagation(); next.focus({ preventScroll:true }); }
|
|
64
|
+
}
|
|
65
|
+
document.addEventListener("keydown", keyboard, { capture:true, signal:bindings.signal });
|
|
66
|
+
const observer = new MutationObserver(sync);
|
|
67
|
+
observer.observe(document.documentElement, { childList:true, subtree:true });
|
|
68
|
+
const dispose = () => { observer.disconnect(); bindings.abort(); entryBindings?.abort(); node?.remove(); node = null; anchor = null; };
|
|
69
|
+
signal.addEventListener("abort", dispose, { once:true });
|
|
70
|
+
sync();
|
|
71
|
+
return { sync, dispose };
|
|
72
|
+
}
|
|
73
|
+
return { accountMenuEntry };
|
|
74
|
+
}
|
|
@@ -11,6 +11,8 @@ export function installButton(signal, ui) {
|
|
|
11
11
|
[data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>[data-mcx-ui-action=primary]:hover:not(:disabled):not([aria-disabled=true]) { background:var(--mcx-color-background-primary-solid-hover); }
|
|
12
12
|
[data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>[data-mcx-ui-action=danger] { box-shadow:none; background:var(--mcx-color-background-danger-soft-alpha); color:var(--mcx-color-text-danger); }
|
|
13
13
|
[data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>[data-mcx-ui-action=danger]:hover:not(:disabled):not([aria-disabled=true]) { background:var(--mcx-color-background-danger-soft-alpha-hover); }
|
|
14
|
+
[data-mcx-ui-action=danger-solid], [data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>[data-mcx-ui-action=danger-solid] { box-shadow:none; border-color:transparent; background:var(--mcx-color-background-danger-solid); color:var(--mcx-color-text-danger-solid); }
|
|
15
|
+
[data-mcx-ui-action=danger-solid]:hover:not(:disabled):not([aria-disabled=true]), [data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>[data-mcx-ui-action=danger-solid]:hover:not(:disabled):not([aria-disabled=true]) { background:color-mix(in oklab,var(--mcx-color-background-danger-solid) 90%,transparent); }
|
|
14
16
|
[data-mcx-ui-surface=dialog] button:disabled { opacity:.4; cursor:default; }
|
|
15
17
|
[data-mcx-ui-surface=dialog] [data-mcx-ui-close]:focus-visible, [data-mcx-ui-surface=dialog] [data-mcx-ui-footer]>button:focus-visible { outline:2px solid var(--mcx-color-ring); outline-offset:0; }
|
|
16
18
|
`;
|
|
@@ -5,16 +5,19 @@ export function installNavigationRail(signal, ui, native) {
|
|
|
5
5
|
style.setAttribute("data-minecodex-ui-styles", "navigation-rail");
|
|
6
6
|
style.textContent = `[data-mcx-native-rail-icon-hidden]{display:none!important}`;
|
|
7
7
|
document.head.append(style);
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
function restoreNode(node, state) {
|
|
9
|
+
state.icon?.removeAttribute("data-mcx-native-rail-icon-hidden");
|
|
10
|
+
state.replacement?.remove();
|
|
11
|
+
if (!node.isConnected) return;
|
|
12
|
+
// 路由可能已变化,恢复当前 committed props,不回放旧选中态。
|
|
13
|
+
const attributes = native.attributes(node, [...state.attributes.keys()]) ?? state.attributes;
|
|
14
|
+
for (const [name, value] of attributes) {
|
|
15
|
+
if (value === null) node.removeAttribute(name);
|
|
16
|
+
else node.setAttribute(name, value);
|
|
17
17
|
}
|
|
18
|
+
}
|
|
19
|
+
function restore() {
|
|
20
|
+
for (const [node, state] of snapshots) restoreNode(node, state);
|
|
18
21
|
snapshots.clear();
|
|
19
22
|
}
|
|
20
23
|
function selection(button, selected) {
|
|
@@ -38,6 +41,10 @@ export function installNavigationRail(signal, ui, native) {
|
|
|
38
41
|
if (!icon) continue;
|
|
39
42
|
const item = native.item(node);
|
|
40
43
|
const active = item ? item.isCurrentDestination : node.getAttribute("aria-current") === "page";
|
|
44
|
+
if (!active && snapshots.has(node)) {
|
|
45
|
+
restoreNode(node, snapshots.get(node));
|
|
46
|
+
snapshots.delete(node);
|
|
47
|
+
}
|
|
41
48
|
if (!active && !snapshots.has(node)) native.remember(node, icon);
|
|
42
49
|
if (!selected || (!active && !node.hasAttribute("data-selected"))) continue;
|
|
43
50
|
let state = snapshots.get(node);
|
|
@@ -46,7 +53,7 @@ export function installNavigationRail(signal, ui, native) {
|
|
|
46
53
|
.map(name => [name, node.getAttribute(name)])) };
|
|
47
54
|
snapshots.set(node, state);
|
|
48
55
|
}
|
|
49
|
-
if (active && state.icon !== icon) {
|
|
56
|
+
if (active && (state.icon !== icon || !state.replacement?.isConnected)) {
|
|
50
57
|
state.icon?.removeAttribute("data-mcx-native-rail-icon-hidden");
|
|
51
58
|
state.replacement?.remove();
|
|
52
59
|
state.icon = icon;
|
|
@@ -57,6 +64,7 @@ export function installNavigationRail(signal, ui, native) {
|
|
|
57
64
|
icon.setAttribute("data-mcx-native-rail-icon-hidden", "");
|
|
58
65
|
}
|
|
59
66
|
}
|
|
67
|
+
if (state.replacement?.isConnected) state.icon?.setAttribute("data-mcx-native-rail-icon-hidden", "");
|
|
60
68
|
node.removeAttribute("data-selected");
|
|
61
69
|
node.removeAttribute("aria-current");
|
|
62
70
|
if (!node.hasAttribute("data-suppress-active-style")) node.setAttribute("data-suppress-active-style", "");
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
export function installPage(signal, ui) {
|
|
1
|
+
export function installPage(signal, ui, native) {
|
|
2
|
+
const pages = new Map();
|
|
3
|
+
signal.addEventListener("abort", () => { for (const lease of pages.values()) lease.release(); pages.clear(); }, { once:true });
|
|
2
4
|
return {
|
|
3
|
-
page(node, { transparent = false } = {}) {
|
|
5
|
+
page(node, { transparent = false, sidebar = "inherit", onNavigate } = {}) {
|
|
6
|
+
if (sidebar === "none" && !pages.has(node)) pages.set(node, native.standalone({ onNavigate }));
|
|
4
7
|
ui.surface(node, "page", { variant:transparent ? "transparent" : "opaque" });
|
|
5
8
|
return ui.layer(node, "page");
|
|
6
9
|
},
|
|
10
|
+
releasePage(node, options) {
|
|
11
|
+
pages.get(node)?.release(options);
|
|
12
|
+
pages.delete(node);
|
|
13
|
+
},
|
|
7
14
|
};
|
|
8
15
|
}
|
|
@@ -4,6 +4,7 @@ export function installLayers(signal) {
|
|
|
4
4
|
style.setAttribute("data-minecodex-ui-styles", "layers");
|
|
5
5
|
style.textContent = `
|
|
6
6
|
[data-mcx-ui-layer=page] { position:fixed; z-index:20; }
|
|
7
|
+
[data-mcx-ui-layer=notification] { position:fixed; z-index:30; }
|
|
7
8
|
[data-mcx-ui-layer=floating], [data-mcx-ui-layer=modal] { position:fixed; z-index:50; }
|
|
8
9
|
`;
|
|
9
10
|
document.head.append(style);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { createNativeAccountMenuAdapter } from "./native/account-menu.mjs";
|
|
2
|
+
import { installAccountMenuEntry } from "./components/account-menu.mjs";
|
|
1
3
|
import { createNativeThemeAdapter } from "./native/theme.mjs";
|
|
4
|
+
import { createNativePageAdapter } from "./native/page.mjs";
|
|
2
5
|
import { createNativeRailAdapter } from "./native/navigation-rail.mjs";
|
|
3
6
|
import { installSurfaces } from "./foundation/surfaces.mjs";
|
|
4
7
|
import { installLayers } from "./foundation/layers.mjs";
|
|
@@ -11,12 +14,14 @@ import { installFeatureTooltips } from "./components/tooltip.mjs";
|
|
|
11
14
|
|
|
12
15
|
// 所有依赖在组装时显式写入源码,Renderer 不依赖 Node 模块闭包。
|
|
13
16
|
export function createUIInstallerSource() {
|
|
14
|
-
const installers = [installSurfaces, installLayers, installDialog, installButton,
|
|
17
|
+
const installers = [installSurfaces, installLayers, installDialog, installButton, installComposerMenu];
|
|
15
18
|
return `function installFeatureUI(signal, context) {
|
|
16
19
|
const ui = {theme:(${createNativeThemeAdapter.toString()})(context.themeTokens,context.themeTokenAliases,context.themeBindings)};
|
|
17
20
|
${installers.map(install => `Object.assign(ui, (${install.toString()})(signal, ui));`).join("\n")}
|
|
21
|
+
Object.assign(ui, (${installPage.toString()})(signal, ui, (${createNativePageAdapter.toString()})(context.codex)));
|
|
18
22
|
Object.assign(ui, (${installNavigationRail.toString()})(signal, ui, (${createNativeRailAdapter.toString()})(context.codex)));
|
|
19
23
|
Object.assign(ui, (${installFeatureTooltips.toString()})(signal));
|
|
24
|
+
Object.assign(ui, (${installAccountMenuEntry.toString()})(signal, ui, (${createNativeAccountMenuAdapter.toString()})(context.codex)));
|
|
20
25
|
return ui;
|
|
21
26
|
}`;
|
|
22
27
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function createNativeAccountMenuAdapter(codex) {
|
|
2
|
+
function settings() {
|
|
3
|
+
for (const menu of document.querySelectorAll('[role="menu"]')) {
|
|
4
|
+
if (!menu.checkVisibility({ visibilityProperty:true })) continue;
|
|
5
|
+
for (const item of menu.querySelectorAll('[role="menuitem"]')) {
|
|
6
|
+
const profile = codex.props(item, p => typeof p.onOpenSettings === "function" && "settingsShortcut" in p);
|
|
7
|
+
if (!profile || !codex.props(item, p => p.onClick === profile.onOpenSettings)) continue;
|
|
8
|
+
const content = item.querySelector('[data-menu-row-content]');
|
|
9
|
+
const [leading, label, shortcut] = content?.children ?? [];
|
|
10
|
+
if (!leading?.querySelector('svg') || !label || !shortcut) continue;
|
|
11
|
+
const owner = codex.props(item, p => typeof p.onClose === "function" && "open" in p);
|
|
12
|
+
if (!owner) continue;
|
|
13
|
+
codex.report("account-menu", true);
|
|
14
|
+
return { menu, item, close:owner.onClose };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
codex.report("account-menu", false, "profile-menu-unavailable");
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return { settings };
|
|
21
|
+
}
|
|
@@ -28,6 +28,11 @@ export function createNativeRailAdapter(codex) {
|
|
|
28
28
|
}
|
|
29
29
|
return defaultIcons.get(node)?.cloneNode(true) ?? null;
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
function attributes(node, names) {
|
|
32
|
+
const props = codex.currentFiber(node)?.memoizedProps;
|
|
33
|
+
if (!props || !names.some(name => Object.hasOwn(props, name))) return null;
|
|
34
|
+
return new Map(names.map(name => [name, props[name] == null ? null : String(props[name])]));
|
|
35
|
+
}
|
|
36
|
+
return { item:nativeItem, icon:defaultIcon, attributes,
|
|
32
37
|
remember:(node, icon) => defaultIcons.set(node, icon.cloneNode(true)) };
|
|
33
38
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// 原生页面壳由路由决定;借用 Projects 的无上下文侧栏壳,不改侧栏展开偏好。
|
|
2
|
+
export function createNativePageAdapter(codex) {
|
|
3
|
+
function standalone({ onNavigate } = {}) {
|
|
4
|
+
const rail = codex.rail();
|
|
5
|
+
const scope = codex.props(rail, props => Boolean((props.router ?? props.value?.router)?.navigate));
|
|
6
|
+
const router = scope?.router ?? scope?.value?.router;
|
|
7
|
+
const origin = router?.state?.location;
|
|
8
|
+
if (!origin) throw new Error("The native page navigation was not found");
|
|
9
|
+
if (onNavigate && typeof router.subscribe !== "function") throw new Error("The native page navigation subscription was not found");
|
|
10
|
+
const target = "/projects";
|
|
11
|
+
const changed = origin.pathname !== target;
|
|
12
|
+
if (changed) void router.navigate(target, { replace:true, state:origin.state });
|
|
13
|
+
let released = false;
|
|
14
|
+
let unsubscribe = null;
|
|
15
|
+
let shell = router.state.location.pathname === target ? router.state.location : null;
|
|
16
|
+
const lease = {
|
|
17
|
+
release({ restoreNavigation=true } = {}) {
|
|
18
|
+
if (released) return;
|
|
19
|
+
released = true;
|
|
20
|
+
unsubscribe?.();
|
|
21
|
+
if (changed && restoreNavigation && router.state.location.pathname === target)
|
|
22
|
+
void router.navigate(origin, { replace:true, state:origin.state });
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
if (onNavigate) unsubscribe = router.subscribe(state => {
|
|
26
|
+
if (released || (state.navigation?.state && state.navigation.state !== "idle")) return;
|
|
27
|
+
const location = state.location;
|
|
28
|
+
// 等待借用页面壳的首次提交;hover 和 loader 通知不代表用户离开。
|
|
29
|
+
if (!shell && location === origin) return;
|
|
30
|
+
if (!shell && location.pathname === target) { shell = location; return; }
|
|
31
|
+
if (location === shell) return;
|
|
32
|
+
lease.release({ restoreNavigation:false });
|
|
33
|
+
onNavigate();
|
|
34
|
+
});
|
|
35
|
+
return lease;
|
|
36
|
+
}
|
|
37
|
+
return { standalone };
|
|
38
|
+
}
|
|
@@ -39,6 +39,7 @@ export const CODEX_THEME_TOKENS = Object.freeze([
|
|
|
39
39
|
"--color-background-elevated-primary-opaque",
|
|
40
40
|
"--color-background-primary-ghost-hover",
|
|
41
41
|
"--color-chart-blue",
|
|
42
|
+
"--color-chart-green",
|
|
42
43
|
"--color-chart-purple",
|
|
43
44
|
"--color-background-panel",
|
|
44
45
|
"--color-background-control",
|
|
@@ -135,6 +136,9 @@ export const CODEX_THEME_TOKENS = Object.freeze([
|
|
|
135
136
|
"--color-background-danger-soft-alpha",
|
|
136
137
|
"--color-background-danger-soft-alpha-hover",
|
|
137
138
|
"--color-text-danger",
|
|
139
|
+
"--color-background-danger-solid",
|
|
140
|
+
"--color-background-danger-solid-hover",
|
|
141
|
+
"--color-text-danger-solid",
|
|
138
142
|
]);
|
|
139
143
|
|
|
140
144
|
// images 图片编辑器可用性依赖的项目 token 子集。
|