Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c45093f
style: redesign UI with Codex dark theme aesthetic
gnoviawan Mar 12, 2026
5277f91
style: remove panel borders and add rounded corners for Codex aesthetic
gnoviawan Mar 12, 2026
16e1353
style: make scrollbar thinner (6px) for minimal Codex aesthetic
gnoviawan Mar 12, 2026
3fcccb6
style: reduce scrollbar to 4px for ultra-minimal look
gnoviawan Mar 12, 2026
cda434c
style: use background color for title bar, remove border
gnoviawan Mar 12, 2026
731cad9
style: reduce tab text size from text-sm to text-xs
gnoviawan Mar 12, 2026
3da9508
style: make ResizableHandle transparent for cleaner panel separation
gnoviawan Mar 12, 2026
8ba4f99
fix: restructure File Explorer as separate panel
gnoviawan Mar 12, 2026
e7af3ff
fix: wrap FileExplorer in PaneDndProvider for drag-drop context
gnoviawan Mar 12, 2026
45251d9
fix: properly separate main content and file explorer with flex layout
gnoviawan Mar 12, 2026
9405dc9
fix: restructure layout - separate FileExplorer from main content
gnoviawan Mar 12, 2026
13935fe
fix: add h-full to terminal containers for proper display
gnoviawan Mar 12, 2026
fcd8743
fix: restructure layout with proper padding and height
gnoviawan Mar 12, 2026
244f570
fix: resolve layout and terminal issues after sidebar redesign
gnoviawan Mar 12, 2026
9faf9d0
fix: review fixes - tab contrast, terminal shortcut guard, menu radiu…
gnoviawan Mar 12, 2026
dfdaba8
fix: clear stale file explorer on project removal, allow sidebar togg…
gnoviawan Mar 12, 2026
e84a8a7
test: update ProjectSidebar test for version label replacing new proj…
gnoviawan Mar 12, 2026
7fe257b
fix: guard against empty path in explorer root sync and clean up stal…
gnoviawan Mar 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions src/renderer/components/ProjectSidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,10 @@ describe('ProjectSidebar', () => {
expect(onNewProject).toHaveBeenCalled()
})

