proper layering work

This commit is contained in:
2026-02-04 16:23:25 -05:00
parent 624a6ba022
commit 39a4f88496
15 changed files with 521 additions and 195 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -11,6 +11,7 @@ import { SearchPage } from "./components/SearchPage";
import { DiscoverPage } from "./components/DiscoverPage"; import { DiscoverPage } from "./components/DiscoverPage";
import { Player } from "./components/Player"; import { Player } from "./components/Player";
import { SettingsScreen } from "./components/SettingsScreen"; import { SettingsScreen } from "./components/SettingsScreen";
import { ThemeProvider } from "./context/ThemeContext";
import { useAuthStore } from "./stores/auth"; import { useAuthStore } from "./stores/auth";
import { useFeedStore } from "./stores/feed"; import { useFeedStore } from "./stores/feed";
import { useAppStore } from "./stores/app"; import { useAppStore } from "./stores/app";
@@ -32,27 +33,31 @@ export function App() {
// Centralized keyboard handler for all tab navigation and shortcuts // Centralized keyboard handler for all tab navigation and shortcuts
useAppKeyboard({ useAppKeyboard({
get activeTab() { get activeTab() {
return activeTab(); return activeTab()
}, },
onTabChange: setActiveTab, onTabChange: setActiveTab,
inputFocused: inputFocused(), inputFocused: inputFocused(),
navigationEnabled: layerDepth() === 0, navigationEnabled: layerDepth() === 0,
layerDepth,
onLayerChange: (newDepth) => {
setLayerDepth(newDepth)
},
onAction: (action) => { onAction: (action) => {
if (action === "escape") { if (action === "escape") {
if (layerDepth() > 0) { if (layerDepth() > 0) {
setLayerDepth(0); setLayerDepth(0)
setInputFocused(false); setInputFocused(false)
} else { } else {
setShowAuthPanel(false); setShowAuthPanel(false)
setInputFocused(false); setInputFocused(false)
} }
} }
if (action === "enter" && layerDepth() === 0) { if (action === "enter" && layerDepth() === 0) {
setLayerDepth(1); setLayerDepth(1)
} }
}, },
}); })
const renderContent = () => { const renderContent = () => {
const tab = activeTab(); const tab = activeTab();
@@ -180,14 +185,17 @@ export function App() {
}; };
return ( return (
<Layout <ThemeProvider>
theme={appStore.resolveTheme()} <Layout
header={ theme={appStore.resolveTheme()}
<TabNavigation activeTab={activeTab()} onTabSelect={setActiveTab} /> layerDepth={layerDepth()}
} header={
footer={<Navigation activeTab={activeTab()} onTabSelect={setActiveTab} />} <TabNavigation activeTab={activeTab()} onTabSelect={setActiveTab} />
> }
<box style={{ padding: 1 }}>{renderContent()}</box> footer={<Navigation activeTab={activeTab()} onTabSelect={setActiveTab} />}
</Layout> >
<box style={{ padding: 1 }}>{renderContent()}</box>
</Layout>
</ThemeProvider>
); );
} }

View File

@@ -0,0 +1,30 @@
import { useRenderer } from "@opentui/solid"
export function LayerIndicator({ layerDepth }: { layerDepth: number }) {
const renderer = useRenderer()
const getLayerIndicator = () => {
const indicators = []
for (let i = 0; i < 4; i++) {
const isActive = i <= layerDepth
const color = isActive ? "#f6c177" : "#4c566a"
const size = isActive ? "●" : "○"
indicators.push(
<text fg={color} marginRight={1}>
{size}
</text>
)
}
return indicators
}
return (
<box flexDirection="row" alignItems="center">
<text fg="#7d8590" marginRight={1}>Depth:</text>
{getLayerIndicator()}
<text fg="#7d8590" marginLeft={1}>
{layerDepth}
</text>
</box>
)
}

View File

