Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions apps/web/src/hooks/useLayoutActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,29 +137,28 @@ export function useLayoutActions(): UseLayoutActionsResult {
const diffViewerOpen = diffState.isOpen;
const simulationOpen = useSimulationViewerStore.getState().isOpen;
const previewState = usePreviewStateStore.getState();
const previewOpen = projectId
? (previewState.openByProjectId[projectId] ?? false)
: false;
const previewOpen = projectId ? (previewState.openByProjectId[projectId] ?? false) : false;

const terminalStoreState = useTerminalStateStore.getState();
const threadTerminal = threadId
? selectThreadTerminalState(terminalStoreState.terminalStateByThreadId, threadId)
: null;

const previewDock = projectId
? (previewState.dockByProjectId[projectId] ?? null)
: null;
const previewSize = projectId
? (previewState.sizeByProjectId[projectId] ?? null)
: null;
const previewDock = projectId ? (previewState.dockByProjectId[projectId] ?? null) : null;
const previewSize = projectId ? (previewState.sizeByProjectId[projectId] ?? null) : null;

const now = Date.now();
return {
id: generateLayoutId(),
name: name.trim().slice(0, 128) || "Untitled Layout",
createdAt: now,
updatedAt: now,
activePanel: resolveActivePanel(codeViewerOpen, diffViewerOpen, previewOpen, simulationOpen),
activePanel: resolveActivePanel(
codeViewerOpen,
diffViewerOpen,
previewOpen,
simulationOpen,
),
terminalOpen: threadTerminal?.terminalOpen ?? false,
terminalHeight: threadTerminal?.terminalHeight ?? null,
sidebarWidths: readSidebarWidths(),
Expand Down
19 changes: 15 additions & 4 deletions apps/web/src/layoutStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ export interface SavedLayout {
const LAYOUT_STORAGE_KEY = "okcode:saved-layouts:v1";
const MAX_SAVED_LAYOUTS = 32;

const VALID_PANELS = new Set<string>(["none", "code-viewer", "diff-viewer", "preview", "simulation"]);
const VALID_PANELS = new Set<string>([
"none",
"code-viewer",
"diff-viewer",
"preview",
"simulation",
]);
const VALID_DOCKS = new Set<string>(["left", "right", "top", "bottom"]);

// ─── Validation helpers ─────────────────────────────────────────────
Expand Down Expand Up @@ -100,8 +106,10 @@ function normalizeLayout(raw: unknown): SavedLayout | null {
return {
id: obj.id.trim(),
name: obj.name.trim().slice(0, 128),
createdAt: typeof obj.createdAt === "number" && Number.isFinite(obj.createdAt) ? obj.createdAt : now,
updatedAt: typeof obj.updatedAt === "number" && Number.isFinite(obj.updatedAt) ? obj.updatedAt : now,
createdAt:
typeof obj.createdAt === "number" && Number.isFinite(obj.createdAt) ? obj.createdAt : now,
updatedAt:
typeof obj.updatedAt === "number" && Number.isFinite(obj.updatedAt) ? obj.updatedAt : now,
activePanel: isValidPanel(obj.activePanel) ? obj.activePanel : "none",
terminalOpen: typeof obj.terminalOpen === "boolean" ? obj.terminalOpen : false,
terminalHeight: isFinitePositiveOrNull(obj.terminalHeight) ? obj.terminalHeight : null,
Expand Down Expand Up @@ -254,7 +262,10 @@ export const useLayoutStore = create<LayoutStoreState>((set) => ({
const nextLayouts = state.savedLayouts.filter((l) => l.id !== id);
if (nextLayouts.length === state.savedLayouts.length) return state;
const nextActiveId = state.activeLayoutId === id ? null : state.activeLayoutId;
const next: PersistedLayoutState = { savedLayouts: nextLayouts, activeLayoutId: nextActiveId };
const next: PersistedLayoutState = {
savedLayouts: nextLayouts,
activeLayoutId: nextActiveId,
};
persistState(next);
return next;
});
Expand Down
11 changes: 11 additions & 0 deletions apps/web/src/routes/_chat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";

describe("chat route sidebar chrome", () => {
it("keeps the left sidebar off the backdrop blur path", () => {
const src = readFileSync(resolve(import.meta.dirname, "./_chat.tsx"), "utf8");

expect(src).not.toContain("backdrop-blur-sm");
});
});
4 changes: 3 additions & 1 deletion apps/web/src/routes/_chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ function ChatRouteLayout() {
<Sidebar
side="left"
collapsible="offcanvas"
className="border-r-2 border-border/60 bg-card/80 text-foreground backdrop-blur-sm shadow-[2px_0_12px_-4px_rgba(0,0,0,0.08)] dark:border-border/40 dark:bg-card/60 dark:shadow-[2px_0_16px_-4px_rgba(0,0,0,0.3)]"
// Keep the primary sidebar on a simpler paint path. The blur layer is
// visually nice, but it is also the most likely source of display-only shimmer.
className="border-r-2 border-border/60 bg-card/80 text-foreground shadow-[2px_0_12px_-4px_rgba(0,0,0,0.08)] dark:border-border/40 dark:bg-card/60 dark:shadow-[2px_0_16px_-4px_rgba(0,0,0,0.3)]"
style={
{
"--sidebar-background-opacity": settings.sidebarOpacity,
Expand Down
Loading