From cedf1c3d9e7c1abe576c28e1077629f138575c8b Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 23:31:49 +0000 Subject: [PATCH 01/23] Update generated --- packages/but-sdk/src/generated/index.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/but-sdk/src/generated/index.d.ts b/packages/but-sdk/src/generated/index.d.ts index 5328823f01..efa4b301ec 100644 --- a/packages/but-sdk/src/generated/index.d.ts +++ b/packages/but-sdk/src/generated/index.d.ts @@ -3,6 +3,11 @@ /** Just like [apply_only()], but will create an oplog entry as well on success. */ export declare function apply(projectId: string, existingBranch: string): Promise +/** + * Persist hunk-to-commit assignments for the current workspace. + * + * `assignments` is a list of hunk assignment requests produced by the UI. + */ export declare function assignHunk(projectId: string, assignments: Array): Promise export declare function branchDetails(projectId: string, branchName: string, remote: string | null): Promise From 772c43ff0d6ec52f9e4a7b9c4a66609a041cabff Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 23:26:16 +0000 Subject: [PATCH 02/23] Fix normalize logic to handle commits in multiple stacks --- apps/lite/ui/src/routes/project-index.tsx | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 742547d227..8e23d23d9b 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -79,14 +79,18 @@ const getBranchNameByCommitId = (headInfo: RefInfo): Map => { return byCommitId; }; -const getStackIdByCommitId = (headInfo: RefInfo): Map => { - const byCommitId = new Map(); +const getStackIdsByCommitId = (headInfo: RefInfo): Map> => { + const byCommitId = new Map>(); for (const stack of headInfo.stacks) { if (stack.id == null) continue; for (const segment of stack.segments) - for (const commit of segment.commits) byCommitId.set(commit.id, stack.id); + for (const commit of segment.commits) { + const stackIds = byCommitId.get(commit.id) ?? new Set(); + stackIds.add(stack.id); + byCommitId.set(commit.id, stackIds); + } } return byCommitId; @@ -542,14 +546,14 @@ type Selection = const normalizeSelection = ( selection: Selection, - stackIdByCommitId: Map, + stackIdsByCommitId: Map>, ): Selection | null => Match.value(selection).pipe( Match.tag("changes", (selection) => selection), Match.tag("commit", (selection) => { - const stackId = stackIdByCommitId.get(selection.commitId); - if (stackId === undefined) return null; - if (stackId !== selection.stackId) return null; + const stackIds = stackIdsByCommitId.get(selection.commitId); + if (stackIds === undefined) return null; + if (!stackIds.has(selection.stackId)) return null; return selection; }), Match.exhaustive, @@ -1097,7 +1101,7 @@ const ProjectPage: FC = () => { `project:${projectId}:workspace:selection`, { defaultValue: null }, ); - const commitStackIds = getStackIdByCommitId(headInfo); + const commitStackIds = getStackIdsByCommitId(headInfo); const selection = _selection ? normalizeSelection(_selection, commitStackIds) : null; useMonitorDraggedSourceItem({ projectId, setDraggedSourceItem }); From 13b78a6650d41006f193bee4a0233b86ae2aacd7 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:57:05 +0000 Subject: [PATCH 03/23] Update agents --- apps/lite/AGENTS.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/lite/AGENTS.md b/apps/lite/AGENTS.md index 9db55eccb2..2bbb952581 100644 --- a/apps/lite/AGENTS.md +++ b/apps/lite/AGENTS.md @@ -5,3 +5,19 @@ Typechecking is the fastest way to validate that everything is okay. Always run ```console $ pnpm -F @gitbutler/lite check ``` + +## Components + +Memoization utilities such as `useMemo`, `useCallback`, and `React.memo` are redundant as we use React Compiler. + +Component definitions should follow this pattern, optionally destructuring `p`: + +```tsx +type Props = { + ... +}; + +export const MyComponent: FC = (p) => { + // [...] +}; +``` From 956bc00414bb88d015789fcded841a65c8ca920d Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 21:36:17 +0000 Subject: [PATCH 04/23] Default selection --- apps/lite/ui/src/routes/project-branches.tsx | 10 +++- apps/lite/ui/src/routes/project-index.tsx | 55 +++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index dc4386d1d6..85eca40fc6 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -40,6 +40,12 @@ const normalizeSelectionForBranches = ( return selection; }; +const getDefaultSelection = (branches: Array): Selection | null => { + const firstBranch = branches[0]; + if (!firstBranch) return null; + return { branchName: firstBranch.name }; +}; + const normalizeSelectionForBranchDetails = ( selection: Selection, branchDetails: BranchDetails, @@ -301,7 +307,9 @@ const ProjectBranchesPage: FC = () => { `project:${projectId}:branches:selection`, { defaultValue: null }, ); - const selection = _selection ? normalizeSelectionForBranches(_selection, sortedBranches) : null; + const selection = + (_selection ? normalizeSelectionForBranches(_selection, sortedBranches) : null) ?? + getDefaultSelection(sortedBranches); const selectedBranch = sortedBranches.find((branch) => branch.name === selection?.branchName); const selectedRemote = selectedBranch && !selectedBranch.hasLocal ? selectedBranch.remotes[0] : null; diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 8e23d23d9b..efbc86f951 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -559,6 +559,52 @@ const normalizeSelection = ( Match.exhaustive, ); +const firstSelectablePath = ({ + changes, + assignments, + stackId, +}: { + changes: Array; + assignments: Array; + stackId: string | null; +}): string | null => { + const assignmentsByPath = getAssignmentsByPath(assignments, stackId); + return changes.find((change) => assignmentsByPath.has(change.path))?.path ?? null; +}; + +const getDefaultSelection = ({ + headInfo, + changes, + assignments, +}: { + headInfo: RefInfo; + changes: Array; + assignments: Array; +}): Selection | null => { + const firstUnassignedPath = firstSelectablePath({ changes, assignments, stackId: null }); + if (firstUnassignedPath !== null) + return { _tag: "changes", stackId: null, path: firstUnassignedPath }; + + for (const stack of headInfo.stacks) { + if (stack.id == null) continue; + + const firstAssignedPath = firstSelectablePath({ + changes, + assignments, + stackId: stack.id, + }); + if (firstAssignedPath !== null) + return { _tag: "changes", stackId: stack.id, path: firstAssignedPath }; + + for (const segment of stack.segments) { + const firstCommit = segment.commits[0]; + if (firstCommit) return { _tag: "commit", stackId: stack.id, commitId: firstCommit.id }; + } + } + + return null; +}; + const Preview: FC<{ projectId: string; selection: Selection; @@ -1096,13 +1142,20 @@ const ProjectPage: FC = () => { // TODO: handle project not found error. or only run when project is not null? waterfall. const { data: headInfo } = useSuspenseQuery(headInfoQueryOptions(projectId)); + const { data: worktreeChanges } = useSuspenseQuery(changesInWorktreeQueryOptions(projectId)); const [_selection, select] = useLocalStorageState( `project:${projectId}:workspace:selection`, { defaultValue: null }, ); const commitStackIds = getStackIdsByCommitId(headInfo); - const selection = _selection ? normalizeSelection(_selection, commitStackIds) : null; + const selection = + (_selection ? normalizeSelection(_selection, commitStackIds) : null) ?? + getDefaultSelection({ + headInfo, + changes: worktreeChanges.changes, + assignments: worktreeChanges.assignments, + }); useMonitorDraggedSourceItem({ projectId, setDraggedSourceItem }); From 392a133d6678db5def0538c5912acff4e4b21d76 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:24:27 +0000 Subject: [PATCH 05/23] Don't use current color --- apps/lite/ui/src/routes/project-index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index efbc86f951..7b6677c09a 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -651,7 +651,7 @@ const RubTarget: FC< render, ref: dropRef, props: mergeProps(props, { - style: { ...(isDropTarget && { outline: "2px dashed" }) }, + style: { ...(isDropTarget && { outline: "2px dashed black" }) }, }), }); @@ -1006,7 +1006,7 @@ const CommitMoveToBranchTarget: FC< render, ref: dropRef, props: mergeProps(props, { - style: { ...(isDropTarget && { outline: "2px dashed" }) }, + style: { ...(isDropTarget && { outline: "2px dashed black" }) }, }), }); From b77c04ee5b37ad6cb1fe32d9172c93902df9c537 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:07:26 +0000 Subject: [PATCH 06/23] Show commit row as selected/highlighted, not just button --- apps/lite/ui/src/routes/project-branches.tsx | 13 ++--- .../ui/src/routes/project-index.module.css | 5 ++ apps/lite/ui/src/routes/project-index.tsx | 17 ++++-- .../ui/src/routes/project-shared.module.css | 16 ++++++ apps/lite/ui/src/routes/project-shared.tsx | 54 ++++++------------- 5 files changed, 58 insertions(+), 47 deletions(-) diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index 85eca40fc6..7c0d85966e 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -99,12 +99,13 @@ const CommitC: FC<{ projectId={projectId} commitId={commit.id} renderFile={(change) => ( -
- toggleFileSelect(change.path)} - /> +
+ toggleFileSelect(change.path)} />
)} /> diff --git a/apps/lite/ui/src/routes/project-index.module.css b/apps/lite/ui/src/routes/project-index.module.css index e06cbbc428..a4f114608e 100644 --- a/apps/lite/ui/src/routes/project-index.module.css +++ b/apps/lite/ui/src/routes/project-index.module.css @@ -61,6 +61,11 @@ background-color: white; } +.dependencyIndicator { + background-color: transparent; + color: inherit; +} + .stack { display: flex; row-gap: 16px; diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 7b6677c09a..9ebb28f333 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -113,6 +113,7 @@ const DependencyIndicator: FC<{ return ( { onHover(commitIds); @@ -791,14 +792,18 @@ const CommitC: FC<{ projectId={projectId} commitId={commit.id} renderFile={(change) => ( -
+
toggleFileSelect(change.path)} /> } @@ -859,7 +864,12 @@ const Changes: FC<{ return (
  • -
    +
    { toggleFileSelect(change.path); }} diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index d584b8b59f..b2f12dc838 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -61,6 +61,8 @@ .commitButton { flex-grow: 1; + background-color: transparent; + color: inherit; } .fileList { @@ -74,6 +76,8 @@ .fileButton { flex-grow: 1; + background-color: transparent; + color: inherit; } .selected { @@ -85,6 +89,11 @@ background-color: lightgray; } +.highlighted { + background-color: yellow; + color: black; +} + .hunks { padding-left: 0; list-style: none; @@ -117,6 +126,13 @@ field-sizing: content; box-sizing: content-box; min-height: calc(2lh); + background-color: transparent; + color: inherit; +} + +.menuTrigger { + background-color: transparent; + color: inherit; } .menuPopup { diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index b3c316ce01..dd5262d156 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -177,14 +177,13 @@ export const FileDiff: FC<{ export const FileButton: FC< { change: TreeChange; - isSelected: boolean; toggleSelect: () => void; } & ComponentProps<"button"> -> = ({ change, isSelected, toggleSelect, className, ...restProps }) => ( +> = ({ change, toggleSelect, className, ...restProps }) => ( } @@ -461,7 +439,9 @@ export const CommitRow: FC< )} - 𑁔 + + 𑁔 + Date: Wed, 18 Mar 2026 22:18:04 +0000 Subject: [PATCH 07/23] Fix branches selection style when commit is selected --- apps/lite/ui/src/routes/project-branches.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index 7c0d85966e..5ff1a91d4c 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -314,6 +314,10 @@ const ProjectBranchesPage: FC = () => { const selectedBranch = sortedBranches.find((branch) => branch.name === selection?.branchName); const selectedRemote = selectedBranch && !selectedBranch.hasLocal ? selectedBranch.remotes[0] : null; + const isBranchSelected = (branchName: string) => + selection?.branchName === branchName && selection.commitId === undefined; + const isBranchSelectedWithin = (branchName: string) => + selection?.branchName === branchName && selection.commitId !== undefined; const isCommitSelected = (branchName: string, commitId: string) => selection?.branchName === branchName && @@ -364,12 +368,20 @@ const ProjectBranchesPage: FC = () => { {sortedBranches.map((branch) => { const ref = getBranchRef(branch); const stackId = branch.stack?.id; - const isSelected = selectedBranch?.name === branch.name; + const isSelected = isBranchSelected(branch.name); + const isSelectedWithin = isBranchSelectedWithin(branch.name); return (
  • + } + /> )} /> @@ -864,33 +864,33 @@ const Changes: FC<{ return (
  • -
    - { toggleFileSelect(change.path); }} /> - } - /> - {isNonEmptyArray(dependencyCommitIds) && ( - - )} -
    + {isNonEmptyArray(dependencyCommitIds) && ( + + )} +
  • + } + /> ); })} diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index dd5262d156..0885899e3a 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -247,8 +247,9 @@ export const CommitLabel: FC<{ const DraggableCommit: FC< { commit: Commit; + canDrag?: boolean; } & useRender.ComponentProps<"div"> -> = ({ commit, render, ...props }) => { +> = ({ commit, canDrag = true, render, ...props }) => { const [isDragging, dragRef] = useDraggable({ getInitialData: (): DragData => ({ sourceItem: { _tag: "Commit", commitId: commit.id }, @@ -258,6 +259,7 @@ const DraggableCommit: FC< ), + canDrag: () => canDrag, }); return useRender({ @@ -394,65 +396,66 @@ export const CommitRow: FC< }; return ( -
    - {isEditingMessage ? ( - { - setIsEditingMessage(false); - }} - /> - ) : ( - - + {isEditingMessage ? ( + { + setIsEditingMessage(false); + }} + /> + ) : ( + + } /> - } - /> - - - setIsEditingMessage(true)} - onInsertBlank={insertBlankCommit} - parts={ContextMenu} - /> - - - - )} - - - 𑁔 - - - - setIsEditingMessage(true)} - onInsertBlank={insertBlankCommit} - parts={Menu} - /> - - - -
    + + + setIsEditingMessage(true)} + onInsertBlank={insertBlankCommit} + parts={ContextMenu} + /> + + + + )} + + + 𑁔 + + + + setIsEditingMessage(true)} + onInsertBlank={insertBlankCommit} + parts={Menu} + /> + + + +
    + } + /> ); }; From 91e29d04f31bf28f5804d82361428ae91d73acf7 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:57:58 +0000 Subject: [PATCH 10/23] Make commit move target overlap commits to remove gap --- apps/lite/ui/src/routes/project-index.module.css | 16 +++++++++++++--- apps/lite/ui/src/routes/project-index.tsx | 5 +++++ .../lite/ui/src/routes/project-shared.module.css | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.module.css b/apps/lite/ui/src/routes/project-index.module.css index a4f114608e..90864b0662 100644 --- a/apps/lite/ui/src/routes/project-index.module.css +++ b/apps/lite/ui/src/routes/project-index.module.css @@ -29,15 +29,15 @@ } .commitMoveTarget { - --hit-area: 19px; + --hit-area: 17px; --indicator-height: 3px; display: flex; - position: relative; + position: absolute; flex-direction: column; justify-content: center; height: var(--hit-area); - margin-block: calc(((var(--hit-area) - var(--indicator-height)) / 2) * -1); + inset-inline: 0; pointer-events: none; &:before { @@ -47,6 +47,16 @@ } } +.commitMoveTargetAbove { + top: 0; + transform: translateY(calc((var(--hit-area) - var(--indicator-height)) / -2)); +} + +.commitMoveTargetBelow { + bottom: 0; + transform: translateY(calc((var(--hit-area) - var(--indicator-height)) / 2)); +} + .commitMoveTargetEnabled { pointer-events: auto; } diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 253bc46645..3596c58b1e 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -700,6 +700,11 @@ const CommitMoveTarget: FC<{ ref={dropRef} className={classes( styles.commitMoveTarget, + Match.value(side).pipe( + Match.when("above", () => styles.commitMoveTargetAbove), + Match.when("below", () => styles.commitMoveTargetBelow), + Match.exhaustive, + ), sourceItem?._tag === "Commit" && !isNoOp(sourceItem.commitId) && styles.commitMoveTargetEnabled, diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index b2f12dc838..17fe6c7178 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -43,6 +43,7 @@ .commit { display: flex; + position: relative; flex-direction: column; } From 178d5309b5c9d61dc11a4b4dd288636ec3de43cb Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:58:03 +0000 Subject: [PATCH 11/23] Fix commit row alignment when editor open --- apps/lite/ui/src/routes/project-shared.module.css | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index 17fe6c7178..e9fc89e305 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -49,6 +49,7 @@ .commitRow { display: flex; + align-items: baseline; } .commitDetails { From 6d673080bff160240ce895c713a5cf839bf41c50 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:58:03 +0000 Subject: [PATCH 12/23] Remove button borders --- apps/lite/ui/src/global.css | 3 +-- apps/lite/ui/src/routes/project-shared.module.css | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/global.css b/apps/lite/ui/src/global.css index 0851817c55..af41fa9c1c 100644 --- a/apps/lite/ui/src/global.css +++ b/apps/lite/ui/src/global.css @@ -16,8 +16,7 @@ select { } button { - border: 1px solid; - border-color: black; + border: none; font: inherit; line-height: inherit; text-align: left; diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index e9fc89e305..f7603d48e9 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -128,6 +128,7 @@ field-sizing: content; box-sizing: content-box; min-height: calc(2lh); + border: none; background-color: transparent; color: inherit; } From 3c235c7ba793fd8a26c8ef54a75e8927dac02fec Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 02:14:14 +0000 Subject: [PATCH 13/23] Remove heading --- apps/lite/ui/src/routes/project-index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 3596c58b1e..025cb3f777 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -1109,7 +1109,6 @@ const StackC: FC<{ render={

    {branchName}

    } /> -

    Commits

    {(commit, index) => { const changeUnit: ChangeUnit = { From e2b2f8042e2582a44657912c05d021ec682d22d0 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 18 Mar 2026 22:07:00 +0000 Subject: [PATCH 14/23] Style resets --- apps/lite/ui/src/global.css | 14 +++++++--- .../ui/src/routes/project-branches.module.css | 2 -- apps/lite/ui/src/routes/project-branches.tsx | 4 +-- .../ui/src/routes/project-index.module.css | 7 ----- apps/lite/ui/src/routes/project-index.tsx | 17 ++++++++---- .../ui/src/routes/project-shared.module.css | 27 ------------------- apps/lite/ui/src/routes/project-shared.tsx | 12 ++++----- 7 files changed, 30 insertions(+), 53 deletions(-) diff --git a/apps/lite/ui/src/global.css b/apps/lite/ui/src/global.css index af41fa9c1c..8d1398f6de 100644 --- a/apps/lite/ui/src/global.css +++ b/apps/lite/ui/src/global.css @@ -11,12 +11,19 @@ body { input, textarea, select { + padding: 0; + border: none; + background: none; + color: inherit; font: inherit; line-height: inherit; } button { + padding: 0; border: none; + background: none; + color: inherit; font: inherit; line-height: inherit; text-align: left; @@ -41,7 +48,8 @@ p { margin-block: 0; } -textarea, -button { - padding: 2px 4px; +ul, +ol { + padding-left: 0; + list-style: none; } diff --git a/apps/lite/ui/src/routes/project-branches.module.css b/apps/lite/ui/src/routes/project-branches.module.css index b33a19ee4f..5f5d46c910 100644 --- a/apps/lite/ui/src/routes/project-branches.module.css +++ b/apps/lite/ui/src/routes/project-branches.module.css @@ -1,8 +1,6 @@ .branchesList { flex-shrink: 0; width: 350px; - padding-left: 0; - list-style: none; } .branchesListItem { diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index 8c7aabe74a..01b29bfc0d 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -197,7 +197,7 @@ const CommitDiff: FC<{ if (data.changes.length === 0) return null; return ( -
      +
        {data.changes.map((change) => (
      • {change.path}
        @@ -232,7 +232,7 @@ const ShowBranch: FC<{ {data.changes.length === 0 ? (
        No file changes.
        ) : ( -
          +
            {data.changes.map((change) => (
          • {change.path}
            diff --git a/apps/lite/ui/src/routes/project-index.module.css b/apps/lite/ui/src/routes/project-index.module.css index 90864b0662..33be2a09df 100644 --- a/apps/lite/ui/src/routes/project-index.module.css +++ b/apps/lite/ui/src/routes/project-index.module.css @@ -24,8 +24,6 @@ display: flex; row-gap: 16px; flex-direction: column; - padding-left: 0; - list-style: none; } .commitMoveTarget { @@ -71,11 +69,6 @@ background-color: white; } -.dependencyIndicator { - background-color: transparent; - color: inherit; -} - .stack { display: flex; row-gap: 16px; diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 025cb3f777..b7074786b9 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -113,7 +113,6 @@ const DependencyIndicator: FC<{ return ( { onHover(commitIds); @@ -509,7 +508,7 @@ const ShowCommit: FC<{ {commitMessageBody !== "" && (

            {commitMessageBody}

            )} -
              +
                {data.changes.map((change) => (
              • {change.path}

                @@ -582,7 +581,11 @@ const getDefaultSelection = ({ changes: Array; assignments: Array; }): Selection | null => { - const firstUnassignedPath = firstSelectablePath({ changes, assignments, stackId: null }); + const firstUnassignedPath = firstSelectablePath({ + changes, + assignments, + stackId: null, + }); if (firstUnassignedPath !== null) return { _tag: "changes", stackId: null, path: firstUnassignedPath }; @@ -595,7 +598,11 @@ const getDefaultSelection = ({ stackId: stack.id, }); if (firstAssignedPath !== null) - return { _tag: "changes", stackId: stack.id, path: firstAssignedPath }; + return { + _tag: "changes", + stackId: stack.id, + path: firstAssignedPath, + }; for (const segment of stack.segments) { const firstCommit = segment.commits[0]; @@ -858,7 +865,7 @@ const Changes: FC<{ {changes.length === 0 ? ( <>No changes. ) : ( -
                  +
                    {changes.map((change) => { const assignments = assignmentsByPath.get(change.path); const hunkDependencyDiffs = hunkDependencyDiffsByPath.get(change.path); diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index f7603d48e9..96de38b8d5 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -56,20 +56,8 @@ padding-left: 8px; } -.commitsList { - padding-left: 0; - list-style: none; -} - .commitButton { flex-grow: 1; - background-color: transparent; - color: inherit; -} - -.fileList { - padding-left: 0; - list-style: none; } .fileRow { @@ -78,8 +66,6 @@ .fileButton { flex-grow: 1; - background-color: transparent; - color: inherit; } .selected { @@ -96,11 +82,6 @@ color: black; } -.hunks { - padding-left: 0; - list-style: none; -} - .hunkHeaderRow { display: flex; column-gap: 4px; @@ -128,14 +109,6 @@ field-sizing: content; box-sizing: content-box; min-height: calc(2lh); - border: none; - background-color: transparent; - color: inherit; -} - -.menuTrigger { - background-color: transparent; - color: inherit; } .menuPopup { diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index 0885899e3a..8b037fbb87 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -163,7 +163,7 @@ export const FileDiff: FC<{ if (visibleHunks.length === 0) return
                    No hunks.
                    ; return ( -
                      +
                        {visibleHunks.map((hunk) => (
                      • {renderHunk(hunk, patch)}
                      • ))} @@ -216,7 +216,7 @@ export const CommitDetails: FC<{ {conflictedPaths.length > 0 && (
                        Conflicts:
                        -
                          +
                            {conflictedPaths.map((path) => (
                          • {path}
                          • ))} @@ -225,7 +225,7 @@ export const CommitDetails: FC<{ )} {data.changes.length > 0 && ( -
                              +
                                {data.changes.map((file) => (
                              • {renderFile(file)}
                              • ))} @@ -440,9 +440,7 @@ export const CommitRow: FC< )} - - 𑁔 - + 𑁔 No commits.
                        ; return ( -
                          +
                            {commits.map((commit, index) => (
                          • {children(commit, index)}
                          • ))} From fbc0088d47fd717a1beeb4b72427a3ab044e535b Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:35:19 +0000 Subject: [PATCH 15/23] Use PascalCase --- apps/lite/ui/src/ChangeUnit.ts | 4 +- apps/lite/ui/src/routes/project-branches.tsx | 6 +-- apps/lite/ui/src/routes/project-index.tsx | 56 ++++++++++---------- apps/lite/ui/src/rub.ts | 28 +++++----- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/apps/lite/ui/src/ChangeUnit.ts b/apps/lite/ui/src/ChangeUnit.ts index be4587fd2b..e844287398 100644 --- a/apps/lite/ui/src/ChangeUnit.ts +++ b/apps/lite/ui/src/ChangeUnit.ts @@ -1,9 +1,9 @@ export type ChangeUnit = | { - _tag: "commit"; + _tag: "Commit"; commitId: string; } | { - _tag: "changes"; + _tag: "Changes"; stackId: string | null; }; diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index 01b29bfc0d..e03f794b18 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -180,7 +180,7 @@ const CommitFileDiff: FC<{ projectId={projectId} change={change} renderHunk={(hunk, patch) => ( - + )} /> ); @@ -207,7 +207,7 @@ const CommitDiff: FC<{ renderHunk={(hunk, patch) => ( @@ -243,7 +243,7 @@ const ShowBranch: FC<{ diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index b7074786b9..ef6d7f2f19 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -444,7 +444,7 @@ const ChangesFileDiff: FC<{ return ( ( - + )} /> ); @@ -518,7 +518,7 @@ const ShowCommit: FC<{ renderHunk={(hunk, patch) => ( @@ -533,12 +533,12 @@ const ShowCommit: FC<{ type Selection = | { - _tag: "changes"; + _tag: "Changes"; stackId: string | null; path: string; } | { - _tag: "commit"; + _tag: "Commit"; stackId: string; commitId: string; path?: string; @@ -549,8 +549,8 @@ const normalizeSelection = ( stackIdsByCommitId: Map>, ): Selection | null => Match.value(selection).pipe( - Match.tag("changes", (selection) => selection), - Match.tag("commit", (selection) => { + Match.tag("Changes", (selection) => selection), + Match.tag("Commit", (selection) => { const stackIds = stackIdsByCommitId.get(selection.commitId); if (stackIds === undefined) return null; if (!stackIds.has(selection.stackId)) return null; @@ -587,7 +587,7 @@ const getDefaultSelection = ({ stackId: null, }); if (firstUnassignedPath !== null) - return { _tag: "changes", stackId: null, path: firstUnassignedPath }; + return { _tag: "Changes", stackId: null, path: firstUnassignedPath }; for (const stack of headInfo.stacks) { if (stack.id == null) continue; @@ -599,14 +599,14 @@ const getDefaultSelection = ({ }); if (firstAssignedPath !== null) return { - _tag: "changes", + _tag: "Changes", stackId: stack.id, path: firstAssignedPath, }; for (const segment of stack.segments) { const firstCommit = segment.commits[0]; - if (firstCommit) return { _tag: "commit", stackId: stack.id, commitId: firstCommit.id }; + if (firstCommit) return { _tag: "Commit", stackId: stack.id, commitId: firstCommit.id }; } } @@ -619,7 +619,7 @@ const Preview: FC<{ onDependencyHover: (commitIds: Array | null) => void; }> = ({ projectId, selection, onDependencyHover }) => Match.value(selection).pipe( - Match.tag("changes", ({ stackId, path }) => ( + Match.tag("Changes", ({ stackId, path }) => ( )), - Match.tag("commit", ({ commitId, path }) => + Match.tag("Commit", ({ commitId, path }) => path !== undefined ? ( ) : ( @@ -774,7 +774,7 @@ const CommitC: FC<{ }) => { const expanded = isSelected || isAnyFileSelected; - const changeUnit: ChangeUnit = { _tag: "commit", commitId: commit.id }; + const changeUnit: ChangeUnit = { _tag: "Commit", commitId: commit.id }; return (
                            @@ -855,7 +855,7 @@ const Changes: FC<{ const changes = worktreeChanges.changes.filter((change) => assignmentsByPath.has(change.path)); - const changeUnit: ChangeUnit = { _tag: "changes", stackId }; + const changeUnit: ChangeUnit = { _tag: "Changes", stackId }; return ( @@ -1119,7 +1119,7 @@ const StackC: FC<{ {(commit, index) => { const changeUnit: ChangeUnit = { - _tag: "commit", + _tag: "Commit", commitId: commit.id, }; return ( @@ -1185,46 +1185,46 @@ const ProjectPage: FC = () => { const baseId = commonBaseCommitId(headInfo); const isUnassignedFileSelected = (path: string): boolean => - selection?._tag === "changes" && selection.stackId === null && selection.path === path; + selection?._tag === "Changes" && selection.stackId === null && selection.path === path; const toggleUnassignedFileSelection = (path: string) => { - select(isUnassignedFileSelected(path) ? null : { _tag: "changes", stackId: null, path }); + select(isUnassignedFileSelected(path) ? null : { _tag: "Changes", stackId: null, path }); }; const isCommitSelected = (stackId: string, commitId: string) => - selection?._tag === "commit" && + selection?._tag === "Commit" && selection.stackId === stackId && selection.commitId === commitId && selection.path === undefined; const isCommitAnyFileSelected = (stackId: string, commitId: string) => - selection?._tag === "commit" && + selection?._tag === "Commit" && selection.stackId === stackId && selection.commitId === commitId && selection.path !== undefined; const isChangeUnitFileSelected = (stackId: string, changeUnit: ChangeUnit, path: string) => { if (!selection) return false; - if (selection._tag === "commit" && changeUnit._tag === "commit") + if (selection._tag === "Commit" && changeUnit._tag === "Commit") return ( selection.stackId === stackId && selection.commitId === changeUnit.commitId && selection.path === path ); - if (selection._tag === "changes" && changeUnit._tag === "changes") + if (selection._tag === "Changes" && changeUnit._tag === "Changes") return selection.stackId === stackId && selection.path === path; return false; }; const toggleCommitSelection = (stackId: string, commitId: string) => { - select(isCommitSelected(stackId, commitId) ? null : { _tag: "commit", stackId, commitId }); + select(isCommitSelected(stackId, commitId) ? null : { _tag: "Commit", stackId, commitId }); }; const toggleChangeUnitFileSelection = (stackId: string, changeUnit: ChangeUnit, path: string) => { select( isChangeUnitFileSelected(stackId, changeUnit, path) - ? changeUnit._tag === "commit" - ? { _tag: "commit", stackId, commitId: changeUnit.commitId } + ? changeUnit._tag === "Commit" + ? { _tag: "Commit", stackId, commitId: changeUnit.commitId } : null - : changeUnit._tag === "commit" - ? { _tag: "commit", stackId, commitId: changeUnit.commitId, path } - : { _tag: "changes", stackId, path }, + : changeUnit._tag === "Commit" + ? { _tag: "Commit", stackId, commitId: changeUnit.commitId, path } + : { _tag: "Changes", stackId, path }, ); }; diff --git a/apps/lite/ui/src/rub.ts b/apps/lite/ui/src/rub.ts index 777c80aad5..4516c7d9cf 100644 --- a/apps/lite/ui/src/rub.ts +++ b/apps/lite/ui/src/rub.ts @@ -42,9 +42,9 @@ export const rub = async ({ projectId, source, target }: RubParams): Promise + Match.tag("Commit", (source) => Match.value(target).pipe( - Match.tag("commit", async (target): Promise => { + Match.tag("Commit", async (target): Promise => { const response = await window.lite.commitMoveChangesBetween({ projectId, sourceCommitId: source.commitId, @@ -53,7 +53,7 @@ export const rub = async ({ projectId, source, target }: RubParams): Promise => { + Match.tag("Changes", async (target): Promise => { const response = await window.lite.commitUncommitChanges({ projectId, commitId: source.commitId, @@ -67,9 +67,9 @@ export const rub = async ({ projectId, source, target }: RubParams): Promise + Match.tag("Changes", () => Match.value(target).pipe( - Match.tag("commit", async (target): Promise => { + Match.tag("Commit", async (target): Promise => { const response = await window.lite.commitAmend({ projectId, commitId: target.commitId, @@ -82,7 +82,7 @@ export const rub = async ({ projectId, source, target }: RubParams): Promise => { + Match.tag("Changes", async (target): Promise => { await window.lite.assignHunk({ projectId, assignments: source.hunkHeaders.map( @@ -119,22 +119,22 @@ export const rubOperationLabel = ( Match.tag("TreeChange", ({ source }) => Match.value(source.parent).pipe( Match.withReturnType(), - Match.tag("commit", (source) => + Match.tag("Commit", (source) => Match.value(target).pipe( Match.withReturnType(), - Match.tag("commit", (target) => { + Match.tag("Commit", (target) => { if (source.commitId === target.commitId) return null; return "Amend"; }), - Match.tag("changes", () => "Uncommit"), + Match.tag("Changes", () => "Uncommit"), Match.exhaustive, ), ), - Match.tag("changes", (source) => + Match.tag("Changes", (source) => Match.value(target).pipe( Match.withReturnType(), - Match.tag("commit", () => "Amend"), - Match.tag("changes", (target) => { + Match.tag("Commit", () => "Amend"), + Match.tag("Changes", (target) => { if (source.stackId === target.stackId) return null; return target.stackId === null ? "Unassign" : "Assign"; }), @@ -147,11 +147,11 @@ export const rubOperationLabel = ( Match.tag("Commit", ({ source }) => Match.value(target).pipe( Match.withReturnType(), - Match.tag("commit", (target) => { + Match.tag("Commit", (target) => { if (source.commitId === target.commitId) return null; return "Squash"; }), - Match.tag("changes", () => null), + Match.tag("Changes", () => null), Match.exhaustive, ), ), From f11fe437f0a58b413ab52734a9524cd06b243549 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:37:42 +0000 Subject: [PATCH 16/23] Rename --- apps/lite/ui/src/routes/project-index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index ef6d7f2f19..3c7d838cfe 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -533,7 +533,7 @@ const ShowCommit: FC<{ type Selection = | { - _tag: "Changes"; + _tag: "ChangesFile"; stackId: string | null; path: string; } @@ -549,7 +549,7 @@ const normalizeSelection = ( stackIdsByCommitId: Map>, ): Selection | null => Match.value(selection).pipe( - Match.tag("Changes", (selection) => selection), + Match.tag("ChangesFile", (selection) => selection), Match.tag("Commit", (selection) => { const stackIds = stackIdsByCommitId.get(selection.commitId); if (stackIds === undefined) return null; @@ -587,7 +587,7 @@ const getDefaultSelection = ({ stackId: null, }); if (firstUnassignedPath !== null) - return { _tag: "Changes", stackId: null, path: firstUnassignedPath }; + return { _tag: "ChangesFile", stackId: null, path: firstUnassignedPath }; for (const stack of headInfo.stacks) { if (stack.id == null) continue; @@ -599,7 +599,7 @@ const getDefaultSelection = ({ }); if (firstAssignedPath !== null) return { - _tag: "Changes", + _tag: "ChangesFile", stackId: stack.id, path: firstAssignedPath, }; @@ -619,7 +619,7 @@ const Preview: FC<{ onDependencyHover: (commitIds: Array | null) => void; }> = ({ projectId, selection, onDependencyHover }) => Match.value(selection).pipe( - Match.tag("Changes", ({ stackId, path }) => ( + Match.tag("ChangesFile", ({ stackId, path }) => ( { const baseId = commonBaseCommitId(headInfo); const isUnassignedFileSelected = (path: string): boolean => - selection?._tag === "Changes" && selection.stackId === null && selection.path === path; + selection?._tag === "ChangesFile" && selection.stackId === null && selection.path === path; const toggleUnassignedFileSelection = (path: string) => { - select(isUnassignedFileSelected(path) ? null : { _tag: "Changes", stackId: null, path }); + select(isUnassignedFileSelected(path) ? null : { _tag: "ChangesFile", stackId: null, path }); }; const isCommitSelected = (stackId: string, commitId: string) => @@ -1208,7 +1208,7 @@ const ProjectPage: FC = () => { selection.commitId === changeUnit.commitId && selection.path === path ); - if (selection._tag === "Changes" && changeUnit._tag === "Changes") + if (selection._tag === "ChangesFile" && changeUnit._tag === "Changes") return selection.stackId === stackId && selection.path === path; return false; }; @@ -1224,7 +1224,7 @@ const ProjectPage: FC = () => { : null : changeUnit._tag === "Commit" ? { _tag: "Commit", stackId, commitId: changeUnit.commitId, path } - : { _tag: "Changes", stackId, path }, + : { _tag: "ChangesFile", stackId, path }, ); }; From 3f40213139a6175c9246fd851d0b0ee467b20b00 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:41:40 +0000 Subject: [PATCH 17/23] Extract `CommitFile` --- apps/lite/ui/src/routes/project-index.tsx | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 3c7d838cfe..d4ada9fc79 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -541,7 +541,12 @@ type Selection = _tag: "Commit"; stackId: string; commitId: string; - path?: string; + } + | { + _tag: "CommitFile"; + stackId: string; + commitId: string; + path: string; }; const normalizeSelection = ( @@ -550,7 +555,7 @@ const normalizeSelection = ( ): Selection | null => Match.value(selection).pipe( Match.tag("ChangesFile", (selection) => selection), - Match.tag("Commit", (selection) => { + Match.tag("Commit", "CommitFile", (selection) => { const stackIds = stackIdsByCommitId.get(selection.commitId); if (stackIds === undefined) return null; if (!stackIds.has(selection.stackId)) return null; @@ -627,13 +632,10 @@ const Preview: FC<{ onDependencyHover={onDependencyHover} /> )), - Match.tag("Commit", ({ commitId, path }) => - path !== undefined ? ( - - ) : ( - - ), - ), + Match.tag("Commit", ({ commitId }) => ), + Match.tag("CommitFile", ({ commitId, path }) => ( + + )), Match.exhaustive, ); @@ -1193,16 +1195,14 @@ const ProjectPage: FC = () => { const isCommitSelected = (stackId: string, commitId: string) => selection?._tag === "Commit" && selection.stackId === stackId && - selection.commitId === commitId && - selection.path === undefined; + selection.commitId === commitId; const isCommitAnyFileSelected = (stackId: string, commitId: string) => - selection?._tag === "Commit" && + selection?._tag === "CommitFile" && selection.stackId === stackId && - selection.commitId === commitId && - selection.path !== undefined; + selection.commitId === commitId; const isChangeUnitFileSelected = (stackId: string, changeUnit: ChangeUnit, path: string) => { if (!selection) return false; - if (selection._tag === "Commit" && changeUnit._tag === "Commit") + if (selection._tag === "CommitFile" && changeUnit._tag === "Commit") return ( selection.stackId === stackId && selection.commitId === changeUnit.commitId && @@ -1223,7 +1223,7 @@ const ProjectPage: FC = () => { ? { _tag: "Commit", stackId, commitId: changeUnit.commitId } : null : changeUnit._tag === "Commit" - ? { _tag: "Commit", stackId, commitId: changeUnit.commitId, path } + ? { _tag: "CommitFile", stackId, commitId: changeUnit.commitId, path } : { _tag: "ChangesFile", stackId, path }, ); }; From 4d53c0dfafad8bb639deb94c06ba0b360e6997d4 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:41:40 +0000 Subject: [PATCH 18/23] Convert to tagged union --- apps/lite/ui/src/routes/project-branches.tsx | 110 +++++++++++-------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index e03f794b18..54f858b8a7 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -24,12 +24,24 @@ import { listBranchesQueryOptions, listProjectsQueryOptions, } from "#ui/queries.ts"; - -type Selection = { - branchName: BranchIdentity; - commitId?: string; - path?: string; -}; +import { Match } from "effect"; + +type Selection = + | { + _tag: "Branch"; + branchName: BranchIdentity; + } + | { + _tag: "Commit"; + branchName: BranchIdentity; + commitId: string; + } + | { + _tag: "CommitFile"; + branchName: BranchIdentity; + commitId: string; + path: string; + }; const normalizeSelectionForBranches = ( selection: Selection, @@ -43,18 +55,25 @@ const normalizeSelectionForBranches = ( const getDefaultSelection = (branches: Array): Selection | null => { const firstBranch = branches[0]; if (!firstBranch) return null; - return { branchName: firstBranch.name }; + return { _tag: "Branch", branchName: firstBranch.name }; }; const normalizeSelectionForBranchDetails = ( selection: Selection, branchDetails: BranchDetails, -): Selection | null => { - if (selection.commitId === undefined) return selection; - const commitIds = new Set(branchDetails.commits.map((commit) => commit.id)); - if (commitIds.has(selection.commitId)) return selection; - return { branchName: selection.branchName }; -}; +): Selection | null => + Match.value(selection).pipe( + Match.tag("Branch", (selection) => selection), + Match.tag("Commit", "CommitFile", (selection): Selection => { + const commitIds = new Set(branchDetails.commits.map((commit) => commit.id)); + if (commitIds.has(selection.commitId)) return selection; + return { + _tag: "Branch", + branchName: selection.branchName, + }; + }), + Match.exhaustive, + ); const getBranchRef = (branch: BranchListing): string | null => { if (branch.hasLocal) return `refs/heads/${branch.name}`; @@ -274,24 +293,20 @@ const Preview: FC<{ if (selection === null) return null; - if (selection.commitId !== undefined && selection.path !== undefined) - return ( - - ); - - if (selection.commitId !== undefined) - return ; - - if (selectedBranchRef !== null) - return ( - - ); - - return
                            No branch diff available.
                            ; + return Match.value(selection).pipe( + Match.tag("Branch", ({ branchName }) => + selectedBranchRef !== null ? ( + + ) : ( +
                            No branch diff available.
                            + ), + ), + Match.tag("Commit", ({ commitId }) => ), + Match.tag("CommitFile", ({ commitId, path }) => ( + + )), + Match.exhaustive, + ); }; const ProjectBranchesPage: FC = () => { @@ -316,31 +331,36 @@ const ProjectBranchesPage: FC = () => { selectedBranch && !selectedBranch.hasLocal ? selectedBranch.remotes[0] : null; const isBranchSelected = (branchName: string) => - selection?.branchName === branchName && selection.commitId === undefined; + selection?._tag === "Branch" && selection.branchName === branchName; const isBranchSelectedWithin = (branchName: string) => - selection?.branchName === branchName && selection.commitId !== undefined; + selection?._tag !== "Branch" && selection?.branchName === branchName; const isCommitSelected = (branchName: string, commitId: string) => - selection?.branchName === branchName && - selection.commitId === commitId && - selection.path === undefined; + selection?._tag === "Commit" && + selection.branchName === branchName && + selection.commitId === commitId; const isCommitAnyFileSelected = (branchName: string, commitId: string) => - selection?.branchName === branchName && - selection.commitId === commitId && - selection.path !== undefined; + selection?._tag === "CommitFile" && + selection.branchName === branchName && + selection.commitId === commitId; const isCommitFileSelected = (branchName: string, commitId: string, path: string) => - selection?.branchName === branchName && + selection?._tag === "CommitFile" && + selection.branchName === branchName && selection.commitId === commitId && selection.path === path; const toggleCommitSelection = (branchName: string, commitId: string) => { - select(isCommitSelected(branchName, commitId) ? { branchName } : { branchName, commitId }); + select( + isCommitSelected(branchName, commitId) + ? { _tag: "Branch", branchName } + : { _tag: "Commit", branchName, commitId }, + ); }; const toggleCommitFileSelection = (branchName: string, commitId: string, path: string) => { select( isCommitFileSelected(branchName, commitId, path) - ? { branchName, commitId } - : { branchName, commitId, path }, + ? { _tag: "Commit", branchName, commitId } + : { _tag: "CommitFile", branchName, commitId, path }, ); }; @@ -386,7 +406,9 @@ const ProjectBranchesPage: FC = () => { )} onClick={() => { select((selected) => - selected?.branchName === branch.name ? null : { branchName: branch.name }, + selected?.branchName === branch.name + ? null + : { _tag: "Branch", branchName: branch.name }, ); }} > From 9163651aabd61d723c24648ee9195ef3b81089a9 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:29:23 +0000 Subject: [PATCH 19/23] Implement new selection logic --- apps/lite/ui/src/routes/project-branches.tsx | 111 ++++++++++++------- apps/lite/ui/src/routes/project-index.tsx | 31 +++++- apps/lite/ui/src/routes/project-shared.tsx | 25 ++++- 3 files changed, 119 insertions(+), 48 deletions(-) diff --git a/apps/lite/ui/src/routes/project-branches.tsx b/apps/lite/ui/src/routes/project-branches.tsx index 54f858b8a7..2c913f215a 100644 --- a/apps/lite/ui/src/routes/project-branches.tsx +++ b/apps/lite/ui/src/routes/project-branches.tsx @@ -1,5 +1,5 @@ import useLocalStorageState from "use-local-storage-state"; -import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; +import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { createRoute } from "@tanstack/react-router"; import { FC, Suspense } from "react"; import { @@ -88,6 +88,7 @@ const CommitC: FC<{ isSelected: boolean; isAnyFileSelected: boolean; isFileSelected: (path: string) => boolean; + toggleExpand: () => Promise | void; toggleSelect: () => void; toggleFileSelect: (path: string) => void; }> = ({ @@ -96,44 +97,42 @@ const CommitC: FC<{ isSelected, isAnyFileSelected, isFileSelected, + toggleExpand, toggleSelect, toggleFileSelect, -}) => { - const expanded = isSelected || isAnyFileSelected; - - return ( -
                            - - {expanded && ( -
                            - Loading changed details…
                            }> - ( -
                            - toggleFileSelect(change.path)} /> -
                            - )} - /> - -
                            - )} -
                            - ); -}; +}) => ( +
                            + + {isAnyFileSelected && ( +
                            + Loading changed details…
                            }> + ( +
                            + toggleFileSelect(change.path)} /> +
                            + )} + /> + +
                            + )} + +); const BranchDetailsC: FC<{ projectId: string; @@ -142,6 +141,7 @@ const BranchDetailsC: FC<{ isCommitSelected: (commitId: string) => boolean; isCommitAnyFileSelected: (commitId: string) => boolean; isCommitFileSelected: (commitId: string, path: string) => boolean; + toggleCommitExpanded: (commitId: string) => Promise | void; toggleCommitSelection: (commitId: string) => void; toggleCommitFileSelection: (commitId: string, path: string) => void; }> = ({ @@ -151,6 +151,7 @@ const BranchDetailsC: FC<{ isCommitSelected, isCommitAnyFileSelected, isCommitFileSelected, + toggleCommitExpanded, toggleCommitSelection, toggleCommitFileSelection, }) => { @@ -169,6 +170,7 @@ const BranchDetailsC: FC<{ isSelected={isCommitSelected(commit.id)} isAnyFileSelected={isCommitAnyFileSelected(commit.id)} isFileSelected={(path) => isCommitFileSelected(commit.id, path)} + toggleExpand={() => toggleCommitExpanded(commit.id)} toggleSelect={() => { toggleCommitSelection(commit.id); }} @@ -315,6 +317,7 @@ const ProjectBranchesPage: FC = () => { const { data: projects } = useSuspenseQuery(listProjectsQueryOptions()); const project = projects.find((project) => project.id === projectId); const { data: branches } = useSuspenseQuery(listBranchesQueryOptions(projectId)); + const queryClient = useQueryClient(); const applyBranch = useMutation(applyBranchMutationOptions); const unapplyStack = useMutation(unapplyStackMutationOptions); @@ -333,7 +336,8 @@ const ProjectBranchesPage: FC = () => { const isBranchSelected = (branchName: string) => selection?._tag === "Branch" && selection.branchName === branchName; const isBranchSelectedWithin = (branchName: string) => - selection?._tag !== "Branch" && selection?.branchName === branchName; + (selection?._tag === "Commit" || selection?._tag === "CommitFile") && + selection.branchName === branchName; const isCommitSelected = (branchName: string, commitId: string) => selection?._tag === "Commit" && @@ -356,6 +360,23 @@ const ProjectBranchesPage: FC = () => { : { _tag: "Commit", branchName, commitId }, ); }; + const toggleCommitExpanded = async (branchName: string, commitId: string) => { + if (isCommitAnyFileSelected(branchName, commitId)) { + select({ _tag: "Commit", branchName, commitId }); + return; + } + + const commitDetails = await queryClient.ensureQueryData( + commitDetailsWithLineStatsQueryOptions({ projectId, commitId }), + ); + const firstPath = commitDetails.changes[0]?.path; + + select( + firstPath !== undefined + ? { _tag: "CommitFile", branchName, commitId, path: firstPath } + : { _tag: "Commit", branchName, commitId }, + ); + }; const toggleCommitFileSelection = (branchName: string, commitId: string, path: string) => { select( isCommitFileSelected(branchName, commitId, path) @@ -363,6 +384,11 @@ const ProjectBranchesPage: FC = () => { : { _tag: "CommitFile", branchName, commitId, path }, ); }; + const toggleBranchSelection = (branchName: string) => { + select((selected) => + selected?.branchName === branchName ? null : { _tag: "Branch", branchName }, + ); + }; // TODO: dedupe if (!project) return

                            Project not found.

                            ; @@ -405,11 +431,7 @@ const ProjectBranchesPage: FC = () => { : undefined, )} onClick={() => { - select((selected) => - selected?.branchName === branch.name - ? null - : { _tag: "Branch", branchName: branch.name }, - ); + toggleBranchSelection(branch.name); }} > {branch.name} @@ -466,6 +488,9 @@ const ProjectBranchesPage: FC = () => { isCommitFileSelected={(commitId, path) => isCommitFileSelected(selectedBranch.name, commitId, path) } + toggleCommitExpanded={(commitId) => + toggleCommitExpanded(selectedBranch.name, commitId) + } toggleCommitSelection={(commitId) => toggleCommitSelection(selectedBranch.name, commitId) } diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index d4ada9fc79..4eb248d1d6 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -24,7 +24,7 @@ import { HunkHeader, } from "@gitbutler/but-sdk"; import { Array, Match } from "effect"; -import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; +import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { createContext, FC, Suspense, useContext, useEffect, useState } from "react"; import styles from "./project-index.module.css"; import sharedStyles from "./project-shared.module.css"; @@ -760,6 +760,7 @@ const CommitC: FC<{ isSelected: boolean; isAnyFileSelected: boolean; isFileSelected: (path: string) => boolean; + toggleExpand: () => Promise | void; toggleSelect: () => void; toggleFileSelect: (path: string) => void; }> = ({ @@ -771,11 +772,10 @@ const CommitC: FC<{ isSelected, isAnyFileSelected, isFileSelected, + toggleExpand, toggleSelect, toggleFileSelect, }) => { - const expanded = isSelected || isAnyFileSelected; - const changeUnit: ChangeUnit = { _tag: "Commit", commitId: commit.id }; return ( @@ -795,11 +795,12 @@ const CommitC: FC<{ isSelected={isSelected} isAnyFileSelected={isAnyFileSelected} isHighlighted={isHighlighted} + toggleExpand={toggleExpand} toggleSelect={toggleSelect} /> } /> - {expanded && ( + {isAnyFileSelected && (
                            Loading changed details…
                            }> boolean; isCommitAnyFileSelected: (commitId: string) => boolean; isChangeUnitFileSelected: (changeUnit: ChangeUnit, path: string) => boolean; + toggleCommitExpanded: (commitId: string) => Promise | void; toggleCommitSelection: (commitId: string) => void; toggleChangeUnitFileSelection: (changeUnit: ChangeUnit, path: string) => void; highlightedCommitIds: Set; @@ -1061,6 +1063,7 @@ const StackC: FC<{ isCommitSelected, isCommitAnyFileSelected, isChangeUnitFileSelected, + toggleCommitExpanded, toggleCommitSelection, toggleChangeUnitFileSelection, highlightedCommitIds, @@ -1134,6 +1137,7 @@ const StackC: FC<{ isSelected={isCommitSelected(commit.id)} isAnyFileSelected={isCommitAnyFileSelected(commit.id)} isFileSelected={(path) => isChangeUnitFileSelected(changeUnit, path)} + toggleExpand={() => toggleCommitExpanded(commit.id)} toggleSelect={() => { toggleCommitSelection(commit.id); }} @@ -1165,6 +1169,7 @@ const ProjectPage: FC = () => { // TODO: handle project not found error. or only run when project is not null? waterfall. const { data: headInfo } = useSuspenseQuery(headInfoQueryOptions(projectId)); const { data: worktreeChanges } = useSuspenseQuery(changesInWorktreeQueryOptions(projectId)); + const queryClient = useQueryClient(); const [_selection, select] = useLocalStorageState( `project:${projectId}:workspace:selection`, @@ -1216,6 +1221,23 @@ const ProjectPage: FC = () => { const toggleCommitSelection = (stackId: string, commitId: string) => { select(isCommitSelected(stackId, commitId) ? null : { _tag: "Commit", stackId, commitId }); }; + const toggleCommitExpanded = async (stackId: string, commitId: string) => { + if (isCommitAnyFileSelected(stackId, commitId)) { + select({ _tag: "Commit", stackId, commitId }); + return; + } + + const commitDetails = await queryClient.ensureQueryData( + commitDetailsWithLineStatsQueryOptions({ projectId, commitId }), + ); + const firstPath = commitDetails.changes[0]?.path; + + select( + firstPath !== undefined + ? { _tag: "CommitFile", stackId, commitId, path: firstPath } + : { _tag: "Commit", stackId, commitId }, + ); + }; const toggleChangeUnitFileSelection = (stackId: string, changeUnit: ChangeUnit, path: string) => { select( isChangeUnitFileSelected(stackId, changeUnit, path) @@ -1279,6 +1301,7 @@ const ProjectPage: FC = () => { isChangeUnitFileSelected={(changeUnit, path) => isChangeUnitFileSelected(stackId, changeUnit, path) } + toggleCommitExpanded={(commitId) => toggleCommitExpanded(stackId, commitId)} toggleCommitSelection={(commitId) => { toggleCommitSelection(stackId, commitId); }} diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index 8b037fbb87..20699e4aed 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -9,7 +9,15 @@ import { } from "@gitbutler/but-sdk"; import { Match } from "effect"; import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; -import { ComponentProps, FC, ReactNode, startTransition, useOptimistic, useState } from "react"; +import { + ComponentProps, + FC, + ReactNode, + startTransition, + useOptimistic, + useState, + useTransition, +} from "react"; import styles from "./project-shared.module.css"; import { commitDetailsWithLineStatsQueryOptions, @@ -363,6 +371,7 @@ export const CommitRow: FC< isSelected: boolean; isAnyFileSelected: boolean; isHighlighted: boolean; + toggleExpand: () => Promise | void; toggleSelect: () => void; } & ComponentProps<"div"> > = ({ @@ -371,12 +380,14 @@ export const CommitRow: FC< isSelected, isAnyFileSelected, isHighlighted, + toggleExpand, toggleSelect, className, ...restProps }) => { const commitInsertBlank = useMutation(commitInsertBlankMutationOptions); const [isEditingMessage, setIsEditingMessage] = useState(false); + const [isExpandPending, startExpandTransition] = useTransition(); const [optimisticMessage, setOptimisticMessage] = useOptimistic( commit.message, (_currentMessage, nextMessage: string) => nextMessage, @@ -408,6 +419,8 @@ export const CommitRow: FC< isHighlighted && styles.highlighted, className, )} + style={{ ...(isExpandPending && { opacity: 0.5 }) }} + aria-busy={isExpandPending} > {isEditingMessage ? ( )} + 𑁔 From 6af31b6484f5e110ebdb61bed6fe5691f0c67097 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 00:22:43 +0000 Subject: [PATCH 20/23] Add the ability to select branches in workspace view --- .../ui/src/routes/project-index.module.css | 4 + apps/lite/ui/src/routes/project-index.tsx | 117 +++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/routes/project-index.module.css b/apps/lite/ui/src/routes/project-index.module.css index 33be2a09df..1f1ec4d8ef 100644 --- a/apps/lite/ui/src/routes/project-index.module.css +++ b/apps/lite/ui/src/routes/project-index.module.css @@ -26,6 +26,10 @@ flex-direction: column; } +.branchButton { + width: 100%; +} + .commitMoveTarget { --hit-area: 17px; --indicator-height: 3px; diff --git a/apps/lite/ui/src/routes/project-index.tsx b/apps/lite/ui/src/routes/project-index.tsx index 4eb248d1d6..d6e021f116 100644 --- a/apps/lite/ui/src/routes/project-index.tsx +++ b/apps/lite/ui/src/routes/project-index.tsx @@ -50,6 +50,7 @@ import { unapplyStackMutationOptions, } from "#ui/mutations.ts"; import { + branchDiffQueryOptions, changesInWorktreeQueryOptions, commitDetailsWithLineStatsQueryOptions, headInfoQueryOptions, @@ -96,6 +97,24 @@ const getStackIdsByCommitId = (headInfo: RefInfo): Map> => { return byCommitId; }; +const getBranchRefsByStackId = (headInfo: RefInfo): Map> => { + const refsByStackId = new Map>(); + + for (const stack of headInfo.stacks) { + if (stack.id == null) continue; + + const branchRefs = new Set(); + for (const segment of stack.segments) { + const branchRef = getSegmentBranchRef(segment); + if (branchRef !== null) branchRefs.add(branchRef); + } + + refsByStackId.set(stack.id, branchRefs); + } + + return refsByStackId; +}; + const DependencyIndicator: FC<{ projectId: string; commitIds: NonEmptyArray; @@ -292,6 +311,9 @@ const stackRelativeTo = (stack: Stack): RelativeTo | null => { return { type: "commit", subject: firstCommit.id }; }; +const getSegmentBranchRef = (segment: Stack["segments"][number]): string | null => + segment.refName ? `refs/heads/${segment.refName.displayName}` : null; + // TODO: check this const assignedChangesDiffSpecs = ( changes: Array, @@ -486,6 +508,43 @@ const CommitFileDiff: FC<{ ); }; +const ShowBranch: FC<{ + projectId: string; + branch: string; + branchName: string; +}> = ({ projectId, branch, branchName }) => { + const { data } = useSuspenseQuery(branchDiffQueryOptions({ projectId, branch })); + + return ( + <> +

                            {branchName}

                            + {data.changes.length === 0 ? ( +
                            No file changes.
                            + ) : ( +
                              + {data.changes.map((change) => ( +
                            • +

                              {change.path}

                              + ( + + )} + /> +
                            • + ))} +
                            + )} + + ); +}; + const ShowCommit: FC<{ projectId: string; commitId: string; @@ -532,6 +591,12 @@ const ShowCommit: FC<{ }; type Selection = + | { + _tag: "Branch"; + stackId: string; + branchName: string; + branchRef: string; + } | { _tag: "ChangesFile"; stackId: string | null; @@ -552,8 +617,14 @@ type Selection = const normalizeSelection = ( selection: Selection, stackIdsByCommitId: Map>, + branchRefsByStackId: Map>, ): Selection | null => Match.value(selection).pipe( + Match.tag("Branch", (selection) => { + const branchRefs = branchRefsByStackId.get(selection.stackId); + if (branchRefs === undefined) return null; + return branchRefs.has(selection.branchRef) ? selection : null; + }), Match.tag("ChangesFile", (selection) => selection), Match.tag("Commit", "CommitFile", (selection) => { const stackIds = stackIdsByCommitId.get(selection.commitId); @@ -624,6 +695,9 @@ const Preview: FC<{ onDependencyHover: (commitIds: Array | null) => void; }> = ({ projectId, selection, onDependencyHover }) => Match.value(selection).pipe( + Match.tag("Branch", ({ branchName, branchRef }) => ( + + )), Match.tag("ChangesFile", ({ stackId, path }) => ( boolean; + toggleBranchSelection: (stackId: string, branchName: string, branchRef: string) => void; isCommitSelected: (commitId: string) => boolean; isCommitAnyFileSelected: (commitId: string) => boolean; isChangeUnitFileSelected: (changeUnit: ChangeUnit, path: string) => boolean; @@ -1060,6 +1136,8 @@ const StackC: FC<{ }> = ({ projectId, stack, + isBranchSelected, + toggleBranchSelection, isCommitSelected, isCommitAnyFileSelected, isChangeUnitFileSelected, @@ -1112,13 +1190,33 @@ const StackC: FC<{
                              {stack.segments.map((segment) => { const branchName = segment.refName?.displayName ?? "Untitled"; + const branchRef = getSegmentBranchRef(segment); const anchorRef = segment.refName ? segment.refName.fullNameBytes : null; return (
                            • {branchName}} + render={ +

                              + {branchRef !== null ? ( + + ) : ( + branchName + )} +

                              + } /> @@ -1176,8 +1274,9 @@ const ProjectPage: FC = () => { { defaultValue: null }, ); const commitStackIds = getStackIdsByCommitId(headInfo); + const branchRefsByStackId = getBranchRefsByStackId(headInfo); const selection = - (_selection ? normalizeSelection(_selection, commitStackIds) : null) ?? + (_selection ? normalizeSelection(_selection, commitStackIds, branchRefsByStackId) : null) ?? getDefaultSelection({ headInfo, changes: worktreeChanges.changes, @@ -1197,6 +1296,18 @@ const ProjectPage: FC = () => { select(isUnassignedFileSelected(path) ? null : { _tag: "ChangesFile", stackId: null, path }); }; + const isBranchSelected = (stackId: string, branchRef: string) => + selection?._tag === "Branch" && + selection.stackId === stackId && + selection.branchRef === branchRef; + const toggleBranchSelection = (stackId: string, branchName: string, branchRef: string) => { + select( + isBranchSelected(stackId, branchRef) + ? null + : { _tag: "Branch", stackId, branchName, branchRef }, + ); + }; + const isCommitSelected = (stackId: string, commitId: string) => selection?._tag === "Commit" && selection.stackId === stackId && @@ -1294,6 +1405,8 @@ const ProjectPage: FC = () => { key={stack.id} projectId={project.id} stack={stack} + isBranchSelected={isBranchSelected} + toggleBranchSelection={toggleBranchSelection} isCommitSelected={(commitId) => isCommitSelected(stackId, commitId)} isCommitAnyFileSelected={(commitId) => isCommitAnyFileSelected(stackId, commitId) From ed1bdf9e2dd9f427afda6c37d98c75b163ff17ea Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 02:26:22 +0000 Subject: [PATCH 21/23] Fix file button overflow --- apps/lite/ui/src/routes/project-shared.module.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index 96de38b8d5..3a9919332d 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -66,6 +66,9 @@ .fileButton { flex-grow: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .selected { From 367a4ee5dcaa8963270cb3f73f65fa212a189356 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 07:52:28 +0000 Subject: [PATCH 22/23] Select commit on edit --- apps/lite/ui/src/routes/project-shared.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index 20699e4aed..d499e8b461 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -406,6 +406,11 @@ export const CommitRow: FC< }); }; + const startEditingMessage = () => { + if (!isSelected) toggleSelect(); + setIsEditingMessage(true); + }; + return ( setIsEditingMessage(true)} + onReword={startEditingMessage} onInsertBlank={insertBlankCommit} parts={ContextMenu} /> @@ -467,7 +472,7 @@ export const CommitRow: FC< setIsEditingMessage(true)} + onReword={startEditingMessage} onInsertBlank={insertBlankCommit} parts={Menu} /> From 5037b3d6c92276c916ee0e20b023b36d9cd90993 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Thu, 19 Mar 2026 14:51:35 +0000 Subject: [PATCH 23/23] New styles --- apps/lite/ui/src/routes/ProjectPanelLayout.tsx | 3 ++- apps/lite/ui/src/routes/project-index.module.css | 2 ++ apps/lite/ui/src/routes/project-index.tsx | 2 +- .../lite/ui/src/routes/project-shared.module.css | 16 ++++++++++++++++ apps/lite/ui/src/routes/project-shared.tsx | 5 ++++- apps/lite/ui/src/routes/root.tsx | 4 +++- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/lite/ui/src/routes/ProjectPanelLayout.tsx b/apps/lite/ui/src/routes/ProjectPanelLayout.tsx index 7459af368a..d6d10aab91 100644 --- a/apps/lite/ui/src/routes/ProjectPanelLayout.tsx +++ b/apps/lite/ui/src/routes/ProjectPanelLayout.tsx @@ -72,6 +72,7 @@ export const ProjectPanelLayout: FC<{
                              diff --git a/apps/lite/ui/src/routes/project-shared.module.css b/apps/lite/ui/src/routes/project-shared.module.css index 3a9919332d..1d17cce8d6 100644 --- a/apps/lite/ui/src/routes/project-shared.module.css +++ b/apps/lite/ui/src/routes/project-shared.module.css @@ -1,3 +1,8 @@ +.button { + padding: 2px 4px; + background-color: #eee; +} + .lanes { display: flex; column-gap: 8px; @@ -58,6 +63,15 @@ .commitButton { flex-grow: 1; + padding: 2px 4px; +} + +.commitToggleExpandButton { + padding: 2px 4px; +} + +.commitMenuTrigger { + padding: 2px 4px; } .fileRow { @@ -66,6 +80,7 @@ .fileButton { flex-grow: 1; + padding: 2px 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -109,6 +124,7 @@ .editCommitMessageInput { flex-grow: 1; + padding: 2px 4px; field-sizing: content; box-sizing: content-box; min-height: calc(2lh); diff --git a/apps/lite/ui/src/routes/project-shared.tsx b/apps/lite/ui/src/routes/project-shared.tsx index d499e8b461..743bd3e4fb 100644 --- a/apps/lite/ui/src/routes/project-shared.tsx +++ b/apps/lite/ui/src/routes/project-shared.tsx @@ -458,6 +458,7 @@ export const CommitRow: FC< )} - 𑁔 + + 𑁔 + { {projectMatch && (