This commit is contained in:
2026-02-07 00:44:52 -05:00
parent db74e20571
commit 46f9135776
4 changed files with 48 additions and 86 deletions

View File

@@ -1,124 +0,0 @@
import type { JSX } from "solid-js";
import type { RGBA } from "@opentui/core";
import { Show, For } from "solid-js";
import { useTheme } from "@/context/ThemeContext";
type PanelConfig = {
/** Panel content */
content: JSX.Element;
/** Panel title shown in header */
title?: string;
/** Fixed width (leave undefined for flex) */
width?: number;
/** Whether this panel is currently focused */
focused?: boolean;
};
type LayoutProps = {
/** Top tab bar */
header?: JSX.Element;
/** Bottom status bar */
footer?: JSX.Element;
/** Panels to display left-to-right like a file explorer */
panels: PanelConfig[];
/** Index of the currently active/focused panel */
activePanelIndex?: number;
};
export function Layout(props: LayoutProps) {
const panelBg = (index: number): RGBA => {
const backgrounds = theme.layerBackgrounds;
const layers = [
backgrounds?.layer0 ?? theme.background,
backgrounds?.layer1 ?? theme.backgroundPanel,
backgrounds?.layer2 ?? theme.backgroundElement,
backgrounds?.layer3 ?? theme.backgroundMenu,
];
return layers[Math.min(index, layers.length - 1)];
};
const borderColor = (index: number): RGBA | string => {
const isActive = index === (props.activePanelIndex ?? 0);
return isActive
? (theme.accent ?? theme.primary)
: (theme.border ?? theme.textMuted);
};
const { theme } = useTheme();
return (
<box
flexDirection="column"
width="100%"
height="100%"
backgroundColor={theme.surface}
>
{/* Header - tab bar */}
<Show when={props.header}>
<box
style={{
height: 3,
backgroundColor: theme.surface ?? theme.backgroundPanel,
}}
>
<box style={{ paddingLeft: 1, paddingTop: 0, paddingBottom: 0 }}>
{props.header}
</box>
</box>
</Show>
{/* Main content: side-by-side panels */}
<box flexDirection="row" style={{ flexGrow: 1 }}>
<For each={props.panels}>
{(panel, index) => (
<box
flexDirection="column"
border
borderColor={theme.border}
backgroundColor={panelBg(index())}
style={{
flexGrow: panel.width ? 0 : 1,
width: panel.width,
height: "100%",
}}
>
{/* Panel header */}
<Show when={panel.title}>
<box
style={{
height: 1,
paddingLeft: 1,
paddingRight: 1,
backgroundColor:
index() === (props.activePanelIndex ?? 0)
? (theme.accent ?? theme.primary)
: (theme.surface ?? theme.backgroundPanel),
}}
>
<text
fg={
index() === (props.activePanelIndex ?? 0)
? "black"
: undefined
}
>
<strong>{panel.title}</strong>
</text>
</box>
</Show>
{/* Panel body */}
<box
style={{
flexGrow: 1,
padding: 1,
}}
>
{panel.content}
</box>
</box>
)}
</For>
</box>
</box>
);
}

View File

@@ -1,50 +0,0 @@
import { useTheme } from "@/context/ThemeContext";
export type TabId =
| "feed"
| "shows"
| "discover"
| "search"
| "player"
| "settings";
export type TabDefinition = {
id: TabId;
label: string;
};
export const tabs: TabDefinition[] = [
{ id: "feed", label: "Feed" },
{ id: "shows", label: "My Shows" },
{ id: "discover", label: "Discover" },
{ id: "search", label: "Search" },
{ id: "player", label: "Player" },
{ id: "settings", label: "Settings" },
];
type TabProps = {
tab: TabDefinition;
active: boolean;
onSelect: (tab: TabId) => void;
};
export function Tab(props: TabProps) {
const { theme } = useTheme();
return (
<box
border
borderColor={theme.border}
onMouseDown={() => props.onSelect(props.tab.id)}
style={{
padding: 1,
backgroundColor: props.active ? theme.primary : "transparent",
}}
>
<text style={{ fg: theme.text }}>
{props.active ? "[" : " "}
{props.tab.label}
{props.active ? "]" : " "}
</text>
</box>
);
}

View File

@@ -1,43 +1,57 @@
import { Tab, type TabId } from "./Tab";
import { useTheme } from "@/context/ThemeContext";
import { For } from "solid-js";
type TabNavigationProps = {
interface TabNavigationProps {
activeTab: TabId;
onTabSelect: (tab: TabId) => void;
};
}
export const tabs: TabDefinition[] = [
{ id: "feed", label: "Feed" },
{ id: "shows", label: "My Shows" },
{ id: "discover", label: "Discover" },
{ id: "search", label: "Search" },
{ id: "player", label: "Player" },
{ id: "settings", label: "Settings" },
];
export function TabNavigation(props: TabNavigationProps) {
const { theme } = useTheme();
return (
<box style={{ flexDirection: "row", gap: 1 }}>
<Tab
tab={{ id: "feed", label: "Feed" }}
active={props.activeTab === "feed"}
onSelect={props.onTabSelect}
/>
<Tab
tab={{ id: "shows", label: "My Shows" }}
active={props.activeTab === "shows"}
onSelect={props.onTabSelect}
/>
<Tab
tab={{ id: "discover", label: "Discover" }}
active={props.activeTab === "discover"}
onSelect={props.onTabSelect}
/>
<Tab
tab={{ id: "search", label: "Search" }}
active={props.activeTab === "search"}
onSelect={props.onTabSelect}
/>
<Tab
tab={{ id: "player", label: "Player" }}
active={props.activeTab === "player"}
onSelect={props.onTabSelect}
/>
<Tab
tab={{ id: "settings", label: "Settings" }}
active={props.activeTab === "settings"}
onSelect={props.onTabSelect}
/>
<For each={tabs}>
{(tab) => (
<box
border
borderColor={theme.border}
onMouseDown={() => props.onTabSelect(tab.id)}
style={{
padding: 1,
backgroundColor:
tab.id == props.activeTab ? theme.primary : "transparent",
}}
>
<text style={{ fg: theme.text }}>
{tab.id == props.activeTab ? "[" : " "}
{tab.label}
{tab.id == props.activeTab ? "]" : " "}
</text>
</box>
)}
</For>
</box>
);
}
export type TabId =
| "feed"
| "shows"
| "discover"
| "search"
| "player"
| "settings";
export type TabDefinition = {
id: TabId;
label: string;
};