mirror of
https://github.com/Heretek-AI/ompweb.git
synced 2026-11-09 02:39:49 -10:00
Explorer leaves the sidebar for a resizable Explorer/Git/File right panel (width helpers, pinned tabs, change badges); FileExplorer goes virtualized; top-bar popovers drop in favor of the composer ring; sidebar hosts the provider usage block.
64 lines
2.3 KiB
TypeScript
64 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { useI18n } from "@/lib/i18n";
|
|
|
|
export function projectLabel(projectPath: string): string {
|
|
const trimmed = projectPath.replace(/[\\/]+$/, "");
|
|
const index = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
return index >= 0 ? trimmed.slice(index + 1) : trimmed;
|
|
}
|
|
|
|
// Resizable desktop sidebar: the width is stored on the container as the
|
|
// --sidebar-width CSS variable (globals.css) and persisted between sessions.
|
|
export const SIDEBAR_WIDTH_STORAGE_KEY = "omp-web:sidebar-width";
|
|
export const SIDEBAR_MIN_WIDTH = 200;
|
|
export const SIDEBAR_MAX_WIDTH = 520;
|
|
export const SIDEBAR_DEFAULT_WIDTH = 260;
|
|
|
|
export function clampSidebarWidth(width: number): number {
|
|
return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_MIN_WIDTH, Math.round(width)));
|
|
}
|
|
|
|
export function loadSidebarWidth(): number {
|
|
if (typeof window === "undefined") return SIDEBAR_DEFAULT_WIDTH;
|
|
try {
|
|
const raw = window.localStorage.getItem(SIDEBAR_WIDTH_STORAGE_KEY);
|
|
const width = raw ? Number(raw) : NaN;
|
|
return Number.isFinite(width) ? clampSidebarWidth(width) : SIDEBAR_DEFAULT_WIDTH;
|
|
} catch {
|
|
return SIDEBAR_DEFAULT_WIDTH;
|
|
}
|
|
}
|
|
|
|
// Resizable right (file) panel: null means the fluid 42% default; a number is
|
|
// a user-chosen pixel width persisted between sessions (same drag pattern as
|
|
// the left sidebar, mirrored — the handle sits on the panel's left edge).
|
|
export const RIGHT_PANEL_WIDTH_STORAGE_KEY = "omp-web:right-panel-width";
|
|
export const RIGHT_PANEL_MIN_WIDTH = 300;
|
|
export const RIGHT_PANEL_MAX_WIDTH = 900;
|
|
|
|
export function clampRightPanelWidth(width: number): number {
|
|
return Math.min(RIGHT_PANEL_MAX_WIDTH, Math.max(RIGHT_PANEL_MIN_WIDTH, Math.round(width)));
|
|
}
|
|
|
|
export function loadRightPanelWidth(): number | null {
|
|
if (typeof window === "undefined") return null;
|
|
try {
|
|
const raw = window.localStorage.getItem(RIGHT_PANEL_WIDTH_STORAGE_KEY);
|
|
if (!raw) return null;
|
|
const width = Number(raw);
|
|
return Number.isFinite(width) ? clampRightPanelWidth(width) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function PanelLoadingFallback() {
|
|
const { t } = useI18n();
|
|
return (
|
|
<div role="status" style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-dim)", fontSize: 12 }}>
|
|
{t("appShell.loading")}
|
|
</div>
|
|
);
|
|
}
|