it('should call onNewProject when bottom + button is clicked', () => {
const onNewProject = vi.fn()
renderWithRouter({ onNewProject })
it('should show version label at the bottom', () => {
renderWithRouter({})

// Use data-testid for robust button selection
const bottomButton = screen.getByTestId('bottom-new-project')
fireEvent.click(bottomButton)

expect(onNewProject).toHaveBeenCalled()
expect(screen.getByText(/Termul v/)).toBeInTheDocument()
})

it('should show empty state when no projects', () => {
Expand Down
30 changes: 12 additions & 18 deletions src/renderer/components/ProjectSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,15 +310,15 @@ export function ProjectSidebar({
)

return (
<aside className="w-64 bg-card border-r border-border flex flex-col flex-shrink-0">
<aside className="w-64 bg-sidebar flex flex-col flex-shrink-0 rounded-xl h-full">
{/* Header with inline + button */}
<div className="h-10 flex items-center justify-between px-4 border-b border-border">
<span className="text-xs font-semibold tracking-wider text-muted-foreground uppercase">
<div className="h-10 flex items-center justify-between px-4 border-b border-sidebar-border rounded-t-xl">
<span className="text-xs font-semibold tracking-wider text-sidebar-foreground uppercase">
Projects
</span>
<button
onClick={onNewProject}
className="group h-6 w-6 inline-flex items-center justify-center rounded hover:bg-secondary transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
className="group h-6 w-6 inline-flex items-center justify-center rounded-md hover:bg-sidebar-accent transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
title="New Project"
aria-label="Create new project from header"
data-testid="header-new-project"
Expand Down Expand Up @@ -376,7 +376,7 @@ export function ProjectSidebar({
<div className="mt-2">
<button
onClick={() => setShowArchived(!showArchived)}
className="w-full flex items-center px-4 py-2 text-xs font-semibold tracking-wider text-muted-foreground uppercase hover:bg-secondary/50 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
className="w-full flex items-center px-4 py-2 text-xs font-semibold tracking-wider text-sidebar-foreground uppercase hover:bg-sidebar-accent/50 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
aria-expanded={showArchived}
aria-label={`Archived projects (${archivedProjects.length})`}
>
Expand All @@ -402,17 +402,11 @@ export function ProjectSidebar({
)}
</div>

{/* Bottom toolbar - New Project only */}
<div className="border-t border-border p-2">
<button
onClick={onNewProject}
className="group w-full h-8 inline-flex items-center justify-center rounded hover:bg-secondary transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
title="New Project"
aria-label="Create new project from toolbar"
data-testid="bottom-new-project"
>
<Plus size={16} className="text-muted-foreground group-hover:text-foreground" />
</button>
{/* Bottom toolbar - Version */}
<div className="p-2 rounded-b-xl">
<div className="w-full h-8 inline-flex items-center justify-center">
<span className="text-xs text-muted-foreground">Termul v0.3.0-4</span>
</div>
</div>

{/* Context Menu */}
Expand Down Expand Up @@ -505,7 +499,7 @@ function ProjectItem({
onContextMenu={onContextMenu}
className={cn(
'w-full flex items-center px-0 py-2 transition-colors group text-left border-l-2',
isActive ? `${colors.border} bg-secondary` : `${colors.borderMuted} hover:bg-secondary/50`
isActive ? `${colors.border} bg-sidebar-accent` : `${colors.borderMuted} hover:bg-sidebar-accent/50`
)}
aria-current={isActive ? 'page' : undefined}
aria-label={`Project: ${project.name}${isActive ? ' (active)' : ''}`}
Expand All @@ -529,7 +523,7 @@ function ProjectItem({
onChange={(e) => onEditNameChange(e.target.value)}
onKeyDown={handleKeyDown}
onBlur={onSaveRename}
className="flex-1 bg-secondary border border-border rounded px-2 py-0.5 text-sm text-foreground outline-none focus:ring-1 focus:ring-primary mr-2"
className="flex-1 bg-sidebar-accent border border-border rounded-md px-2 py-0.5 text-sm text-foreground outline-none focus:ring-1 focus:ring-primary mr-2"
onClick={(e) => e.stopPropagation()}
/>
) : (
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/TitleBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useUpdatePanelVisibility } from '@/hooks/use-app-settings'
import { windowApi } from '@/lib/api'
import { toast } from 'sonner'

const focusableButtonClass = 'h-full px-3 hover:bg-secondary inline-flex items-center focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-inset'
const focusableButtonClass = 'h-full px-3 hover:bg-secondary/80 inline-flex items-center focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-inset'

export function TitleBar(): React.JSX.Element {
const [isMaximized, setIsMaximized] = useState(false)
Expand Down Expand Up @@ -43,7 +43,7 @@ export function TitleBar(): React.JSX.Element {

return (
<header
className="h-8 flex items-center bg-card border-b border-border select-none shrink-0"
className="h-8 flex items-center bg-background select-none shrink-0"
>
<div
className="flex items-center h-full px-3"
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/file-explorer/FileExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
}
}
},
[togglePathSelection, selectPathRange, selectPath, toggleDirectory]

Check warning on line 134 in src/renderer/components/file-explorer/FileExplorer.tsx

View workflow job for this annotation

GitHub Actions / Lint, Typecheck & Test

React Hook useCallback has a missing dependency: 'handleSelect'. Either include it or remove the dependency array
)

// Handle keyboard shortcuts
Expand Down Expand Up @@ -418,11 +418,11 @@
return (
<div
ref={containerRef}
className="h-full flex flex-col bg-background text-foreground"
className="w-64 flex flex-col bg-background text-foreground rounded-xl flex-shrink-0 h-full"
tabIndex={0}
>
{/* Header */}
<div className="flex items-center justify-between px-3 h-10 border-b border-border flex-shrink-0">
<div className="flex items-center justify-between px-3 h-10 border-b border-border flex-shrink-0 rounded-t-xl">
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">
Explorer
</span>
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
outline: 'border border-input bg-background hover:bg-secondary hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
ghost: 'hover:bg-secondary hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
sm: 'h-9 rounded-lg px-3',
lg: 'h-11 rounded-lg px-8',
icon: 'h-10 w-10'
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}
className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}
{...props}
/>
)
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/components/ui/context-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const ContextMenuSubTrigger = React.forwardRef<
<ContextMenuPrimitive.SubTrigger
ref={ref}
className={cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-secondary focus:bg-secondary',
inset && 'pl-8',
className
)}
Expand Down Expand Up @@ -60,7 +60,7 @@ const ContextMenuContent = React.forwardRef<
<ContextMenuPrimitive.Content
ref={ref}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
Expand All @@ -78,7 +78,7 @@ const ContextMenuItem = React.forwardRef<
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
inset && 'pl-8',
className
)}
Expand All @@ -94,7 +94,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
<ContextMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
className
)}
checked={checked}
Expand All @@ -117,7 +117,7 @@ const ContextMenuRadioItem = React.forwardRef<
<ContextMenuPrimitive.RadioItem
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
className
)}
{...props}
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'fixed inset-0 z-50 bg-black/90 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className
)}
{...props}
Expand All @@ -36,13 +36,13 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-xl',
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-lg opacity-70 ring-offset-background transition-opacity hover:bg-secondary hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
Expand Down
14 changes: 7 additions & 7 deletions src/renderer/components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-accent focus:bg-accent',
'flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none data-[state=open]:bg-secondary focus:bg-secondary',
inset && 'pl-8',
className
)}
Expand All @@ -44,7 +44,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
Expand All @@ -61,7 +61,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
Expand All @@ -79,7 +79,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
inset && 'pl-8',
className
)}
Expand All @@ -95,7 +95,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-md py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
className
)}
checked={checked}
Expand All @@ -118,7 +118,7 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground',
'relative flex cursor-default select-none items-center rounded-md py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-secondary focus:text-accent-foreground',
className
)}
{...props}
Expand Down Expand Up @@ -153,7 +153,7 @@ const DropdownMenuSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn('-mx-1 my-1 h-px bg-muted', className)}
className={cn('-mx-1 my-1 h-px bg-border', className)}
{...props}
/>
))
Expand Down
Loading
Loading