diff --git a/frontend/components/layout/UnifiedPanel.tsx b/frontend/components/layout/UnifiedPanel.tsx index e1241c2..b198cbe 100644 --- a/frontend/components/layout/UnifiedPanel.tsx +++ b/frontend/components/layout/UnifiedPanel.tsx @@ -1,9 +1,10 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { cn } from "@/utils/cn"; import { useNotifications, useActiveDownloads } from "@/hooks/useNotifications"; +import { useActivityPanelSettings } from "@/lib/activity-panel-settings-context"; import { ActivityIconBar, type ActivityType } from "@/features/vibe/ActivityIconBar"; import { type VibeTab, @@ -21,14 +22,45 @@ interface UnifiedPanelProps { export function UnifiedPanel({ isOpen, onToggle }: UnifiedPanelProps) { const [activeTab, setActiveTab] = useState("now-playing"); const [expandedActivity, setExpandedActivity] = useState(null); + // Externally-registered settings content (discover settings gear, lyrics). + // Pages register it via useActivityPanelSettings and open it by dispatching + // "set-activity-panel-tab" { tab: "settings" }; this panel renders it. + const [showSettings, setShowSettings] = useState(false); + const { settingsContent } = useActivityPanelSettings(); const { unreadCount } = useNotifications(); const { downloads: activeDownloads } = useActiveDownloads(); const hasActivity = unreadCount > 0 || activeDownloads.length > 0; const handleToggleActivity = (type: ActivityType) => { + setShowSettings(false); setExpandedActivity((prev) => (prev === type ? null : type)); }; + // Reset settings view on collapse so reopening shows the feed. + const handleCollapse = () => { + setShowSettings(false); + onToggle(); + }; + + // Respond to the cross-component tab event (discover gear, lyrics back button). + useEffect(() => { + const handleSetTab = (e: Event) => { + const tab = (e as CustomEvent<{ tab?: string }>).detail?.tab; + if (tab === "settings") { + setExpandedActivity(null); + setShowSettings(true); + } else { + setShowSettings(false); + } + }; + window.addEventListener("set-activity-panel-tab", handleSetTab); + return () => window.removeEventListener("set-activity-panel-tab", handleSetTab); + }, []); + + // settingsContent null (owner page unmounted) falls through to the feed via + // the `settingsContent &&` render guard -- no reset effect needed. + const settingsActive = showSettings && !!settingsContent; + return (
{/* Collapsed strip */}
+ {settingsActive ? ( + // Externally-registered settings (discover gear / lyrics). + // The content provides its own header and back button, + // which dispatches set-activity-panel-tab to exit. +
+ {settingsContent} +
+ ) : ( + <> {/* Header */}
@@ -72,7 +113,7 @@ export function UnifiedPanel({ isOpen, onToggle }: UnifiedPanelProps) {