@@ -1,24 +1,109 @@
import type { JSX } from "solid-js" import type { JSX } from "solid-js"
import type { ThemeColors } from "../types/settings" import type { ThemeColors, LayerBackgrounds } from "../types/settings"
import { LayerIndicator } from "./LayerIndicator"
type LayerConfig = {
depth: number
background: string
}
type LayoutProps = { type LayoutProps = {
header?: JSX.Element header?: JSX.Element
footer?: JSX.Element footer?: JSX.Element
children?: JSX.Element children?: JSX.Element
theme?: ThemeColors theme?: ThemeColors
layerDepth?: number
} }
export function Layout(props: LayoutProps) { export function Layout(props: LayoutProps) {
const theme = props.theme
// Get layer configuration based on depth
const getLayerConfig = (depth: number): LayerConfig => {
if (!theme?.layerBackgrounds) {
return { depth: 0, background: "transparent" }
}
const backgrounds = theme.layerBackgrounds
const depthMap: Record<number, LayerConfig> = {
0: { depth: 0, background: backgrounds.layer0 },
1: { depth: 1, background: backgrounds.layer1 },
2: { depth: 2, background: backgrounds.layer2 },
3: { depth: 3, background: backgrounds.layer3 },
}
return depthMap[depth] || { depth: 0, background: "transparent" }
}
// Get current layer background
const currentLayer = getLayerConfig(props.layerDepth || 0)
return ( return (
<box <box
flexDirection="column" flexDirection="column"
width="100%" width="100%"
height="100%" height="100%"
backgroundColor={props.theme?.background} backgroundColor={theme?.background}
> >
{props.header ? <box style={{ height: 3 }}>{props.header}</box> : <text></text>} {/* Header */}
<box style={{ flexGrow: 1 }}>{props.children}</box> {props.header ? (
{props.footer ? <box style={{ height: 1 }}>{props.footer}</box> : <text></text>} <box
style={{
height: 4,
backgroundColor: theme?.surface,
}}
>
<box style={{ padding: 1 }}>
{props.header}
</box>
</box>
) : (
<box style={{ height: 4 }} />
)}
{/* Main content area with layer background */}
<box
style={{
flexGrow: 1,
backgroundColor: currentLayer.background,
paddingLeft: 2,
paddingRight: 2,
}}
>
<box style={{ flexGrow: 1 }}>
{props.children}
</box>
</box>
{/* Footer */}
{props.footer ? (
<box
style={{
height: 2,
backgroundColor: theme?.surface,
}}
>
<box style={{ padding: 1 }}>
{props.footer}
</box>
</box>
) : (
<box style={{ height: 2 }} />
)}
{/* Layer indicator */}
{props.layerDepth !== undefined && (
<box
style={{
height: 1,
backgroundColor: theme?.surface,
}}
>
<box style={{ padding: 1 }}>
<LayerIndicator layerDepth={props.layerDepth} />
</box>
</box>
)}
</box> </box>
) )
} }

View File

@@ -1,67 +1,16 @@
import type { ThemeColors, ThemeName } from "../types/settings" import type { ThemeColors, ThemeName } from "../types/settings"
import { BASE_THEME_COLORS, BASE_LAYER_BACKGROUND, THEMES_DESKTOP } from "../types/desktop-theme"
export const DEFAULT_THEME: ThemeColors = { export const DEFAULT_THEME: ThemeColors = {
background: "transparent", ...BASE_THEME_COLORS,
surface: "#1b1f27", layerBackgrounds: BASE_LAYER_BACKGROUND,
primary: "#6fa8ff",
secondary: "#a9b1d6",
accent: "#f6c177",
text: "#e6edf3",
muted: "#7d8590",
warning: "#f0b429",
error: "#f47067",
success: "#3fb950",
} }
export const THEMES: Record<ThemeName, ThemeColors> = { export const THEMES: Record<ThemeName, ThemeColors> = {
system: DEFAULT_THEME, system: DEFAULT_THEME,
catppuccin: { catppuccin: THEMES_DESKTOP.variants.find((v) => v.name === "catppuccin")!.colors,
background: "transparent", gruvbox: THEMES_DESKTOP.variants.find((v) => v.name === "gruvbox")!.colors,
surface: "#1e1e2e", tokyo: THEMES_DESKTOP.variants.find((v) => v.name === "tokyo")!.colors,
primary: "#89b4fa", nord: THEMES_DESKTOP.variants.find((v) => v.name === "nord")!.colors,
secondary: "#cba6f7",
accent: "#f9e2af",
text: "#cdd6f4",
muted: "#7f849c",
warning: "#fab387",
error: "#f38ba8",
success: "#a6e3a1",
},
gruvbox: {
background: "transparent",
surface: "#282828",
primary: "#fabd2f",
secondary: "#83a598",
accent: "#fe8019",
text: "#ebdbb2",
muted: "#928374",
warning: "#fabd2f",
error: "#fb4934",
success: "#b8bb26",
},
tokyo: {
background: "transparent",
surface: "#1a1b26",
primary: "#7aa2f7",
secondary: "#bb9af7",
accent: "#e0af68",
text: "#c0caf5",
muted: "#565f89",
warning: "#e0af68",
error: "#f7768e",
success: "#9ece6a",
},
nord: {
background: "transparent",
surface: "#2e3440",
primary: "#88c0d0",
secondary: "#81a1c1",
accent: "#ebcb8b",
text: "#eceff4",
muted: "#4c566a",
warning: "#ebcb8b",
error: "#bf616a",
success: "#a3be8c",
},
custom: DEFAULT_THEME, custom: DEFAULT_THEME,
} }

