feat: better icons and overlay panes

This commit is contained in:
Brooklyn Nicholson
2026-05-04 14:20:18 -05:00
parent ca8f2c7907
commit d1d0ed4016
71 changed files with 2043 additions and 363 deletions
+6 -3
View File
@@ -19,27 +19,29 @@ import { TITLEBAR_HEIGHT, titlebarControlsPosition } from './titlebar'
import { TitlebarControls, type TitlebarTool } from './titlebar-controls'
interface AppShellProps {
commandCenterOpen: boolean
children: ReactNode
inspectorWidth: string
leftTitlebarTools?: readonly TitlebarTool[]
previewWidth: string
rightRailOpen: boolean
settingsOpen: boolean
sidebar: ReactNode
titlebarTools?: readonly TitlebarTool[]
onToggleCommandCenter: () => void
onOpenSettings: () => void
overlays?: ReactNode
}
export function AppShell({
commandCenterOpen,
children,
inspectorWidth,
leftTitlebarTools,
previewWidth,
rightRailOpen,
settingsOpen,
sidebar,
titlebarTools,
onToggleCommandCenter,
onOpenSettings,
overlays
}: AppShellProps) {
@@ -133,9 +135,10 @@ export function AppShell({
}
>
<TitlebarControls
commandCenterOpen={commandCenterOpen}
leftTools={leftTitlebarTools}
onOpenSettings={onOpenSettings}
settingsOpen={settingsOpen}
onToggleCommandCenter={onToggleCommandCenter}
showInspectorToggle={rightRailOpen}
tools={titlebarTools}
/>
@@ -1,10 +1,9 @@
import { useStore } from '@nanostores/react'
import { NotebookTabs, Search, Settings, SlidersHorizontal, Volume2, VolumeX } from 'lucide-react'
import type { ReactNode } from 'react'
import type * as React from 'react'
import type { ComponentProps, ReactNode } from 'react'
import { useNavigate } from 'react-router-dom'
import { triggerHaptic } from '@/lib/haptics'
import { Command, NotebookTabs, Settings, SlidersHorizontal, Volume2, VolumeX } from '@/lib/icons'
import { cn } from '@/lib/utils'
import { $hapticsMuted, toggleHapticsMuted } from '@/store/haptics'
import { $inspectorOpen, $sidebarOpen, toggleInspectorOpen, toggleSidebarOpen } from '@/store/layout'
@@ -28,19 +27,21 @@ export interface TitlebarTool {
export type TitlebarToolSide = 'left' | 'right'
export type SetTitlebarToolGroup = (id: string, tools: readonly TitlebarTool[], side?: TitlebarToolSide) => void
interface TitlebarControlsProps extends React.ComponentProps<'div'> {
interface TitlebarControlsProps extends ComponentProps<'div'> {
commandCenterOpen: boolean
leftTools?: readonly TitlebarTool[]
settingsOpen: boolean
showInspectorToggle: boolean
tools?: readonly TitlebarTool[]
onToggleCommandCenter: () => void
onOpenSettings: () => void
}
export function TitlebarControls({
commandCenterOpen,
leftTools = [],
settingsOpen,
showInspectorToggle,
tools = [],
onToggleCommandCenter,
onOpenSettings
}: TitlebarControlsProps) {
const navigate = useNavigate()
@@ -71,9 +72,15 @@ export function TitlebarControls({
}
},
{
icon: <Search size={TITLEBAR_ICON_SIZE} />,
id: 'search',
label: 'Search'
active: commandCenterOpen,
icon: <Command size={TITLEBAR_ICON_SIZE} />,
id: 'command-center',
label: commandCenterOpen ? 'Close command center' : 'Open command center',
title: commandCenterOpen ? 'Close command center' : 'Open command center',
onSelect: () => {
triggerHaptic('tap')
onToggleCommandCenter()
}
},
...leftTools
]
@@ -113,7 +120,7 @@ export function TitlebarControls({
<>
<div
aria-label="Window controls"
className="fixed left-(--titlebar-controls-left) top-(--titlebar-controls-top) z-2147483647 flex translate-y-[2px] flex-row items-center gap-px pointer-events-auto [-webkit-app-region:no-drag]"
className="fixed left-(--titlebar-controls-left) top-(--titlebar-controls-top) z-70 flex translate-y-[2px] flex-row items-center gap-px pointer-events-auto select-none [-webkit-app-region:no-drag]"
>
{leftToolbarTools
.filter(tool => !tool.hidden)
@@ -122,37 +129,24 @@ export function TitlebarControls({
))}
</div>
{!settingsOpen && (
<div
aria-label="App controls"
className="fixed right-(--titlebar-tools-right) top-(--titlebar-controls-top) z-2147483647 flex flex-row items-center justify-end gap-px pointer-events-auto [-webkit-app-region:no-drag]"
>
{rightToolbarTools
.filter(tool => !tool.hidden)
.map(tool => (
<TitlebarToolButton
key={tool.id}
navigate={navigate}
tool={tool}
/>
))}
</div>
)}
<div
aria-label="App controls"
className="fixed right-(--titlebar-tools-right) top-(--titlebar-controls-top) z-70 flex flex-row items-center justify-end gap-px pointer-events-auto select-none [-webkit-app-region:no-drag]"
>
{rightToolbarTools
.filter(tool => !tool.hidden)
.map(tool => (
<TitlebarToolButton key={tool.id} navigate={navigate} tool={tool} />
))}
</div>
</>
)
}
function TitlebarToolButton({
navigate,
tool
}: {
navigate: ReturnType<typeof useNavigate>
tool: TitlebarTool
}) {
function TitlebarToolButton({ navigate, tool }: { navigate: ReturnType<typeof useNavigate>; tool: TitlebarTool }) {
const className = cn(
titlebarButtonClass,
'grid place-items-center bg-transparent [&_svg]:size-3.5',
tool.active && 'bg-muted text-muted-foreground',
'grid place-items-center bg-transparent select-none [&_svg]:size-4',
tool.className
)
@@ -175,7 +169,7 @@ function TitlebarToolButton({
return (
<button
aria-label={tool.label}
aria-pressed={tool.active}
aria-pressed={tool.active ?? undefined}
className={className}
disabled={tool.disabled}
onClick={() => {