diff --git a/apps/ui/src/components/ui/course-promo-badge.tsx b/apps/ui/src/components/ui/course-promo-badge.tsx index 4a888fb6..74353ae6 100644 --- a/apps/ui/src/components/ui/course-promo-badge.tsx +++ b/apps/ui/src/components/ui/course-promo-badge.tsx @@ -7,6 +7,7 @@ import { TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; +import { useAppStore } from "@/store/app-store"; interface CoursePromoBadgeProps { sidebarOpen?: boolean; @@ -14,8 +15,10 @@ interface CoursePromoBadgeProps { export function CoursePromoBadge({ sidebarOpen = true }: CoursePromoBadgeProps) { const [dismissed, setDismissed] = React.useState(false); + const hideMarketingContent = useAppStore((state) => state.hideMarketingContent); - if (dismissed) { + // If marketing content is hidden globally or dismissed locally, don't render + if (hideMarketingContent || dismissed) { return null; } diff --git a/apps/ui/src/components/ui/log-viewer.tsx b/apps/ui/src/components/ui/log-viewer.tsx index a49a8b23..af339adf 100644 --- a/apps/ui/src/components/ui/log-viewer.tsx +++ b/apps/ui/src/components/ui/log-viewer.tsx @@ -379,7 +379,7 @@ function LogEntryItem({ entry, isExpanded, onToggle }: LogEntryItemProps) { {formattedContent.map((part, index) => (
+{part.content}) : ( @@ -418,6 +418,8 @@ export function LogViewer({ output, className }: LogViewerProps) { const [searchQuery, setSearchQuery] = useState(""); const [hiddenTypes, setHiddenTypes] = useState>(new Set()); const [hiddenCategories, setHiddenCategories] = useState >(new Set()); + // Track if user has "Expand All" mode active - new entries will auto-expand when this is true + const [expandAllMode, setExpandAllMode] = useState(false); // Parse entries and compute initial expanded state together const { entries, initialExpandedIds } = useMemo(() => { @@ -442,16 +444,27 @@ export function LogViewer({ output, className }: LogViewerProps) { const appliedInitialRef = useRef >(new Set()); // Apply initial expanded state for new entries + // Also auto-expand all entries when expandAllMode is active const effectiveExpandedIds = useMemo(() => { const result = new Set(expandedIds); - initialExpandedIds.forEach((id) => { - if (!appliedInitialRef.current.has(id)) { - appliedInitialRef.current.add(id); - result.add(id); - } - }); + + // If expand all mode is active, expand all filtered entries + if (expandAllMode) { + entries.forEach((entry) => { + result.add(entry.id); + }); + } else { + // Otherwise, only auto-expand entries based on initial state (shouldCollapseByDefault) + initialExpandedIds.forEach((id) => { + if (!appliedInitialRef.current.has(id)) { + appliedInitialRef.current.add(id); + result.add(id); + } + }); + } + return result; - }, [expandedIds, initialExpandedIds]); + }, [expandedIds, initialExpandedIds, expandAllMode, entries]); // Calculate stats for tool categories const stats = useMemo(() => { @@ -507,6 +520,10 @@ export function LogViewer({ output, className }: LogViewerProps) { }, [entries, hiddenTypes, hiddenCategories, searchQuery]); const toggleEntry = (id: string) => { + // When user manually collapses an entry, turn off expand all mode + if (effectiveExpandedIds.has(id)) { + setExpandAllMode(false); + } setExpandedIds((prev) => { const next = new Set(prev); if (next.has(id)) { @@ -519,10 +536,14 @@ export function LogViewer({ output, className }: LogViewerProps) { }; const expandAll = () => { + // Enable expand all mode so new entries will also be expanded + setExpandAllMode(true); setExpandedIds(new Set(filteredEntries.map((e) => e.id))); }; const collapseAll = () => { + // Disable expand all mode when collapsing all + setExpandAllMode(false); setExpandedIds(new Set()); }; @@ -565,7 +586,7 @@ export function LogViewer({ output, className }: LogViewerProps) { No log entries yet. Logs will appear here as the process runs.
{output && output.trim() && ( -+)} @@ -699,10 +720,16 @@ export function LogViewer({ output, className }: LogViewerProps) { ); case "keyboard": diff --git a/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx b/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx index 05ce6f57..40a21650 100644 --- a/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx +++ b/apps/ui/src/components/views/settings-view/appearance/appearance-section.tsx @@ -1,6 +1,6 @@ -import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; -import { Palette } from "lucide-react"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Palette, Megaphone } from "lucide-react"; import { themeOptions } from "@/config/theme-options"; import { cn } from "@/lib/utils"; import type { Theme, Project } from "../shared/types"; @@ -8,13 +8,17 @@ import type { Theme, Project } from "../shared/types"; interface AppearanceSectionProps { effectiveTheme: Theme; currentProject: Project | null; + hideMarketingContent: boolean; onThemeChange: (theme: Theme) => void; + onHideMarketingContentChange: (hide: boolean) => void; } export function AppearanceSection({ effectiveTheme, currentProject, + hideMarketingContent, onThemeChange, + onHideMarketingContentChange, }: AppearanceSectionProps) { return ({output}+ + {/* Separator */} + + + {/* Hide Marketing Content Setting */} +++ onHideMarketingContentChange(checked === true) + } + className="mt-1" + data-testid="hide-marketing-content-checkbox" + /> + + +++ When enabled, hides promotional content like the "Become a 10x Dev" badge + in the sidebar. This setting persists across sessions. +
+