Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 30 additions & 18 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,6 @@ export default function App({ repoPath }: { repoPath: string }) {

const launchers = repo?.mergedConfig.launchers ?? [];
const hooksMap: HooksMap = repo?.mergedConfig.hooks ?? {};
const hookCount = Object.keys(hooksMap).filter((e) => (hooksMap[e as HookEvent]?.length ?? 0) > 0).length;

return (
<div className="shell">
Expand All @@ -644,35 +643,32 @@ export default function App({ repoPath }: { repoPath: string }) {
<button
className={`sidebar-tab${view === "repository" ? " active" : ""}`}
onClick={() => setView("repository")}
title={t.tabRepository}
>
<HousePlus className="sidebar-tab-icon" size={16} />
<span className="sidebar-tab-label">{t.tabRepository}</span>
<HousePlus className="sidebar-tab-icon" size={22} strokeWidth={2.25} />
</button>
<button
className={`sidebar-tab${view === "worktrees" ? " active" : ""}`}
onClick={() => setView("worktrees")}
disabled={!repo}
title={t.tabWorktrees}
>
<FolderTree className="sidebar-tab-icon" size={16} />
<span className="sidebar-tab-label">{t.tabWorktrees}</span>
{repo && <span className="sidebar-tab-badge">{repo.worktrees.length}</span>}
<FolderTree className="sidebar-tab-icon" size={22} strokeWidth={2.25} />
</button>
<button
className={`sidebar-tab${view === "hooks" ? " active" : ""}`}
onClick={() => setView("hooks")}
disabled={!repo}
title={t.hooks}
>
<FishingHook className="sidebar-tab-icon" size={16} />
<span className="sidebar-tab-label">{t.hooks}</span>
{hookCount > 0 && <span className="sidebar-tab-badge">{hookCount}</span>}
<FishingHook className="sidebar-tab-icon" size={22} strokeWidth={2.25} />
</button>
<button
className={`sidebar-tab${view === "settings" ? " active" : ""}`}
onClick={() => setView("settings")}
title={t.settings}
>
<Settings className="sidebar-tab-icon" size={16} />
<span className="sidebar-tab-label">{t.settings}</span>
{updateInfo && <span className="sidebar-tab-badge" />}
<Settings className="sidebar-tab-icon" size={22} strokeWidth={2.25} />
</button>
</aside>

Expand All @@ -681,6 +677,8 @@ export default function App({ repoPath }: { repoPath: string }) {
{error && <div className="error-banner">{error}</div>}

{view === "repository" && (
<>
<h1 className="view-title">{t.tabRepository}</h1>
<div className="repo-view">
<section className="hero card">
<h2>{t.heroTitle}</h2>
Expand Down Expand Up @@ -722,18 +720,26 @@ export default function App({ repoPath }: { repoPath: string }) {
</div>
</section>
</div>
</>
)}

{view === "worktrees" && (
<>
{!repo ? (
<div className="repo-view">
<section className="hero card">
<h2>{t.loading}</h2>
</section>
</div>
<>
<h1 className="view-title">{t.tabWorktrees}</h1>
<div className="repo-view">
<section className="hero card">
<h2>{t.loading}</h2>
</section>
</div>
</>
) : (
<div className="worktrees-layout">
<div className="worktrees-title-panel">
<h1 className="view-title">{t.tabWorktrees}</h1>
</div>
<div className="worktrees-title-spacer" aria-hidden="true" />
<div className="worktrees-panel">
<div className="repo-name-label">{repo.repoRoot.split("/").pop()}</div>
<div className="worktree-toolbar">
Expand Down Expand Up @@ -824,6 +830,8 @@ export default function App({ repoPath }: { repoPath: string }) {
)}

{view === "hooks" && (
<>
<h1 className="view-title">{t.hooks}</h1>
<div className="hooks-view">
{!repo ? (
<section className="hero card">
Expand All @@ -847,10 +855,13 @@ export default function App({ repoPath }: { repoPath: string }) {
/>
)}
</div>
</>
)}

{view === "settings" && (
<SettingsPage
<>
<h1 className="view-title">{t.settings}</h1>
<SettingsPage
toolStatuses={repo?.toolStatuses ?? bootstrapState.toolStatuses}
logs={logs}
onClearLogs={() => setLogs([])}
Expand Down Expand Up @@ -898,6 +909,7 @@ export default function App({ repoPath }: { repoPath: string }) {
}}
onRetryDownload={() => setDownloadProgress(INITIAL_PROGRESS)}
/>
</>
)}
</main>
</div>
Expand Down
73 changes: 35 additions & 38 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -336,42 +336,42 @@ pre {
}

.sidebar {
width: 54px;
width: 48px;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 2px;
padding: 10px 8px;
align-items: center;
gap: 8px;
padding: 10px 6px;
border-right: 1px solid var(--border-faint);
background: var(--surface-sidebar);
}

.sidebar-tab {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
padding: 8px 8px 6px;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 10px;
background: transparent;
color: var(--ink-ghost);
font-size: 9px;
font-weight: 500;
white-space: nowrap;
border: none;
outline: none;
-webkit-tap-highlight-color: transparent;
cursor: pointer;
transition:
color 140ms ease,
background 140ms ease;
position: relative;
}

.sidebar-tab-icon {
flex-shrink: 0;
.sidebar-tab:focus-visible {
outline: none;
}

.sidebar-tab-label {
line-height: 1;
.sidebar-tab-icon {
flex-shrink: 0;
}

.sidebar-tab:hover {
Expand All @@ -393,29 +393,6 @@ pre {
background: transparent;
}

.sidebar-tab-badge {
position: absolute;
top: 4px;
right: 4px;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 14px;
height: 14px;
padding: 0 3px;
border-radius: 999px;
background: var(--teal-bg-strong);
color: var(--teal-muted);
font-size: 0.55rem;
font-weight: 700;
line-height: 1;
}

.sidebar-tab.active .sidebar-tab-badge {
background: var(--teal-bg-strong);
color: var(--teal-hover);
}

.topbar-path {
position: absolute;
left: 50%;
Expand Down Expand Up @@ -458,16 +435,25 @@ pre {
.main {
flex: 1;
min-width: 0;
padding: 24px 28px;
padding: 18px 18px 24px;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}

.main:has(> .worktrees-layout) {
.main:has(.worktrees-layout) {
padding: 0;
overflow: hidden;
gap: 0;
}

.view-title {
font-size: 14px;
font-weight: 600;
color: var(--ink-primary);
margin: 0;
letter-spacing: -0.01em;
}

.brand-mark {
Expand All @@ -481,18 +467,28 @@ pre {
.worktrees-layout {
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr);
gap: 0;
flex: 1;
min-height: 0;
}

.worktrees-title-panel {
display: flex;
align-items: flex-start;
padding: 18px 18px 6px;
background: var(--surface-warm);
border-right: 1px solid var(--border-default);
}

.worktrees-panel {
background: var(--surface-warm);
border-right: 1px solid var(--border-default);
padding: 12px 10px;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}

.worktree-toolbar {
Expand Down Expand Up @@ -527,6 +523,7 @@ pre {
}

.worktrees-detail {
min-height: 0;
padding: 24px 28px;
overflow-y: auto;
display: flex;
Expand Down
Loading