chore: cleanup
This commit is contained in:
@@ -22,6 +22,7 @@ export default function FileTree(props: {
|
||||
nodeClass?: string
|
||||
level?: number
|
||||
allowed?: readonly string[]
|
||||
modified?: readonly string[]
|
||||
draggable?: boolean
|
||||
tooltip?: boolean
|
||||
onFileClick?: (file: FileNode) => void
|
||||
@@ -50,6 +51,12 @@ export default function FileTree(props: {
|
||||
return { files, dirs }
|
||||
})
|
||||
|
||||
const marks = createMemo(() => {
|
||||
const modified = props.modified
|
||||
if (!modified || modified.length === 0) return
|
||||
return new Set(modified)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const current = filter()
|
||||
if (!current) return
|
||||
@@ -89,7 +96,7 @@ export default function FileTree(props: {
|
||||
<Dynamic
|
||||
component={local.as ?? "div"}
|
||||
classList={{
|
||||
"w-full flex items-center gap-x-2 rounded-md px-2 py-1 hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true,
|
||||
"w-full min-w-0 flex items-center gap-x-2 rounded-md px-2 py-1 hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer": true,
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
[props.nodeClass ?? ""]: !!props.nodeClass,
|
||||
@@ -125,13 +132,16 @@ export default function FileTree(props: {
|
||||
{local.children}
|
||||
<span
|
||||
classList={{
|
||||
"text-12-regular whitespace-nowrap truncate": true,
|
||||
"flex-1 min-w-0 text-12-regular whitespace-nowrap truncate": true,
|
||||
"text-text-weaker": local.node.ignored,
|
||||
"text-text-weak": !local.node.ignored,
|
||||
}}
|
||||
>
|
||||
{local.node.name}
|
||||
</span>
|
||||
{local.node.type === "file" && marks()?.has(local.node.path) ? (
|
||||
<div class="shrink-0 size-1.5 rounded-full bg-surface-warning-strong" />
|
||||
) : null}
|
||||
</Dynamic>
|
||||
)
|
||||
}
|
||||
@@ -173,6 +183,7 @@ export default function FileTree(props: {
|
||||
path={node.path}
|
||||
level={level + 1}
|
||||
allowed={props.allowed}
|
||||
modified={props.modified}
|
||||
draggable={props.draggable}
|
||||
tooltip={props.tooltip}
|
||||
onFileClick={props.onFileClick}
|
||||
|
||||
@@ -425,6 +425,8 @@ export default function Page() {
|
||||
}
|
||||
|
||||
const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : []))
|
||||
const emptyDiffFiles: string[] = []
|
||||
const diffFiles = createMemo(() => diffs().map((d) => d.file), emptyDiffFiles, { equals: same })
|
||||
const diffsReady = createMemo(() => {
|
||||
const id = params.id
|
||||
if (!id) return true
|
||||
@@ -1934,47 +1936,9 @@ export default function Page() {
|
||||
class="relative flex-1 min-w-0 h-full border-l border-border-weak-base flex"
|
||||
>
|
||||
<div class="flex-1 min-w-0 h-full">
|
||||
<Show when={layout.fileTree.opened() && fileTreeTab() === "changes"}>
|
||||
<div class="flex flex-col h-full overflow-hidden bg-background-stronger contain-strict">
|
||||
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
||||
<Switch>
|
||||
<Match when={hasReview()}>
|
||||
<Show
|
||||
when={diffsReady()}
|
||||
when={layout.fileTree.opened() && fileTreeTab() === "changes"}
|
||||
fallback={
|
||||
<div class="px-6 py-4 text-text-weak">{language.t("session.review.loadingChanges")}</div>
|
||||
}
|
||||
>
|
||||
<SessionReviewTab
|
||||
diffs={diffs}
|
||||
view={view}
|
||||
diffStyle={layout.review.diffStyle()}
|
||||
onDiffStyleChange={layout.review.setDiffStyle}
|
||||
onScrollRef={setReviewScroll}
|
||||
onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
|
||||
comments={comments.all()}
|
||||
focusedComment={comments.focus()}
|
||||
onFocusedCommentChange={comments.setFocus}
|
||||
onViewFile={(path) => {
|
||||
const value = file.tab(path)
|
||||
tabs().open(value)
|
||||
file.load(path)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
|
||||
<Mark class="w-14 opacity-10" />
|
||||
<div class="text-13-regular text-text-weak max-w-56">No changes in this session yet</div>
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={!layout.fileTree.opened() || fileTreeTab() === "all"}>
|
||||
<DragDropProvider
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
@@ -2026,9 +1990,11 @@ export default function Page() {
|
||||
</Tabs.Trigger>
|
||||
</Show>
|
||||
<SortableProvider ids={openedTabs()}>
|
||||
<For each={openedTabs()}>{(tab) => <SortableTab tab={tab} onTabClose={tabs().close} />}</For>
|
||||
<For each={openedTabs()}>
|
||||
{(tab) => <SortableTab tab={tab} onTabClose={tabs().close} />}
|
||||
</For>
|
||||
</SortableProvider>
|
||||
<div class="bg-background-base h-full flex items-center justify-center border-b border-border-weak-base px-3">
|
||||
<div class="bg-background-base h-full shrink-0 sticky right-0 z-10 flex items-center justify-center border-b border-l border-border-weak-base px-3">
|
||||
<TooltipKeybind
|
||||
title={language.t("command.file.open")}
|
||||
keybind={command.keybind("file.open")}
|
||||
@@ -2114,13 +2080,13 @@ export default function Page() {
|
||||
</Show>
|
||||
</Tabs.Content>
|
||||
</Show>
|
||||
|
||||
<For each={openedTabs()}>
|
||||
{(tab) => {
|
||||
let scroll: HTMLDivElement | undefined
|
||||
let scrollFrame: number | undefined
|
||||
let pending: { x: number; y: number } | undefined
|
||||
let codeScroll: HTMLElement[] = []
|
||||
let focusToken = 0
|
||||
|
||||
const path = createMemo(() => file.pathFromTab(tab))
|
||||
const state = createMemo(() => {
|
||||
@@ -2184,8 +2150,6 @@ export default function Page() {
|
||||
const [positions, setPositions] = createSignal<Record<string, number>>({})
|
||||
const [draftTop, setDraftTop] = createSignal<number | undefined>(undefined)
|
||||
|
||||
const empty = {} as Record<string, number>
|
||||
|
||||
const commentLabel = (range: SelectedLineRange) => {
|
||||
const start = Math.min(range.start, range.end)
|
||||
const end = Math.max(range.start, range.end)
|
||||
@@ -2219,22 +2183,12 @@ export default function Page() {
|
||||
return rect.top - wrapperRect.top + Math.max(0, (rect.height - 20) / 2)
|
||||
}
|
||||
|
||||
const equal = (a: Record<string, number>, b: Record<string, number>) => {
|
||||
const aKeys = Object.keys(a)
|
||||
const bKeys = Object.keys(b)
|
||||
if (aKeys.length !== bKeys.length) return false
|
||||
for (const key of aKeys) {
|
||||
if (a[key] !== b[key]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const updateComments = () => {
|
||||
const el = wrap
|
||||
const root = getRoot()
|
||||
if (!el || !root) {
|
||||
setPositions((prev) => (Object.keys(prev).length === 0 ? prev : empty))
|
||||
setDraftTop((prev) => (prev === undefined ? prev : undefined))
|
||||
setPositions({})
|
||||
setDraftTop(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2245,7 +2199,7 @@ export default function Page() {
|
||||
next[comment.id] = markerTop(el, marker)
|
||||
}
|
||||
|
||||
setPositions((prev) => (equal(prev, next) ? prev : next))
|
||||
setPositions(next)
|
||||
|
||||
const range = commenting()
|
||||
if (!range) {
|
||||
@@ -2259,18 +2213,11 @@ export default function Page() {
|
||||
return
|
||||
}
|
||||
|
||||
const nextTop = markerTop(el, marker)
|
||||
setDraftTop((prev) => (prev === nextTop ? prev : nextTop))
|
||||
setDraftTop(markerTop(el, marker))
|
||||
}
|
||||
|
||||
let commentFrame: number | undefined
|
||||
|
||||
const scheduleComments = () => {
|
||||
if (commentFrame !== undefined) return
|
||||
commentFrame = requestAnimationFrame(() => {
|
||||
commentFrame = undefined
|
||||
updateComments()
|
||||
})
|
||||
requestAnimationFrame(updateComments)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
@@ -2278,13 +2225,9 @@ export default function Page() {
|
||||
scheduleComments()
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
commenting()
|
||||
scheduleComments()
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const range = commenting()
|
||||
scheduleComments()
|
||||
if (!range) return
|
||||
setDraft("")
|
||||
})
|
||||
@@ -2299,50 +2242,9 @@ export default function Page() {
|
||||
const target = fileComments().find((comment) => comment.id === focus.id)
|
||||
if (!target) return
|
||||
|
||||
focusToken++
|
||||
const token = focusToken
|
||||
|
||||
setOpenedComment(target.id)
|
||||
setCommenting(null)
|
||||
file.setSelectedLines(p, target.selection)
|
||||
|
||||
const scrollTo = (attempt: number) => {
|
||||
if (token !== focusToken) return
|
||||
|
||||
const root = scroll
|
||||
if (!root) {
|
||||
if (attempt >= 120) return
|
||||
requestAnimationFrame(() => scrollTo(attempt + 1))
|
||||
return
|
||||
}
|
||||
|
||||
const anchor = root.querySelector(`[data-comment-id="${target.id}"]`)
|
||||
const ready =
|
||||
anchor instanceof HTMLElement &&
|
||||
anchor.style.pointerEvents !== "none" &&
|
||||
anchor.style.opacity !== "0"
|
||||
|
||||
const shadow = getRoot()
|
||||
const marker = shadow ? findMarker(shadow, target.selection) : undefined
|
||||
const node = (ready ? anchor : (marker ?? wrap)) as HTMLElement | undefined
|
||||
if (!node) {
|
||||
if (attempt >= 120) return
|
||||
requestAnimationFrame(() => scrollTo(attempt + 1))
|
||||
return
|
||||
}
|
||||
|
||||
const rootRect = root.getBoundingClientRect()
|
||||
const targetRect = node.getBoundingClientRect()
|
||||
const offset = targetRect.top - rootRect.top
|
||||
const next = root.scrollTop + offset - rootRect.height / 2 + targetRect.height / 2
|
||||
root.scrollTop = Math.max(0, next)
|
||||
|
||||
if (ready || marker) return
|
||||
if (attempt >= 120) return
|
||||
requestAnimationFrame(() => scrollTo(attempt + 1))
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => scrollTo(0))
|
||||
requestAnimationFrame(() => comments.clearFocus())
|
||||
})
|
||||
|
||||
@@ -2392,6 +2294,8 @@ export default function Page() {
|
||||
id={comment.id}
|
||||
top={positions()[comment.id]}
|
||||
open={openedComment() === comment.id}
|
||||
comment={comment.comment}
|
||||
selection={commentLabel(comment.selection)}
|
||||
onMouseEnter={() => {
|
||||
const p = path()
|
||||
if (!p) return
|
||||
@@ -2404,8 +2308,6 @@ export default function Page() {
|
||||
setOpenedComment((current) => (current === comment.id ? null : comment.id))
|
||||
file.setSelectedLines(p, comment.selection)
|
||||
}}
|
||||
comment={comment.comment}
|
||||
selection={commentLabel(comment.selection)}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
@@ -2416,28 +2318,26 @@ export default function Page() {
|
||||
top={draftTop()}
|
||||
value={draft()}
|
||||
selection={commentLabel(range())}
|
||||
onInput={setDraft}
|
||||
onInput={(value) => setDraft(value)}
|
||||
onCancel={() => setCommenting(null)}
|
||||
onSubmit={(comment) => {
|
||||
onSubmit={(value) => {
|
||||
const p = path()
|
||||
if (!p) return
|
||||
addCommentToContext({
|
||||
file: p,
|
||||
selection: range(),
|
||||
comment,
|
||||
comment: value,
|
||||
origin: "file",
|
||||
})
|
||||
setCommenting(null)
|
||||
}}
|
||||
onPopoverFocusOut={(e) => {
|
||||
const target = e.relatedTarget as Node | null
|
||||
if (target && e.currentTarget.contains(target)) return
|
||||
// Delay to allow click handlers to fire first
|
||||
onPopoverFocusOut={(e: FocusEvent) => {
|
||||
const current = e.currentTarget as HTMLDivElement
|
||||
const target = e.relatedTarget
|
||||
if (target instanceof Node && current.contains(target)) return
|
||||
|
||||
setTimeout(() => {
|
||||
if (
|
||||
!document.activeElement ||
|
||||
!e.currentTarget.contains(document.activeElement)
|
||||
) {
|
||||
if (!document.activeElement || !current.contains(document.activeElement)) {
|
||||
setCommenting(null)
|
||||
}
|
||||
}, 0)
|
||||
@@ -2572,7 +2472,6 @@ export default function Page() {
|
||||
)
|
||||
|
||||
onCleanup(() => {
|
||||
if (commentFrame !== undefined) cancelAnimationFrame(commentFrame)
|
||||
for (const item of codeScroll) {
|
||||
item.removeEventListener("scroll", handleCodeScroll)
|
||||
}
|
||||
@@ -2638,6 +2537,45 @@ export default function Page() {
|
||||
</Show>
|
||||
</DragOverlay>
|
||||
</DragDropProvider>
|
||||
}
|
||||
>
|
||||
<div class="flex flex-col h-full overflow-hidden bg-background-stronger contain-strict">
|
||||
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
||||
<Switch>
|
||||
<Match when={hasReview()}>
|
||||
<Show
|
||||
when={diffsReady()}
|
||||
fallback={
|
||||
<div class="px-6 py-4 text-text-weak">{language.t("session.review.loadingChanges")}</div>
|
||||
}
|
||||
>
|
||||
<SessionReviewTab
|
||||
diffs={diffs}
|
||||
view={view}
|
||||
diffStyle={layout.review.diffStyle()}
|
||||
onDiffStyleChange={layout.review.setDiffStyle}
|
||||
onScrollRef={setReviewScroll}
|
||||
onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
|
||||
comments={comments.all()}
|
||||
focusedComment={comments.focus()}
|
||||
onFocusedCommentChange={comments.setFocus}
|
||||
onViewFile={(path) => {
|
||||
const value = file.tab(path)
|
||||
tabs().open(value)
|
||||
file.load(path)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<div class="h-full px-6 pb-30 flex flex-col items-center justify-center text-center gap-6">
|
||||
<Mark class="w-14 opacity-10" />
|
||||
<div class="text-13-regular text-text-weak max-w-56">No changes in this session yet</div>
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
@@ -2647,7 +2585,7 @@ export default function Page() {
|
||||
<Tabs variant="pill" value={fileTreeTab()} onChange={setFileTreeTabValue} class="h-full">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
|
||||
Changes
|
||||
{reviewCount()} {reviewCount() === 1 ? "Change" : "Changes"}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
|
||||
All files
|
||||
@@ -2662,7 +2600,7 @@ export default function Page() {
|
||||
>
|
||||
<FileTree
|
||||
path=""
|
||||
allowed={diffs().map((d) => d.file)}
|
||||
allowed={diffFiles()}
|
||||
draggable={false}
|
||||
tooltip={false}
|
||||
onFileClick={(node) => focusReviewDiff(node.path)}
|
||||
@@ -2675,7 +2613,7 @@ export default function Page() {
|
||||
</Switch>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="all" class="bg-background-base p-2">
|
||||
<FileTree path="" onFileClick={(node) => openTab(file.tab(node.path))} />
|
||||
<FileTree path="" modified={diffFiles()} onFileClick={(node) => openTab(file.tab(node.path))} />
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
@@ -219,7 +219,6 @@
|
||||
height: auto;
|
||||
padding: 6px;
|
||||
gap: 4px;
|
||||
border-bottom: 1px solid var(--border-weak-base);
|
||||
background-color: var(--background-base);
|
||||
|
||||
&::after {
|
||||
@@ -230,7 +229,7 @@
|
||||
[data-slot="tabs-trigger-wrapper"] {
|
||||
height: 32px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
border-radius: var(--radius-sm);
|
||||
background-color: transparent;
|
||||
gap: 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user