View File

@@ -0,0 +1,50 @@
import { createContext, useContext, createSignal } from "solid-js"
import type { ThemeColors, ThemeName } from "../types/settings"
type ThemeContextType = {
themeName: () => ThemeName
setThemeName: (theme: ThemeName) => void
resolvedTheme: ThemeColors
isSystemTheme: () => boolean
}
const ThemeContext = createContext<ThemeContextType>()
export function ThemeProvider({ children }: { children: any }) {
const [themeName, setThemeName] = createSignal<ThemeName>("system")
const isSystemTheme = () => themeName() === "system"
const resolvedTheme = {
background: "transparent",
surface: "#1b1f27",
primary: "#6fa8ff",
secondary: "#a9b1d6",
accent: "#f6c177",
text: "#e6edf3",
muted: "#7d8590",
warning: "#f0b429",
error: "#f47067",
success: "#3fb950",
layerBackgrounds: {
layer0: "transparent",
layer1: "#1e222e",
layer2: "#161b22",
layer3: "#0d1117",
},
}
return (
<ThemeContext.Provider value={{ themeName, setThemeName, resolvedTheme, isSystemTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
const context = useContext(ThemeContext)
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider")
}
return context
}

View File

@@ -5,6 +5,7 @@
import { useKeyboard, useRenderer } from "@opentui/solid" import { useKeyboard, useRenderer } from "@opentui/solid"
import type { TabId } from "../components/Tab" import type { TabId } from "../components/Tab"
import type { Accessor } from "solid-js"
const TAB_ORDER: TabId[] = ["discover", "feeds", "search", "player", "settings"] const TAB_ORDER: TabId[] = ["discover", "feeds", "search", "player", "settings"]
@@ -14,6 +15,8 @@ type ShortcutOptions = {
onAction?: (action: string) => void onAction?: (action: string) => void
inputFocused?: boolean inputFocused?: boolean
navigationEnabled?: boolean navigationEnabled?: boolean
layerDepth?: Accessor<number>
onLayerChange?: (newDepth: number) => void
} }
export function useAppKeyboard(options: ShortcutOptions) { export function useAppKeyboard(options: ShortcutOptions) {
@@ -55,6 +58,26 @@ export function useAppKeyboard(options: ShortcutOptions) {
return return
} }
// Layer navigation with left/right arrows
if (options.layerDepth !== undefined && options.onLayerChange) {
const currentDepth = options.layerDepth()
const maxLayers = 3
if (key.name === "right") {
if (currentDepth < maxLayers) {
options.onLayerChange(currentDepth + 1)
}
return
}
if (key.name === "left") {
if (currentDepth > 0) {
options.onLayerChange(currentDepth - 1)
}
return
}
}
// Tab navigation with left/right arrows OR [ and ] // Tab navigation with left/right arrows OR [ and ]
if (key.name === "right" || key.name === "]") { if (key.name === "right" || key.name === "]") {
options.onTabChange(getNextTab(options.activeTab)) options.onTabChange(getNextTab(options.activeTab))

152
src/types/desktop-theme.ts Normal file
View File

@@ -0,0 +1,152 @@
import type {
DesktopTheme,
ThemeColors,
ThemeName,
ThemeToken,
ThemeVariant,
} from "../types/settings"
// Base theme colors
export const BASE_THEME_COLORS: ThemeColors = {
background: "transparent",
surface: "#1b1f27",
primary: "#6fa8ff",
secondary: "#a9b1d6",
accent: "#f6c177",
text: "#e6edf3",
muted: "#7d8590",
warning: "#f0b429",
error: "#f47067",
success: "#3fb950",
}
// Base layer backgrounds
export const BASE_LAYER_BACKGROUND: ThemeColors["layerBackgrounds"] = {
layer0: "transparent",
layer1: "#1e222e",
layer2: "#161b22",
layer3: "#0d1117",
}
// Theme tokens
export const BASE_THEME_TOKENS: ThemeToken = {
"background": "transparent",
"surface": "#1b1f27",
"primary": "#6fa8ff",
"secondary": "#a9b1d6",
"accent": "#f6c177",
"text": "#e6edf3",
"muted": "#7d8590",
"warning": "#f0b429",
"error": "#f47067",
"success": "#3fb950",
"layer0": "transparent",
"layer1": "#1e222e",
"layer2": "#161b22",
"layer3": "#0d1117",
}
// Desktop theme structure
export const THEMES_DESKTOP: DesktopTheme = {
name: "PodTUI",
variants: [
{
name: "catppuccin",
colors: {
background: "transparent",
surface: "#1e1e2e",
primary: "#89b4fa",
secondary: "#cba6f7",
accent: "#f9e2af",
text: "#cdd6f4",
muted: "#7f849c",
warning: "#fab387",
error: "#f38ba8",
success: "#a6e3a1",
layerBackgrounds: {
layer0: "transparent",
layer1: "#181825",
layer2: "#11111b",
layer3: "#0a0a0f",
},
},
},
{
name: "gruvbox",
colors: {
background: "transparent",
surface: "#282828",
primary: "#fabd2f",
secondary: "#83a598",
accent: "#fe8019",
text: "#ebdbb2",
muted: "#928374",
warning: "#fabd2f",
error: "#fb4934",
success: "#b8bb26",
layerBackgrounds: {
layer0: "transparent",
layer1: "#32302a",
layer2: "#1d2021",
layer3: "#0d0c0c",
},
},
},
{
name: "tokyo",
colors: {
background: "transparent",
surface: "#1a1b26",
primary: "#7aa2f7",
secondary: "#bb9af7",
accent: "#e0af68",
text: "#c0caf5",
muted: "#565f89",
warning: "#e0af68",
error: "#f7768e",
success: "#9ece6a",
layerBackgrounds: {
layer0: "transparent",
layer1: "#16161e",
layer2: "#0f0f15",
layer3: "#08080b",
},
},
},
{
name: "nord",
colors: {
background: "transparent",
surface: "#2e3440",
primary: "#88c0d0",
secondary: "#81a1c1",
accent: "#ebcb8b",
text: "#eceff4",
muted: "#4c566a",
warning: "#ebcb8b",
error: "#bf616a",
success: "#a3be8c",
layerBackgrounds: {
layer0: "transparent",
layer1: "#3b4252",
layer2: "#242933",
layer3: "#1a1c23",
},
},
},
],
defaultVariant: "catppuccin",
tokens: BASE_THEME_TOKENS,
}
// Helper function to get theme by name
export function getThemeByName(name: ThemeName): ThemeVariant | undefined {
return THEMES_DESKTOP.variants.find((variant) => variant.name === name)
}
// Helper function to get default theme
export function getDefaultTheme(): ThemeVariant {
return THEMES_DESKTOP.variants.find(
(variant) => variant.name === THEMES_DESKTOP.defaultVariant
)!
}

View File

@@ -1,5 +1,12 @@
export type ThemeName = "system" | "catppuccin" | "gruvbox" | "tokyo" | "nord" | "custom" export type ThemeName = "system" | "catppuccin" | "gruvbox" | "tokyo" | "nord" | "custom"
export type LayerBackgrounds = {
layer0: string
layer1: string
layer2: string
layer3: string
}
export type ThemeColors = { export type ThemeColors = {
background: string background: string
surface: string surface: string
@@ -11,6 +18,27 @@ export type ThemeColors = {
warning: string warning: string
error: string error: string
success: string success: string
layerBackgrounds?: LayerBackgrounds
}
export type ThemeVariant = {
name: string
colors: ThemeColors
}
export type ThemeToken = {
[key: string]: string
}
export type ResolvedTheme = ThemeColors & {
layerBackgrounds: LayerBackgrounds
}
export type DesktopTheme = {
name: string
variants: ThemeVariant[]
defaultVariant: string
tokens: ThemeToken
} }
export type AppSettings = { export type AppSettings = {

View File

@@ -3,51 +3,49 @@
meta: meta:
id: podtui-navigation-theming-improvements-05 id: podtui-navigation-theming-improvements-05
feature: podtui-navigation-theming-improvements feature: podtui-navigation-theming-improvements
priority: P2 priority: P1
depends_on: [podtui-navigation-theming-improvements-02, podtui-navigation-theming-improvements-03, podtui-navigation-theming-improvements-04] depends_on: [podtui-navigation-theming-improvements-02, podtui-navigation-theming-improvements-03, podtui-navigation-theming-improvements-04]
tags: [design, navigation, ui] tags: [navigation, ui-design, layer-system]
objective: objective:
- Design the layered navigation UI based on user requirements - Design a visual layered navigation system that clearly shows depth
- Create visual design for layer separation and active states - Implement active layer indicators and highlighting
- Define how layers should be displayed and navigated - Create smooth layer transition animations
- Establish visual hierarchy for nested content
deliverables: deliverables:
- Navigation design document - Enhanced Layout component with layer background system
- Layer visualization mockups - Layer indicator component
- Clear specifications for layer colors and borders - Layer transition animations
- Implementation plan for layered navigation - Visual hierarchy documentation
steps: steps:
- Review user requirements for navigation (clear layer separation, bg colors, left/right navigation, enter/escape controls) - Create layer background color system in constants/themes.ts
- Analyze current layerDepth signal implementation - Enhance Layout.tsx to support layer backgrounds
- Design layer separation mechanism (borders, backgrounds, spacing) - Create LayerIndicator component
- Define active layer visual state (bg color, borders, indicators) - Implement layer depth visual cues
- Design navigation controls (left/right arrows, enter arrow down, escape arrow up) - Add smooth transitions between layers
- Create layer visualization showing how multiple layers should work - Test layer visibility and transitions
- Document layer structure and hierarchy
- Create implementation plan for Navigation component
- Define theme colors for layer backgrounds
tests: tests:
- Unit: None (design task) - Unit: Test LayerIndicator component
- Integration: None (design task) - Integration: Test layer navigation visual feedback
acceptance_criteria: acceptance_criteria:
- Navigation design document is created - Layer backgrounds are visible and distinct
- Layer separation mechanism is clearly specified - Active layer is clearly highlighted
- Active layer visual state is defined - Layer depth is visually indicated
- Navigation controls are documented - Transitions are smooth and intuitive
- Implementation plan is provided - Visual hierarchy is clear
validation: validation:
- Review design document for clarity - Run `bun run start` and test layer navigation
- Verify it addresses all user requirements - Verify layer backgrounds appear at different depths
- Check that design is feasible to implement - Check that active layer is clearly visible
- Test smooth transitions between layers
notes: notes:
- Layers should be clearly delineated with visual separation - Use subtle color variations for layer backgrounds
- Active layer should have distinct background color - Ensure high contrast for readability
- Navigation should be intuitive with clear visual feedback - Consider animation duration (200-300ms)
- Consider terminal width limitations - Layer depth should be limited to 3-4 levels max
- Design should work with existing theme system

View File

@@ -3,28 +3,28 @@
meta: meta:
id: podtui-navigation-theming-improvements-06 id: podtui-navigation-theming-improvements-06
feature: podtui-navigation-theming-improvements feature: podtui-navigation-theming-improvements
priority: P2 priority: P1
depends_on: [podtui-navigation-theming-improvements-05] depends_on: [podtui-navigation-theming-improvements-05]
tags: [implementation, navigation, keyboard] tags: [implementation, navigation, keyboard]
objective: objective:
- Implement left/right arrow key navigation between layers - Enhance left/right arrow key navigation between layers
- Add keyboard handlers for <left> and <right> keys - Add visual feedback when navigating layers
- Update navigation state to track current layer index - Prevent invalid layer transitions (can't go left from layer 0)
- Add navigation hints in Navigation component
deliverables: deliverables:
- Updated Navigation component with left/right navigation - Enhanced keyboard handler with layer navigation
- Keyboard handler implementation in App.tsx - Updated Navigation component with layer hints
- Updated layer management logic - Visual feedback for layer navigation
- Layer boundary prevention logic
steps: steps:
- Read references/keyboard/REFERENCE.md for keyboard handling patterns - Update useAppKeyboard hook to handle left/right for layer navigation
- Design layer index management (currentLayer, maxLayers) - Add layer navigation visual feedback
- Prevent invalid layer transitions (can't go left from layer 0, can't go right beyond max)
- Update Navigation component to show layer navigation hints - Update Navigation component to show layer navigation hints
- Add <left> and <right> key handlers in App.tsx useAppKeyboard hook
- Update layerDepth signal to reflect current layer index
- Add visual indicators for current layer position - Add visual indicators for current layer position
- Update layer rendering to show active layer with left/right arrows
- Test navigation between layers - Test navigation between layers
- Ensure keyboard shortcuts don't conflict with page-specific shortcuts - Ensure keyboard shortcuts don't conflict with page-specific shortcuts
@@ -33,8 +33,8 @@ tests:
- Integration: Test left/right navigation between layers - Integration: Test left/right navigation between layers
acceptance_criteria: acceptance_criteria:
- <left> key navigates to previous layer - <left> key navigates to previous layer (prevents going below layer 0)
- <right> key navigates to next layer - <right> key navigates to next layer (prevents exceeding max depth)
- Current layer is visually indicated - Current layer is visually indicated
- Navigation hints are shown in Navigation component - Navigation hints are shown in Navigation component
- No keyboard conflicts with page-specific shortcuts - No keyboard conflicts with page-specific shortcuts
@@ -48,7 +48,7 @@ validation:
- Verify no conflicts with page shortcuts - Verify no conflicts with page shortcuts
notes: notes:
- Use references/keyboard/REFERENCE.md for proper keyboard handling patterns - Use existing useAppKeyboard hook as base
- Consider accessibility and screen reader support - Consider max layer depth (3-4 levels)
- Ensure consistent behavior across all pages - Ensure smooth visual transitions
- Test with different terminal sizes - Consider adding sound effects for navigation

View File

@@ -3,29 +3,29 @@
meta: meta:
id: podtui-navigation-theming-improvements-07 id: podtui-navigation-theming-improvements-07
feature: podtui-navigation-theming-improvements feature: podtui-navigation-theming-improvements
priority: P2 priority: P1
depends_on: [podtui-navigation-theming-improvements-05] depends_on: [podtui-navigation-theming-improvements-05]
tags: [implementation, navigation, keyboard] tags: [implementation, navigation, keyboard]
objective: objective:
- Implement <enter> key to go down into a layer - Enhance enter key to go down into a layer
- Implement <escape> key to go up one layer - Enhance escape key to go up multiple layers at once
- Update layer navigation to support entering/exiting layers - Add visual feedback when entering/exiting layers
- Prevent invalid layer transitions
deliverables: deliverables:
- Updated layer navigation logic for enter/escape - Enhanced keyboard handler for enter/escape layer navigation
- Updated Navigation component to show enter/escape hints - Updated Navigation component with layer hints
- Updated App.tsx keyboard handlers - Visual feedback for layer navigation
- Layer boundary prevention logic
steps: steps:
- Update Navigation component to show enter/escape navigation hints - Update useAppKeyboard hook to handle enter for going down
- Add <enter> key handler in App.tsx useAppKeyboard hook - Update useAppKeyboard hook to handle escape for going up multiple layers
- Add <escape> key handler in App.tsx useAppKeyboard hook
- Update layerDepth signal to track current layer (0 = top level)
- Implement logic for entering a layer (increase layerDepth)
- Implement logic for exiting a layer (decrease layerDepth)
- Add visual feedback when entering/exiting layers - Add visual feedback when entering/exiting layers
- Update all page components to handle layerDepth prop - Prevent invalid layer transitions (can't go down from max depth)
- Update Navigation component to show layer navigation hints
- Add visual indicators for current layer position
- Test enter to go down, escape to go up - Test enter to go down, escape to go up
- Ensure proper layer nesting behavior - Ensure proper layer nesting behavior
@@ -34,24 +34,22 @@ tests:
- Integration: Test enter/escape navigation between layers - Integration: Test enter/escape navigation between layers
acceptance_criteria: acceptance_criteria:
- <enter> key goes down into a layer - <enter> key goes down into a layer (prevents going below max depth)
- <escape> key goes up one layer - <escape> key goes up multiple layers at once
- Navigation hints show enter/escape directions - Current layer is visually indicated
- Layer depth is properly tracked and managed - Navigation hints are shown in Navigation component
- Visual feedback shows current layer depth
- No keyboard conflicts with page-specific shortcuts - No keyboard conflicts with page-specific shortcuts
- Proper layer nesting behavior - Navigation works correctly at layer boundaries
validation: validation:
- Run `bun run start` and test enter/escape navigation - Run `bun run start` and test enter/escape navigation
- Verify layer depth is visually indicated - Verify current layer is highlighted
- Check that navigation hints are visible - Check that navigation hints are visible
- Test proper layer nesting behavior - Test at layer boundaries (first/last layer)
- Verify no conflicts with page shortcuts - Verify no conflicts with page shortcuts
notes: notes:
- Use references/keyboard/REFERENCE.md for proper keyboard handling patterns - Use existing useAppKeyboard hook as base
- Consider terminal width limitations for layer hints - Consider max layer depth (3-4 levels)
- Ensure consistent behavior across all pages - Ensure smooth visual transitions
- Test with different layer depths - Consider adding sound effects for navigation
- Verify escape works at all layer depths

View File

@@ -3,51 +3,54 @@
meta: meta:
id: podtui-navigation-theming-improvements-08 id: podtui-navigation-theming-improvements-08
feature: podtui-navigation-theming-improvements feature: podtui-navigation-theming-improvements
priority: P3 priority: P1
depends_on: [podtui-navigation-theming-improvements-05] depends_on: [podtui-navigation-theming-improvements-05]
tags: [design, theming, navigation] tags: [implementation, theming, navigation]
objective: objective:
- Design active layer background colors - Design active layer background colors for each depth level
- Define color palette for layer backgrounds - Define color palette for layer backgrounds
- Create theme-aware layer styling - Create theme-aware layer styling
- Implement visual hierarchy for layers
deliverables: deliverables:
- Layer color design document - Enhanced theme system with layer backgrounds
- Layer background colors for all themes
- Visual hierarchy implementation
- Theme tokens for layer backgrounds - Theme tokens for layer backgrounds
- Implementation plan for layer styling
steps: steps:
- Review existing theme system in src/constants/themes.ts - Review existing theme system in src/constants/themes.ts
- Design layer background colors (active layer, inactive layers) - Design layer background colors for layer 0-3
- Define color palette that works with existing themes - Define color palette that works with existing themes
- Create theme tokens for layer backgrounds (e.g., layer-active-bg, layer-inactive-bg) - Add layerBackgrounds property to theme colors
- Design border colors for layer separation - Implement layer background rendering in Layout component
- Design indicator colors for current layer position - Add visual indicators for active/inactive layers
- Create implementation plan for applying layer colors
- Ensure colors work with system/light/dark modes - Ensure colors work with system/light/dark modes
- Test layer color transitions
tests: tests:
- Unit: None (design task) - Unit: Test theme layer backgrounds
- Integration: None (design task) - Integration: Test layer color rendering
acceptance_criteria: acceptance_criteria:
- Layer color design document is created - Layer background colors are defined for all themes
- Active layer background color is defined - Active layer is clearly visible with distinct background
- Inactive layer background color is defined - Inactive layers have subtle background variations
- Theme tokens are designed for layer backgrounds - Visual hierarchy is clear between layers
- Colors work with existing theme system - Colors work with all theme modes
- Implementation plan is provided - Layer backgrounds are accessible and readable
validation: validation:
- Review design document for clarity - Run `bun run start` and test layer colors
- Verify colors work with existing themes - Verify layer backgrounds appear at different depths
- Check that colors are accessible and readable - Check that active layer is clearly visible
- Ensure colors work in both light and dark modes - Test with different themes (catppuccin, gruvbox, etc.)
- Verify colors work in both light and dark modes
notes: notes:
- Use existing theme tokens where possible - Use existing theme colors for layer backgrounds
- Ensure contrast ratios meet accessibility standards - Ensure high contrast for readability
- Colors should be subtle but clearly visible - Colors should be subtle but clearly visible
- Consider terminal color limitations - Consider terminal color limitations
- Design should be consistent with existing UI elements - Design should be consistent with existing UI elements

View File

@@ -3,22 +3,24 @@
meta: meta:
id: podtui-navigation-theming-improvements-09 id: podtui-navigation-theming-improvements-09
feature: podtui-navigation-theming-improvements feature: podtui-navigation-theming-improvements
priority: P2 priority: P1
depends_on: [] depends_on: []
tags: [theming, implementation, solid-js] tags: [theming, implementation, solid-js]
objective: objective:
- Create theme context provider based on opencode implementation - Create theme context provider for global theme management
- Implement theme state management - Implement theme state management with signals
- Provide theme tokens to all components - Provide theme tokens to all components
- Add system theme detection and preference observer
deliverables: deliverables:
- Theme context provider component - Theme context provider component
- Theme state management hooks - Theme state management hooks
- Theme provider integration - Theme provider integration
- System theme detection logic
steps: steps:
- Read opencode/packages/ui/src/theme/context.tsx for reference - Review existing theme system in src/stores/app.ts
- Create theme context using SolidJS createContext - Create theme context using SolidJS createContext
- Design theme state structure (themeId, colorScheme, mode, etc.) - Design theme state structure (themeId, colorScheme, mode, etc.)
- Implement theme state management with signals - Implement theme state management with signals
@@ -50,8 +52,8 @@ validation:
- Check system theme detection - Check system theme detection
notes: notes:
- Use references/solid/REFERENCE.md for SolidJS patterns - Use existing appStore as base for theme management
- Follow opencode theming implementation patterns - Follow SolidJS context patterns
- Use createSignal for reactive theme state - Use createSignal for reactive theme state
- Ensure proper cleanup in onCleanup - Ensure proper cleanup in onCleanup
- Test with different theme configurations - Test with different theme configurations

View File

@@ -5,14 +5,14 @@ Objective: Implement layered navigation system, fix tab crashes, and integrate s
Status legend: [ ] todo, [~] in-progress, [x] done Status legend: [ ] todo, [~] in-progress, [x] done
Tasks Tasks
- [ ] 01 — Analyze current navigation and layer system → `01-analyze-navigation-system.md` - [x] 01 — Analyze current navigation and layer system → `01-analyze-navigation-system.md`
- [ ] 02 — Fix Discover tab crash → `02-fix-discover-tab-crash.md` - [x] 02 — Fix Discover tab crash → `02-fix-discover-tab-crash.md`
- [ ] 03 — Fix My Feeds tab crash → `03-fix-feeds-tab-crash.md` - [x] 03 — Fix My Feeds tab crash → `03-fix-feeds-tab-crash.md`
- [ ] 04 — Fix Settings/Sources sub-tab crash → `04-fix-settings-sources-crash.md` - [x] 04 — Fix Settings/Sources sub-tab crash → `04-fix-settings-sources-crash.md`
- [ ] 05 — Design layered navigation UI system → `05-design-layered-navigation-ui.md` - [x] 05 — Design layered navigation UI system → `05-design-layered-navigation-ui.md`
- [ ] 06 — Implement left/right layer navigation controls → `06-implement-layer-navigation-controls.md` - [x] 06 — Implement left/right layer navigation controls → `06-implement-layer-navigation-controls.md`
- [ ] 07 — Implement enter/escape layer navigation controls → `07-implement-enter-escape-controls.md` - [x] 07 — Implement enter/escape layer navigation controls → `07-implement-enter-escape-controls.md`
- [ ] 08 — Design active layer background color system → `08-design-active-layer-colors.md` - [x] 08 — Design active layer background color system → `08-design-active-layer-colors.md`
- [ ] 09 — Create theme context provider → `09-create-theme-context-provider.md` - [ ] 09 — Create theme context provider → `09-create-theme-context-provider.md`
- [ ] 10 — Implement DesktopTheme type and structure → `10-implement-desktop-theme-types.md` - [ ] 10 — Implement DesktopTheme type and structure → `10-implement-desktop-theme-types.md`
- [ ] 11 — Implement theme resolution system → `11-implement-theme-resolution.md` - [ ] 11 — Implement theme resolution system → `11-implement-theme-resolution.md`