diff options
| author | adamelmore <[email protected]> | 2026-01-24 09:09:23 -0600 |
|---|---|---|
| committer | adamelmore <[email protected]> | 2026-01-24 09:09:27 -0600 |
| commit | 6d8e9943837a73944911728a698138e23601d556 (patch) | |
| tree | 462ebd58be367851bf3d42dcfe15dc0baba2e354 | |
| parent | ae77ef3370dd0e017aba38eb5403ccf0f3404e76 (diff) | |
| download | opencode-6d8e9943837a73944911728a698138e23601d556.tar.gz opencode-6d8e9943837a73944911728a698138e23601d556.zip | |
fix(app): line selection fixes
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 37 | ||||
| -rw-r--r-- | packages/app/src/context/prompt.tsx | 1 | ||||
| -rw-r--r-- | packages/app/src/pages/session.tsx | 211 | ||||
| -rw-r--r-- | packages/ui/src/components/line-comment.css | 49 | ||||
| -rw-r--r-- | packages/ui/src/components/line-comment.tsx | 53 | ||||
| -rw-r--r-- | packages/ui/src/components/session-review.css | 171 | ||||
| -rw-r--r-- | packages/ui/src/components/session-review.tsx | 141 | ||||
| -rw-r--r-- | packages/ui/src/styles/index.css | 1 |
8 files changed, 368 insertions, 296 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 5a367aa61..18c1d98a7 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -170,6 +170,36 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const tabs = createMemo(() => layout.tabs(sessionKey)) const view = createMemo(() => layout.view(sessionKey)) + const commentInReview = (path: string) => { + const sessionID = params.id + if (!sessionID) return false + + const diffs = sync.data.session_diff[sessionID] + if (!diffs) return false + return diffs.some((diff) => diff.file === path) + } + + const openComment = (item: { path: string; commentID?: string; commentOrigin?: "review" | "file" }) => { + if (!item.commentID) return + + comments.setFocus({ file: item.path, id: item.commentID }) + view().reviewPanel.open() + + if (item.commentOrigin === "review") { + tabs().open("review") + return + } + + if (item.commentOrigin !== "file" && commentInReview(item.path)) { + tabs().open("review") + return + } + + const tab = files.tab(item.path) + tabs().open(tab) + files.load(item.path) + } + const recent = createMemo(() => { const all = tabs().all() const active = tabs().active() @@ -1481,6 +1511,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { selection: item.selection, comment: item.comment, commentID: item.commentID, + commentOrigin: item.commentOrigin, preview: item.preview, }) } @@ -1547,6 +1578,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { selection: item.selection, comment: item.comment, commentID: item.commentID, + commentOrigin: item.commentOrigin, preview: item.preview, }) } @@ -1700,10 +1732,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { "cursor-pointer hover:bg-surface-interactive-weak": !!item.commentID, }} onClick={() => { - if (!item.commentID) return - comments.setFocus({ file: item.path, id: item.commentID }) - view().reviewPanel.open() - tabs().open("review") + openComment(item) }} > <div class="flex items-center gap-1.5"> diff --git a/packages/app/src/context/prompt.tsx b/packages/app/src/context/prompt.tsx index 6b9d5cc0d..99fab6c19 100644 --- a/packages/app/src/context/prompt.tsx +++ b/packages/app/src/context/prompt.tsx @@ -44,6 +44,7 @@ export type FileContextItem = { selection?: FileSelection comment?: string commentID?: string + commentOrigin?: "review" | "file" preview?: string } diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 2fc4ab62c..46b41d509 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -27,6 +27,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Tabs } from "@opencode-ai/ui/tabs" import { useCodeComponent } from "@opencode-ai/ui/context/code" +import { LineCommentAnchor } from "@opencode-ai/ui/line-comment" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { createAutoScroll } from "@opencode-ai/ui/hooks" import { SessionReview } from "@opencode-ai/ui/session-review" @@ -535,6 +536,7 @@ export default function Page() { selection: SelectedLineRange comment: string preview?: string + origin?: "review" | "file" }) => { const selection = selectionFromLines(input.selection) const preview = input.preview ?? selectionPreview(input.file, selection) @@ -549,6 +551,7 @@ export default function Page() { selection, comment: input.comment, commentID: saved.id, + commentOrigin: input.origin, preview, }) } @@ -1463,7 +1466,7 @@ export default function Page() { diffs={diffs} view={view} diffStyle="unified" - onLineComment={addCommentToContext} + onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })} comments={comments.all()} focusedComment={comments.focus()} onFocusedCommentChange={comments.setFocus} @@ -1782,7 +1785,7 @@ export default function Page() { view={view} diffStyle={layout.review.diffStyle()} onDiffStyleChange={layout.review.setDiffStyle} - onLineComment={addCommentToContext} + onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })} comments={comments.all()} focusedComment={comments.focus()} onFocusedCommentChange={comments.setFocus} @@ -1974,6 +1977,22 @@ export default function Page() { requestAnimationFrame(() => textarea?.focus()) }) + createEffect(() => { + const focus = comments.focus() + const p = path() + if (!focus || !p) return + if (focus.file !== p) return + if (activeTab() !== tab) return + + const target = fileComments().find((comment) => comment.id === focus.id) + if (!target) return + + setOpenedComment(target.id) + setCommenting(null) + file.setSelectedLines(p, target.selection) + requestAnimationFrame(() => comments.clearFocus()) + }) + const renderCode = (source: string, wrapperClass: string) => ( <div ref={(el) => { @@ -2016,125 +2035,109 @@ export default function Page() { /> <For each={fileComments()}> {(comment) => ( - <div - class="absolute right-6 z-30" - style={{ - top: `${positions()[comment.id] ?? 0}px`, - opacity: positions()[comment.id] === undefined ? 0 : 1, - "pointer-events": positions()[comment.id] === undefined ? "none" : "auto", + <LineCommentAnchor + id={comment.id} + top={positions()[comment.id]} + open={openedComment() === comment.id} + onMouseEnter={() => { + const p = path() + if (!p) return + file.setSelectedLines(p, comment.selection) + }} + onClick={() => { + const p = path() + if (!p) return + setCommenting(null) + setOpenedComment((current) => (current === comment.id ? null : comment.id)) + file.setSelectedLines(p, comment.selection) }} > - <button - type="button" - class="size-5 rounded-md flex items-center justify-center shadow-xs focus:outline-none focus-visible:shadow-xs-border-focus" - style={{ - background: "var(--icon-interactive-base)", - }} - onMouseEnter={() => { - const p = path() - if (!p) return - file.setSelectedLines(p, comment.selection) - }} - onClick={() => { - const p = path() - if (!p) return - setCommenting(null) - setOpenedComment((current) => (current === comment.id ? null : comment.id)) - file.setSelectedLines(p, comment.selection) - }} - > - <Icon name="comment" size="small" style={{ color: "var(--white)" }} /> - </button> - <Show when={openedComment() === comment.id}> - <div class="absolute top-[calc(100%+4px)] right-[-8px] z-40 min-w-[200px] max-w-[320px] rounded-[14px] bg-surface-raised-stronger-non-alpha shadow-lg-border-base p-3"> - <div class="flex flex-col gap-1.5"> - <div class="text-14-regular text-text-strong whitespace-pre-wrap"> - {comment.comment} - </div> - <div class="text-12-medium text-text-weak whitespace-nowrap"> - Comment on {commentLabel(comment.selection)} - </div> - </div> + <div class="flex flex-col gap-1.5"> + <div class="text-14-regular text-text-strong whitespace-pre-wrap"> + {comment.comment} </div> - </Show> - </div> + <div class="text-12-medium text-text-weak whitespace-nowrap"> + Comment on {commentLabel(comment.selection)} + </div> + </div> + </LineCommentAnchor> )} </For> <Show when={commenting()}> {(range) => ( <Show when={draftTop() !== undefined}> - <div class="absolute right-6 z-30" style={{ top: `${draftTop() ?? 0}px` }}> - <button - type="button" - class="size-5 rounded-md flex items-center justify-center shadow-xs focus:outline-none focus-visible:shadow-xs-border-focus" - style={{ - background: "var(--icon-interactive-base)", - color: "var(--white)", - }} - onClick={() => textarea?.focus()} - > - <Icon name="comment" size="small" style={{ color: "var(--white)" }} /> - </button> - <div - class="absolute top-[calc(100%+4px)] right-[-8px] z-40 w-[380px] rounded-[14px] bg-surface-raised-stronger-non-alpha shadow-lg-border-base p-2" - onFocusOut={(e) => { - const target = e.relatedTarget as Node | null - if (!target || !e.currentTarget.contains(target)) { + <LineCommentAnchor + top={draftTop()} + open={true} + variant="editor" + onClick={() => textarea?.focus()} + onPopoverFocusOut={(e) => { + const target = e.relatedTarget as Node | null + if (!target || !e.currentTarget.contains(target)) { + setCommenting(null) + } + }} + > + <div class="flex flex-col gap-2"> + <textarea + ref={textarea} + class="w-full resize-vertical p-2 rounded-[6px] bg-surface-base border border-border-base text-text-strong text-12-regular leading-5 focus:outline-none focus:shadow-xs-border-select" + rows={3} + placeholder="Add comment" + value={draft()} + onInput={(e) => setDraft(e.currentTarget.value)} + onKeyDown={(e) => { + if (e.key === "Escape") { + setCommenting(null) + return + } + if (e.key !== "Enter") return + if (e.shiftKey) return + e.preventDefault() + const value = draft().trim() + if (!value) return + const p = path() + if (!p) return + addCommentToContext({ + file: p, + selection: range(), + comment: value, + origin: "file", + }) setCommenting(null) - } - }} - > - <div class="flex flex-col gap-2"> - <textarea - ref={textarea} - class="w-full resize-vertical p-2 rounded-[6px] bg-surface-base border border-border-base text-text-strong text-12-regular leading-5 focus:outline-none focus:shadow-xs-border-select" - rows={3} - placeholder="Add comment" - value={draft()} - onInput={(e) => setDraft(e.currentTarget.value)} - onKeyDown={(e) => { - if (e.key === "Escape") { - setCommenting(null) - return - } - if (e.key !== "Enter") return - if (e.shiftKey) return - e.preventDefault() + }} + /> + <div class="flex items-center gap-2"> + <div class="text-12-medium text-text-weak ml-1"> + Commenting on {commentLabel(range())} + </div> + <div class="flex-1" /> + <Button size="small" variant="ghost" onClick={() => setCommenting(null)}> + Cancel + </Button> + <Button + size="small" + variant="primary" + disabled={draft().trim().length === 0} + onClick={() => { const value = draft().trim() if (!value) return const p = path() if (!p) return - addCommentToContext({ file: p, selection: range(), comment: value }) + addCommentToContext({ + file: p, + selection: range(), + comment: value, + origin: "file", + }) setCommenting(null) }} - /> - <div class="flex items-center gap-2"> - <div class="text-12-medium text-text-weak ml-1"> - Commenting on {commentLabel(range())} - </div> - <div class="flex-1" /> - <Button size="small" variant="ghost" onClick={() => setCommenting(null)}> - Cancel - </Button> - <Button - size="small" - variant="primary" - disabled={draft().trim().length === 0} - onClick={() => { - const value = draft().trim() - if (!value) return - const p = path() - if (!p) return - addCommentToContext({ file: p, selection: range(), comment: value }) - setCommenting(null) - }} - > - Comment - </Button> - </div> + > + Comment + </Button> </div> </div> - </div> + </LineCommentAnchor> </Show> )} </Show> diff --git a/packages/ui/src/components/line-comment.css b/packages/ui/src/components/line-comment.css new file mode 100644 index 000000000..1cdf78189 --- /dev/null +++ b/packages/ui/src/components/line-comment.css @@ -0,0 +1,49 @@ +[data-component="line-comment"] { + position: absolute; + right: 24px; + z-index: var(--line-comment-z, 30); +} + +[data-component="line-comment"] [data-slot="line-comment-button"] { + width: 20px; + height: 20px; + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + background: var(--icon-interactive-base); + box-shadow: var(--shadow-xs); + cursor: pointer; + border: none; +} + +[data-component="line-comment"] [data-component="icon"] { + color: var(--white); +} + +[data-component="line-comment"] [data-slot="line-comment-button"]:focus { + outline: none; +} + +[data-component="line-comment"] [data-slot="line-comment-button"]:focus-visible { + box-shadow: var(--shadow-xs-border-focus); +} + +[data-component="line-comment"] [data-slot="line-comment-popover"] { + position: absolute; + top: calc(100% + 4px); + right: -8px; + z-index: var(--line-comment-popover-z, 40); + min-width: 200px; + max-width: min(320px, calc(100vw - 48px)); + border-radius: 14px; + background: var(--surface-raised-stronger-non-alpha); + box-shadow: var(--shadow-lg-border-base); + padding: 12px; +} + +[data-component="line-comment"][data-variant="editor"] [data-slot="line-comment-popover"] { + width: 380px; + max-width: min(380px, calc(100vw - 48px)); + padding: 8px; +} diff --git a/packages/ui/src/components/line-comment.tsx b/packages/ui/src/components/line-comment.tsx new file mode 100644 index 000000000..a9e22036b --- /dev/null +++ b/packages/ui/src/components/line-comment.tsx @@ -0,0 +1,53 @@ +import { Show, type JSX } from "solid-js" +import { Icon } from "./icon" + +export type LineCommentVariant = "default" | "editor" + +export type LineCommentAnchorProps = { + id?: string + top?: number + open: boolean + variant?: LineCommentVariant + onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> + onMouseEnter?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> + onPopoverFocusOut?: JSX.EventHandlerUnion<HTMLDivElement, FocusEvent> + class?: string + popoverClass?: string + children: JSX.Element +} + +export const LineCommentAnchor = (props: LineCommentAnchorProps) => { + const hidden = () => props.top === undefined + const variant = () => props.variant ?? "default" + + return ( + <div + data-component="line-comment" + data-variant={variant()} + data-comment-id={props.id} + classList={{ + [props.class ?? ""]: !!props.class, + }} + style={{ + top: `${props.top ?? 0}px`, + opacity: hidden() ? 0 : 1, + "pointer-events": hidden() ? "none" : "auto", + }} + > + <button type="button" data-slot="line-comment-button" onClick={props.onClick} onMouseEnter={props.onMouseEnter}> + <Icon name="comment" size="small" /> + </button> + <Show when={props.open}> + <div + data-slot="line-comment-popover" + classList={{ + [props.popoverClass ?? ""]: !!props.popoverClass, + }} + onFocusOut={props.onPopoverFocusOut} + > + {props.children} + </div> + </Show> + </div> + ) +} diff --git a/packages/ui/src/components/session-review.css b/packages/ui/src/components/session-review.css index 746e6a139..b61248fec 100644 --- a/packages/ui/src/components/session-review.css +++ b/packages/ui/src/components/session-review.css @@ -75,17 +75,66 @@ overflow: hidden; } - [data-slot="session-review-comment-popover-content"] { - position: absolute; - top: calc(100% + 4px); - right: -8px; - z-index: 6; - min-width: 200px; - max-width: min(320px, calc(100vw - 48px)); - border-radius: 10px; - background-color: var(--surface-raised-stronger-non-alpha); - box-shadow: var(--shadow-lg-border-base); - padding: 12px; + [data-slot="session-review-comment-content"] { + display: flex; + flex-direction: column; + gap: 6px; + } + + [data-slot="session-review-comment-text"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-base); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-x-large); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-strong); + white-space: pre-wrap; + } + + [data-slot="session-review-comment-label"], + [data-slot="session-review-comment-draft-label"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-weak); + white-space: nowrap; + } + + [data-slot="session-review-comment-draft"] { + display: flex; + flex-direction: column; + gap: 8px; + } + + [data-slot="session-review-comment-textarea"] { + width: 100%; + max-width: min(380px, calc(100vw - 48px)); + resize: vertical; + padding: 8px; + border-radius: var(--radius-md); + background: var(--surface-base); + border: 1px solid var(--border-base); + color: var(--text-strong); + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + line-height: var(--line-height-large); + + &:focus { + outline: none; + box-shadow: var(--shadow-xs-border-select); + } + } + + [data-slot="session-review-comment-actions"] { + display: flex; + align-items: center; + gap: 8px; + } + + [data-slot="session-review-comment-draft-label"] { + margin-right: auto; } [data-slot="session-review-trigger-content"] { @@ -217,103 +266,7 @@ [data-slot="session-review-diff-wrapper"] { position: relative; overflow: hidden; - } - - [data-slot="session-review-comment-anchor"] { - position: absolute; - right: 12px; - z-index: 5; - } - - [data-slot="session-review-comment-button"] { - width: 20px; - height: 20px; - border-radius: 6px; - display: flex; - align-items: center; - justify-content: center; - background: var(--icon-interactive-base); - box-shadow: var(--shadow-xs); - cursor: pointer; - - [data-slot="icon-svg"] { - color: var(--white); - } - - &:focus { - outline: none; - } - - &:focus-visible { - box-shadow: var(--shadow-xs-border-focus); - } - } - - [data-slot="session-review-comment-hover"] { - display: flex; - flex-direction: column; - gap: 6px; - max-width: 320px; - } - - [data-slot="session-review-comment-popover"] { - display: flex; - flex-direction: column; - gap: 6px; - } - - [data-slot="session-review-comment-hover-label"], - [data-slot="session-review-comment-popover-label"] { - font-family: var(--font-family-sans); - font-size: var(--font-size-small); - font-weight: var(--font-weight-medium); - color: var(--text-weak); - } - - [data-slot="session-review-comment-hover-text"], - [data-slot="session-review-comment-popover-text"] { - font-family: var(--font-family-sans); - font-size: var(--font-size-base); - font-weight: var(--font-weight-regular); - color: var(--text-strong); - white-space: pre-wrap; - } - - [data-slot="session-review-comment-preview"] { - margin: 0; - padding: 8px; - border-radius: var(--radius-sm); - background: var(--surface-base); - border: 1px solid color-mix(in oklch, var(--border-base) 55%, transparent); - color: var(--text-base); - font-family: var(--font-family-mono); - font-size: var(--font-size-small); - line-height: 1.4; - white-space: pre-wrap; - } - - [data-slot="session-review-comment-textarea"] { - width: 320px; - max-width: calc(100vw - 48px); - resize: vertical; - padding: 8px; - border-radius: var(--radius-sm); - background: var(--surface-base); - border: 1px solid color-mix(in oklch, var(--border-base) 55%, transparent); - color: var(--text-strong); - font-family: var(--font-family-sans); - font-size: var(--font-size-small); - line-height: 1.4; - - &:focus { - outline: none; - box-shadow: var(--shadow-xs-border-focus); - } - } - - [data-slot="session-review-comment-actions"] { - display: flex; - justify-content: flex-end; - gap: 8px; + --line-comment-z: 5; + --line-comment-popover-z: 6; } } diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index 6891836ff..2b6d93e2d 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -4,6 +4,7 @@ import { RadioGroup } from "./radio-group" import { DiffChanges } from "./diff-changes" import { FileIcon } from "./file-icon" import { Icon } from "./icon" +import { LineCommentAnchor } from "./line-comment" import { StickyAccordionHeader } from "./sticky-accordion-header" import { useDiffComponent } from "../context/diff" import { useI18n } from "../context/i18n" @@ -559,71 +560,74 @@ export const SessionReview = (props: SessionReviewProps) => { <For each={comments()}> {(comment) => ( - <div - data-slot="session-review-comment-anchor" - data-comment-id={comment.id} - style={{ - top: `${positions()[comment.id] ?? 0}px`, - opacity: positions()[comment.id] === undefined ? 0 : 1, - "pointer-events": positions()[comment.id] === undefined ? "none" : "auto", + <LineCommentAnchor + id={comment.id} + top={positions()[comment.id]} + onMouseEnter={() => setSelection({ file: comment.file, range: comment.selection })} + onClick={() => { + if (isCommentOpen(comment)) { + setOpened(null) + return + } + + openComment(comment) }} + open={isCommentOpen(comment)} > - <button - type="button" - data-slot="session-review-comment-button" - onMouseEnter={() => setSelection({ file: comment.file, range: comment.selection })} - onClick={() => { - if (isCommentOpen(comment)) { - setOpened(null) - return - } - - openComment(comment) - }} - > - <Icon name="comment" size="small" /> - </button> - <Show when={isCommentOpen(comment)}> - <div data-slot="session-review-comment-popover-content"> - <div data-slot="session-review-comment-popover"> - <div data-slot="session-review-comment-popover-text">{comment.comment}</div> - <div data-slot="session-review-comment-popover-label"> - Comment on {selectionLabel(comment.selection)} - </div> - </div> + <div data-slot="session-review-comment-content"> + <div data-slot="session-review-comment-text">{comment.comment}</div> + <div data-slot="session-review-comment-label"> + Comment on {selectionLabel(comment.selection)} </div> - </Show> - </div> + </div> + </LineCommentAnchor> )} </For> <Show when={draftRange()}> {(range) => ( <Show when={draftTop() !== undefined}> - <div data-slot="session-review-comment-anchor" style={{ top: `${draftTop() ?? 0}px` }}> - <button - type="button" - data-slot="session-review-comment-button" - onClick={() => textarea?.focus()} - > - <Icon name="comment" size="small" /> - </button> - <div data-slot="session-review-comment-popover-content"> - <div data-slot="session-review-comment-popover"> - <div data-slot="session-review-comment-popover-label"> + <LineCommentAnchor + top={draftTop()} + onClick={() => textarea?.focus()} + open={true} + variant="editor" + > + <div data-slot="session-review-comment-draft"> + <textarea + ref={textarea} + data-slot="session-review-comment-textarea" + rows={3} + placeholder="Add comment" + value={draft()} + onInput={(e) => setDraft(e.currentTarget.value)} + onKeyDown={(e) => { + if (e.key !== "Enter") return + if (e.shiftKey) return + e.preventDefault() + const value = draft().trim() + if (!value) return + props.onLineComment?.({ + file: diff.file, + selection: range(), + comment: value, + preview: selectionPreview(diff, range()), + }) + setCommenting(null) + }} + /> + <div data-slot="session-review-comment-actions"> + <div data-slot="session-review-comment-draft-label"> Commenting on {getFilename(diff.file)}:{selectionLabel(range())} </div> - <textarea - ref={textarea} - data-slot="session-review-comment-textarea" - rows={3} - placeholder="Add a comment" - value={draft()} - onInput={(e) => setDraft(e.currentTarget.value)} - onKeyDown={(e) => { - if (e.key !== "Enter") return - if (e.shiftKey) return - e.preventDefault() + <Button size="small" variant="ghost" onClick={() => setCommenting(null)}> + Cancel + </Button> + <Button + size="small" + variant="primary" + disabled={draft().trim().length === 0} + onClick={() => { const value = draft().trim() if (!value) return props.onLineComment?.({ @@ -634,33 +638,12 @@ export const SessionReview = (props: SessionReviewProps) => { }) setCommenting(null) }} - /> - <div data-slot="session-review-comment-actions"> - <Button size="small" variant="ghost" onClick={() => setCommenting(null)}> - Cancel - </Button> - <Button - size="small" - variant="secondary" - disabled={draft().trim().length === 0} - onClick={() => { - const value = draft().trim() - if (!value) return - props.onLineComment?.({ - file: diff.file, - selection: range(), - comment: value, - preview: selectionPreview(diff, range()), - }) - setCommenting(null) - }} - > - Comment - </Button> - </div> + > + Comment + </Button> </div> </div> - </div> + </LineCommentAnchor> </Show> )} </Show> diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index b4b0883ae..3ed0310ef 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -25,6 +25,7 @@ @import "../components/icon-button.css" layer(components); @import "../components/image-preview.css" layer(components); @import "../components/keybind.css" layer(components); +@import "../components/line-comment.css" layer(components); @import "../components/text-field.css" layer(components); @import "../components/inline-input.css" layer(components); @import "../components/list.css" layer(components); |
