@hienlh/ppm 0.18.9 → 0.18.10
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/.spike/group-protected-probe.ts +21 -0
- package/.spike/tunnel.err +22 -42
- package/.spike/w.err +26 -94
- package/CHANGELOG.md +12 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{ai-resource-editor-DFCuNe-P.js → ai-resource-editor-mdDKG-rw.js} +1 -1
- package/dist/web/assets/{chat-tab-flMPLoKb.js → chat-tab-C060A94y.js} +3 -3
- package/dist/web/assets/{code-editor-C2VQbXzw.js → code-editor-WELegzdp.js} +2 -2
- package/dist/web/assets/{conflict-editor-CdH_h0vD.js → conflict-editor-fRTU3f1o.js} +1 -1
- package/dist/web/assets/{csv-preview-CY_454vd.js → csv-preview-D1d0cxOJ.js} +1 -1
- package/dist/web/assets/{database-viewer-BCZOTrPT.js → database-viewer-DevnWTV4.js} +1 -1
- package/dist/web/assets/{diff-viewer-BwfMN-nW.js → diff-viewer-DGxVg1pD.js} +1 -1
- package/dist/web/assets/{docx-preview-D3Sdh_aT.js → docx-preview-Cx-zLwAw.js} +1 -1
- package/dist/web/assets/{explorer-body-BKOMM566.js → explorer-body-j_4hVc34.js} +1 -1
- package/dist/web/assets/{explorer-window-content-Bbzijk8t.js → explorer-window-content-DdrGwk3w.js} +1 -1
- package/dist/web/assets/{extension-webview-CuOQrHIS.js → extension-webview-BH_mWYMe.js} +1 -1
- package/dist/web/assets/format-bytes-BE_W3UBg.js +1 -0
- package/dist/web/assets/{git-log-panel-DcV7PhqW.js → git-log-panel-CfpXRJcP.js} +1 -1
- package/dist/web/assets/{glide-data-grid-Cehfgrzc.js → glide-data-grid-n4ox_uev.js} +1 -1
- package/dist/web/assets/{group-chat-tab-BVPYxjz-.js → group-chat-tab-dYuuknLN.js} +1 -1
- package/dist/web/assets/{image-preview-D-Ok10eZ.js → image-preview-Ss38ex8g.js} +1 -1
- package/dist/web/assets/index-BiTiXgBZ.css +2 -0
- package/dist/web/assets/{index-CerSxGdf.js → index-Ch8l9de-.js} +5 -5
- package/dist/web/assets/{keybindings-store-aIY40k2o.js → keybindings-store-CDfTjwZX.js} +1 -1
- package/dist/web/assets/{markdown-renderer-pVzBdkpl.js → markdown-renderer-B317vEys.js} +1 -1
- package/dist/web/assets/{markdown-renderer-I89kyQhe.js → markdown-renderer-CpRlpLHw.js} +1 -1
- package/dist/web/assets/{mobile-explorer-sheet-5Uj9ZMM9.js → mobile-explorer-sheet-D1Bv9UCT.js} +1 -1
- package/dist/web/assets/{notification-store-DJ-OtAG3.js → notification-store-KwTAZT8b.js} +1 -1
- package/dist/web/assets/overview-panel-BxDohIEa.js +1 -0
- package/dist/web/assets/{pdf-preview-Di5xHFyT.js → pdf-preview-dwRe54ht.js} +1 -1
- package/dist/web/assets/{postgres-viewer-CR6VpTrX.js → postgres-viewer-BWZLW7kI.js} +1 -1
- package/dist/web/assets/process-table-CI-fnVsy.js +1 -0
- package/dist/web/assets/resolve-theme-B9ABAH_3.js +1 -0
- package/dist/web/assets/{settings-tab-jbiQwozX.js → settings-tab-mPxrKkfm.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BPYsJDsn.js → sql-query-editor-BwPjEaP9.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-Bq9ZJA2y.js → sqlite-viewer-Cs-_D942.js} +1 -1
- package/dist/web/assets/{system-monitor-body-CKEYWyN9.js → system-monitor-body-CV7-0hZG.js} +2 -2
- package/dist/web/assets/{system-monitor-tab-WjhFFHyM.js → system-monitor-tab-Ce-8Axhh.js} +1 -1
- package/dist/web/assets/{system-monitor-window-content-CMiISeoC.js → system-monitor-window-content-CetwYOQy.js} +1 -1
- package/dist/web/assets/{team-member-sheet-oY5EkH53.js → team-member-sheet-CjgaQjsZ.js} +2 -2
- package/dist/web/assets/{team-member-window-content-yCBeI_5X.js → team-member-window-content-DNJiYWS7.js} +1 -1
- package/dist/web/assets/{terminal-tab-BxHtMR7h.js → terminal-tab-DF7521sT.js} +1 -1
- package/dist/web/assets/{tool-cards-BcGrk1zk.js → tool-cards-DCAXGDJI.js} +2 -2
- package/dist/web/assets/{use-monaco-theme-CGucu3fb.js → use-monaco-theme-DSCdlrjO.js} +1 -1
- package/dist/web/assets/{use-open-team-member-DdrRXj-M.js → use-open-team-member-H4k74HnV.js} +1 -1
- package/dist/web/assets/{use-websocket-C-Rxv8JN.js → use-websocket-iJfc7EbK.js} +1 -1
- package/dist/web/assets/{video-preview-DYAbbmd0.js → video-preview-B0ZWpX0F.js} +1 -1
- package/dist/web/index.html +3 -3
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/web/components/system/build-kill-request.ts +28 -1
- package/src/web/components/system/chart-scale.ts +3 -3
- package/src/web/components/system/kill-confirm-dialog.tsx +44 -28
- package/src/web/components/system/metric-chart-canvas.tsx +1 -2
- package/src/web/components/system/process-columns-grid.ts +39 -29
- package/src/web/components/system/process-group-row.tsx +31 -8
- package/src/web/components/system/process-row.tsx +6 -7
- package/src/web/components/system/process-table-model.ts +4 -22
- package/src/web/components/system/process-table-toolbar.tsx +12 -43
- package/src/web/components/system/process-table.tsx +22 -63
- package/src/web/components/system/sortable-header.tsx +33 -8
- package/src/web/components/system/system-monitor-body.tsx +1 -1
- package/src/web/components/system/use-column-widths.ts +91 -0
- package/src/web/components/system/use-process-kill.ts +100 -0
- package/src/web/styles/globals.css +5 -3
- package/src/web/theme/builtin/aurora.ts +8 -5
- package/dist/web/assets/format-bytes-Dk7B73B7.js +0 -1
- package/dist/web/assets/index-DRA_OpWY.css +0 -2
- package/dist/web/assets/overview-panel-Cgi3UPY1.js +0 -1
- package/dist/web/assets/process-table-DL6shbzt.js +0 -1
- package/dist/web/assets/resolve-theme-IdhSR-gx.js +0 -1
- package/src/web/components/system/sparkline-canvas.tsx +0 -63
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { ArrowUp, ArrowDown } from "lucide-react";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
3
|
import type { SortDir, SortKey } from "../../../types/system-metrics";
|
|
4
|
+
import type { ResizableColumnKey } from "./process-columns-grid";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
export interface ColumnResizeHandlers {
|
|
7
|
+
onResizeStart: (key: ResizableColumnKey, e: { clientX: number; preventDefault: () => void }) => void;
|
|
8
|
+
onResizeReset: (key: ResizableColumnKey) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Sortable column header shared by the process table toolbar. Renders as a
|
|
12
|
+
* `columnheader` `<div>`, not a `<th>` — the parent row is a CSS-grid
|
|
13
|
+
* `<div role="row">`, and a `<th>` inside a non-table ancestor both triggers React's
|
|
14
|
+
* DOM-nesting warning and makes `aria-sort` meaningless to assistive tech outside
|
|
15
|
+
* an actual table. */
|
|
10
16
|
export function SortableHeader({
|
|
11
17
|
label,
|
|
12
18
|
field,
|
|
@@ -16,6 +22,8 @@ export function SortableHeader({
|
|
|
16
22
|
align = "right",
|
|
17
23
|
testId,
|
|
18
24
|
className,
|
|
25
|
+
resizeKey,
|
|
26
|
+
resize,
|
|
19
27
|
}: {
|
|
20
28
|
label: string;
|
|
21
29
|
field: Exclude<SortKey, null>;
|
|
@@ -29,6 +37,9 @@ export function SortableHeader({
|
|
|
29
37
|
/** Extra classes on the outer `columnheader` — e.g. the `hidden @lg:block`
|
|
30
38
|
* visibility rule an optional (Disk/GPU/Net) column needs below `@lg`. */
|
|
31
39
|
className?: string;
|
|
40
|
+
/** Present for fixed-width columns: renders the drag handle on the right edge. */
|
|
41
|
+
resizeKey?: ResizableColumnKey;
|
|
42
|
+
resize?: ColumnResizeHandlers;
|
|
32
43
|
}) {
|
|
33
44
|
const isActive = activeKey === field;
|
|
34
45
|
const Arrow = isActive ? (activeDir === "asc" ? ArrowUp : ArrowDown) : null;
|
|
@@ -39,7 +50,7 @@ export function SortableHeader({
|
|
|
39
50
|
role="columnheader"
|
|
40
51
|
aria-sort={ariaSort}
|
|
41
52
|
className={cn(
|
|
42
|
-
"py-1.5 px-2 font-medium select-none",
|
|
53
|
+
"relative py-1.5 px-2 font-medium select-none",
|
|
43
54
|
align === "left" ? "text-left" : "text-right",
|
|
44
55
|
className,
|
|
45
56
|
)}
|
|
@@ -57,9 +68,23 @@ export function SortableHeader({
|
|
|
57
68
|
isActive && "text-text-primary",
|
|
58
69
|
)}
|
|
59
70
|
>
|
|
60
|
-
<span>{label}</span>
|
|
61
|
-
{Arrow && <Arrow className="size-3" />}
|
|
71
|
+
<span className="truncate">{label}</span>
|
|
72
|
+
{Arrow && <Arrow className="size-3 shrink-0" />}
|
|
62
73
|
</button>
|
|
74
|
+
{/* Drag handle: pointer-only (hidden below `md`, where the table is a
|
|
75
|
+
single narrow column set and there is nothing worth resizing). Double-click
|
|
76
|
+
returns the column to its default width. */}
|
|
77
|
+
{resizeKey && resize && (
|
|
78
|
+
<div
|
|
79
|
+
role="separator"
|
|
80
|
+
aria-orientation="vertical"
|
|
81
|
+
aria-label={`Resize ${label} column`}
|
|
82
|
+
data-testid={testId ? `${testId}-resize` : undefined}
|
|
83
|
+
onPointerDown={(e) => resize.onResizeStart(resizeKey, e)}
|
|
84
|
+
onDoubleClick={() => resize.onResizeReset(resizeKey)}
|
|
85
|
+
className="hidden md:block absolute top-0 -right-1 h-full w-2 cursor-col-resize hover:bg-primary/40 active:bg-primary/60"
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
63
88
|
</div>
|
|
64
89
|
);
|
|
65
90
|
}
|
|
@@ -137,7 +137,7 @@ export const SystemMonitorBody = memo(function SystemMonitorBody({
|
|
|
137
137
|
) : tab === "overview" ? (
|
|
138
138
|
<OverviewPanel system={latest.system} history={history} />
|
|
139
139
|
) : (
|
|
140
|
-
<ProcessTable snapshot={latest}
|
|
140
|
+
<ProcessTable snapshot={latest} />
|
|
141
141
|
)}
|
|
142
142
|
</Suspense>
|
|
143
143
|
</div>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { clampColumnWidth, columnWidthPx, type ColumnWidths, type ResizableColumnKey } from "./process-columns-grid";
|
|
3
|
+
|
|
4
|
+
/** One entry for the whole app: column widths are a per-device preference, not
|
|
5
|
+
* per-window state, so they survive reloads and apply to the mobile tab too. */
|
|
6
|
+
export const COLUMN_WIDTHS_STORAGE_KEY = "ppm-sysmon-col-widths";
|
|
7
|
+
|
|
8
|
+
function loadWidths(): ColumnWidths {
|
|
9
|
+
try {
|
|
10
|
+
const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY);
|
|
11
|
+
if (!raw) return {};
|
|
12
|
+
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
13
|
+
const out: ColumnWidths = {};
|
|
14
|
+
for (const k of ["cpu", "ram", "disk", "gpu", "net"] as ResizableColumnKey[]) {
|
|
15
|
+
const v = parsed[k];
|
|
16
|
+
if (typeof v === "number" && Number.isFinite(v)) out[k] = clampColumnWidth(v);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function saveWidths(widths: ColumnWidths): void {
|
|
25
|
+
try {
|
|
26
|
+
if (Object.keys(widths).length === 0) localStorage.removeItem(COLUMN_WIDTHS_STORAGE_KEY);
|
|
27
|
+
else localStorage.setItem(COLUMN_WIDTHS_STORAGE_KEY, JSON.stringify(widths));
|
|
28
|
+
} catch {
|
|
29
|
+
/* private mode / quota — widths just don't persist */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Drag-to-resize state for the process table's fixed-width columns.
|
|
35
|
+
*
|
|
36
|
+
* `begin(key, event)` is wired to `pointerdown` on a header's right-edge handle;
|
|
37
|
+
* the drag then follows `pointermove`/`pointerup` on `window`, so the pointer may
|
|
38
|
+
* leave the handle (or the window body) without dropping the drag. Widths persist
|
|
39
|
+
* on release, not on every move. `reset(key)` (double-click) returns one column
|
|
40
|
+
* to its default.
|
|
41
|
+
*/
|
|
42
|
+
export function useColumnWidths() {
|
|
43
|
+
const [widths, setWidths] = useState<ColumnWidths>(() => (typeof localStorage === "undefined" ? {} : loadWidths()));
|
|
44
|
+
const drag = useRef<{ key: ResizableColumnKey; startX: number; startWidth: number } | null>(null);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const onMove = (e: PointerEvent) => {
|
|
48
|
+
const d = drag.current;
|
|
49
|
+
if (!d) return;
|
|
50
|
+
const next = clampColumnWidth(d.startWidth + (e.clientX - d.startX));
|
|
51
|
+
setWidths((prev) => (prev[d.key] === next ? prev : { ...prev, [d.key]: next }));
|
|
52
|
+
};
|
|
53
|
+
const onUp = () => {
|
|
54
|
+
if (!drag.current) return;
|
|
55
|
+
drag.current = null;
|
|
56
|
+
document.body.style.cursor = "";
|
|
57
|
+
setWidths((prev) => {
|
|
58
|
+
saveWidths(prev);
|
|
59
|
+
return prev;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
window.addEventListener("pointermove", onMove);
|
|
63
|
+
window.addEventListener("pointerup", onUp);
|
|
64
|
+
window.addEventListener("pointercancel", onUp);
|
|
65
|
+
return () => {
|
|
66
|
+
window.removeEventListener("pointermove", onMove);
|
|
67
|
+
window.removeEventListener("pointerup", onUp);
|
|
68
|
+
window.removeEventListener("pointercancel", onUp);
|
|
69
|
+
};
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
const begin = useCallback(
|
|
73
|
+
(key: ResizableColumnKey, e: { clientX: number; preventDefault: () => void }) => {
|
|
74
|
+
e.preventDefault(); // no text selection while dragging
|
|
75
|
+
drag.current = { key, startX: e.clientX, startWidth: columnWidthPx(key, widths) };
|
|
76
|
+
document.body.style.cursor = "col-resize";
|
|
77
|
+
},
|
|
78
|
+
[widths],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const reset = useCallback((key: ResizableColumnKey) => {
|
|
82
|
+
setWidths((prev) => {
|
|
83
|
+
if (!(key in prev)) return prev;
|
|
84
|
+
const { [key]: _dropped, ...rest } = prev;
|
|
85
|
+
saveWidths(rest);
|
|
86
|
+
return rest;
|
|
87
|
+
});
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
return { widths, begin, reset };
|
|
91
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { toast } from "sonner";
|
|
3
|
+
import { getAuthToken } from "@/lib/api-client";
|
|
4
|
+
import { buildGroupKillRequests, buildKillRequest, isGroupProtected, type KillTarget } from "./build-kill-request";
|
|
5
|
+
import type {
|
|
6
|
+
KillProcessRequest,
|
|
7
|
+
KillProcessResult,
|
|
8
|
+
MetricsSnapshot,
|
|
9
|
+
ProcessGroup,
|
|
10
|
+
ProcessInfo,
|
|
11
|
+
} from "../../../types/system-metrics";
|
|
12
|
+
|
|
13
|
+
/** `api.post` (src/web/lib/api-client.ts) has no way to add a bespoke header, and the
|
|
14
|
+
* kill route requires `X-PPM-Request: 1` — CSRF hardening, since a cross-origin HTML
|
|
15
|
+
* form cannot set a custom header, so a preflight becomes mandatory. A raw fetch here
|
|
16
|
+
* mirrors `handleResponse`'s single-Error-on-any-failure contract exactly, so the
|
|
17
|
+
* caller still has exactly one catch path. */
|
|
18
|
+
export async function killProcess(request: KillProcessRequest): Promise<KillProcessResult> {
|
|
19
|
+
const token = getAuthToken();
|
|
20
|
+
const headers: Record<string, string> = {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"X-PPM-Request": "1",
|
|
23
|
+
};
|
|
24
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
25
|
+
|
|
26
|
+
const res = await fetch("/api/system/resources/kill", {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers,
|
|
29
|
+
body: JSON.stringify(request),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
let json: { ok: boolean; data?: KillProcessResult; error?: string };
|
|
33
|
+
try {
|
|
34
|
+
json = await res.json();
|
|
35
|
+
} catch {
|
|
36
|
+
throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
|
|
37
|
+
}
|
|
38
|
+
if (json.ok === false) throw new Error(json.error ?? `HTTP ${res.status}`);
|
|
39
|
+
return json.data as KillProcessResult;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Pending-kill state plus the confirm handler for single processes and whole app
|
|
44
|
+
* groups. Members are resolved against the CURRENT snapshot at click time, so a
|
|
45
|
+
* helper that exited since the row was drawn is simply not in the list.
|
|
46
|
+
*/
|
|
47
|
+
export function useProcessKill(snapshot: MetricsSnapshot) {
|
|
48
|
+
const [pendingKill, setPendingKill] = useState<KillTarget | null>(null);
|
|
49
|
+
|
|
50
|
+
const membersOf = useCallback(
|
|
51
|
+
(group: ProcessGroup): ProcessInfo[] => {
|
|
52
|
+
const byPid = new Map(snapshot.processes.map((p) => [p.pid, p]));
|
|
53
|
+
return group.pids.map((pid) => byPid.get(pid)).filter((p): p is ProcessInfo => !!p);
|
|
54
|
+
},
|
|
55
|
+
[snapshot.processes],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/** group key → true when any member is refused by the guard (button disabled). */
|
|
59
|
+
const groupProtected = useMemo(
|
|
60
|
+
() => new Map(snapshot.groups.map((g) => [g.key, isGroupProtected(membersOf(g))])),
|
|
61
|
+
[snapshot.groups, membersOf],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const requestKillProcess = useCallback((proc: ProcessInfo) => setPendingKill({ kind: "process", proc }), []);
|
|
65
|
+
const requestKillGroup = useCallback(
|
|
66
|
+
(group: ProcessGroup) => setPendingKill({ kind: "group", group, members: membersOf(group) }),
|
|
67
|
+
[membersOf],
|
|
68
|
+
);
|
|
69
|
+
const cancelKill = useCallback(() => setPendingKill(null), []);
|
|
70
|
+
|
|
71
|
+
const confirmKill = useCallback(async (target: KillTarget, tree: boolean) => {
|
|
72
|
+
setPendingKill(null);
|
|
73
|
+
if (target.kind === "process") {
|
|
74
|
+
const { proc } = target;
|
|
75
|
+
try {
|
|
76
|
+
await killProcess(buildKillRequest(proc, tree));
|
|
77
|
+
toast.success(`Ended ${proc.name} (${proc.pid})`);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
toast.error(e instanceof Error ? e.message : `Failed to end ${proc.name}`);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Whole app: one tree kill on the root when it exists, else one per member.
|
|
84
|
+
// Requests run sequentially so the guard's 403/409 for one member is reported,
|
|
85
|
+
// not lost in a Promise.all rejection.
|
|
86
|
+
const { group, members } = target;
|
|
87
|
+
const failures: string[] = [];
|
|
88
|
+
for (const req of buildGroupKillRequests(group, members)) {
|
|
89
|
+
try {
|
|
90
|
+
await killProcess(req);
|
|
91
|
+
} catch (e) {
|
|
92
|
+
failures.push(e instanceof Error ? e.message : `pid ${req.pid}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (failures.length === 0) toast.success(`Ended ${group.label} (${members.length} processes)`);
|
|
96
|
+
else toast.error(`${group.label}: ${failures.length} of ${members.length} could not be ended — ${failures[0]}`);
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
return { pendingKill, groupProtected, requestKillProcess, requestKillGroup, confirmKill, cancelKill };
|
|
100
|
+
}
|
|
@@ -74,13 +74,15 @@
|
|
|
74
74
|
/*
|
|
75
75
|
* Default token values (Aurora Dark). Present before JS runs so the first
|
|
76
76
|
* paint is correct; apply-theme overrides these on <html> at runtime.
|
|
77
|
+
* Surfaces stay opaque here for the same reason they are in the theme itself:
|
|
78
|
+
* a translucent panel lets content bleed through dropdowns and sheets.
|
|
77
79
|
*/
|
|
78
80
|
:root {
|
|
79
81
|
--bg: radial-gradient(120% 120% at 0% 0%, #0e1626 0%, #0a0e17 55%, #080b12 100%);
|
|
80
82
|
--bg-solid: #0a0e17;
|
|
81
|
-
--rail:
|
|
82
|
-
--panel:
|
|
83
|
-
--panel-2:
|
|
83
|
+
--rail: #141820;
|
|
84
|
+
--panel: #141820;
|
|
85
|
+
--panel-2: #141c2e;
|
|
84
86
|
--border: rgba(255, 255, 255, 0.12);
|
|
85
87
|
--border-soft: rgba(255, 255, 255, 0.06);
|
|
86
88
|
--text: #eaeefb;
|
|
@@ -51,16 +51,19 @@ export const auroraLight: PpmTheme = {
|
|
|
51
51
|
mode: "light",
|
|
52
52
|
swatch: ["#f3f7ff", "#2f6bff", "#7c4dff"],
|
|
53
53
|
syntax: { shikiTheme: "github-light" },
|
|
54
|
+
// Surfaces are opaque on purpose: translucent panels let underlying content
|
|
55
|
+
// bleed through dropdowns, sheets and stacked windows and hurt legibility.
|
|
56
|
+
// Values are the old glass tints pre-blended over bgSolid.
|
|
54
57
|
mobileOverrides: {
|
|
55
|
-
panel: "
|
|
56
|
-
panel2: "
|
|
58
|
+
panel: "#ffffff",
|
|
59
|
+
panel2: "#ffffff",
|
|
57
60
|
},
|
|
58
61
|
tokens: {
|
|
59
62
|
bg: "radial-gradient(120% 120% at 0% 0%, #f3f7ff 0%, #eef2fb 55%, #e8edf7 100%)",
|
|
60
63
|
bgSolid: "#f3f7ff",
|
|
61
|
-
rail: "
|
|
62
|
-
panel: "
|
|
63
|
-
panel2: "
|
|
64
|
+
rail: "#fafcff",
|
|
65
|
+
panel: "#fafcff",
|
|
66
|
+
panel2: "#ffffff",
|
|
64
67
|
border: "rgba(20,30,60,0.12)",
|
|
65
68
|
borderSoft: "rgba(20,30,60,0.07)",
|
|
66
69
|
text: "#0f1a33",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(e,t){return t===void 0?Math.max(...e,1):t}function t(e,t){let n=/^var\((--[\w-]+)\)$/.exec(e.trim());return n&&t.getPropertyValue(n[1]).trim()||e}function n(e){return e<1024?`${e.toFixed(0)} MB`:`${(e/1024).toFixed(1)} GB`}function r(e){if(e<1024)return`${e.toFixed(0)} B/s`;let t=e/1024;if(t<1024)return`${t.toFixed(1)} KB/s`;let n=t/1024;return n<1024?`${n.toFixed(1)} MB/s`:`${(n/1024).toFixed(1)} GB/s`}export{e as i,n,t as r,r as t};
|