diff --git a/src/editor-rewrite/popover.ts b/src/editor-rewrite/popover.ts index 0d56f6b0..91dabbc0 100644 --- a/src/editor-rewrite/popover.ts +++ b/src/editor-rewrite/popover.ts @@ -1,7 +1,7 @@ import { Notice, type Editor } from "obsidian"; +import { syncComposerHeight } from "../ui/composer"; import { createIconButton } from "../ui/components"; -import { syncTextareaHeight } from "../ui/textarea-autogrow"; import { diffLineClass, displayDiffLineText, displayDiffLines } from "../ui/turn-diff"; import { buildSelectionUnifiedDiff } from "./diff"; import { isRewriteActionKey, isRewriteGenerateKey } from "./keys"; @@ -115,6 +115,7 @@ export class RewriteSelectionPopover { } finally { if (this.abortController === abortController) this.abortController = null; this.syncControls(); + if (this.options.session.status === "preview") this.focusApplyButton(); this.position(); } } @@ -140,10 +141,9 @@ export class RewriteSelectionPopover { const root = activeDocument.body.createDiv({ cls: "codex-panel-rewrite-popover" }); root.setAttr("role", "dialog"); root.setAttr("aria-label", "Rewrite selection"); - root.onkeydown = (event) => this.handlePopoverKeydown(event); const instruction = root.createEl("textarea", { - cls: "codex-panel-rewrite-popover__instruction", + cls: "codex-panel__input codex-panel-rewrite-popover__instruction", attr: { placeholder: "How should Codex rewrite the selected text?" }, }); instruction.value = this.options.session.instruction; @@ -162,18 +162,38 @@ export class RewriteSelectionPopover { const promptRow = root.createDiv({ cls: "codex-panel-rewrite-popover__prompt-row" }); promptRow.append(instruction); - const controls = promptRow.createDiv({ cls: "codex-panel-rewrite-popover__controls" }); - const generateButton = createIconButton(controls, "sparkles", "Generate rewrite", "codex-panel-rewrite-popover__icon-button"); + const controls = promptRow.createDiv({ cls: "codex-panel__composer-actions codex-panel-rewrite-popover__controls" }); + const generateButton = createIconButton( + controls, + "sparkles", + "Generate rewrite", + "codex-panel__composer-action codex-panel-rewrite-popover__icon-button", + ); generateButton.onclick = () => void this.generate(); - const cancelButton = createIconButton(controls, "x", "Cancel rewrite", "codex-panel-rewrite-popover__icon-button"); + const cancelButton = createIconButton( + controls, + "x", + "Cancel rewrite", + "codex-panel__composer-action codex-panel-rewrite-popover__icon-button", + ); cancelButton.onclick = () => this.cancel(); const status = root.createDiv({ cls: "codex-panel-rewrite-popover__status" }); const streamPreview = root.createEl("pre", { cls: "codex-panel-rewrite-popover__stream-preview is-hidden" }); const resultRow = root.createDiv({ cls: "codex-panel-rewrite-popover__result-row" }); const diff = resultRow.createDiv({ cls: "codex-panel-rewrite-popover__diff" }); - const applyButton = createIconButton(resultRow, "check", "Apply rewrite", "codex-panel-rewrite-popover__icon-button mod-cta"); + const applyButton = createIconButton( + resultRow, + "check", + "Apply rewrite", + "codex-panel__composer-action codex-panel-rewrite-popover__icon-button mod-cta", + ); applyButton.onclick = () => this.apply(); + applyButton.onkeydown = (event) => { + if (!isRewriteActionKey(event)) return; + event.preventDefault(); + this.apply(); + }; return { root, instruction, generateButton, applyButton, resultRow, status, streamPreview, diff, debug: null }; } @@ -254,13 +274,9 @@ export class RewriteSelectionPopover { this.close(); } - private handlePopoverKeydown(event: KeyboardEvent): void { - if (!this.elements || event.target === this.elements.instruction) return; - if (isInteractiveEventTarget(event.target)) return; - if (this.options.session.replacementText === null || this.options.session.status === "generating") return; - if (!isRewriteActionKey(event)) return; - event.preventDefault(); - this.apply(); + private focusApplyButton(): void { + if (!this.elements || this.elements.applyButton.disabled) return; + this.elements.applyButton.focus({ preventScroll: true }); } private setStatus(text: string, options: { active?: boolean } = {}): void { @@ -291,10 +307,7 @@ export class RewriteSelectionPopover { } private syncInstructionHeight(): void { - syncTextareaHeight(this.elements?.instruction ?? null, { - minHeightFallback: 0, - maxHeightFallback: Math.min(168, activeWindow.innerHeight * 0.28), - }); + syncComposerHeight(this.elements?.instruction ?? null); } private position(): void { @@ -336,8 +349,3 @@ function renderRewriteDiff(parent: HTMLElement, diff: string): void { }); } } - -function isInteractiveEventTarget(target: EventTarget | null): boolean { - if (!(target instanceof HTMLElement)) return false; - return Boolean(target.closest("button, input, textarea, select, a, [role='button']")); -} diff --git a/styles.css b/styles.css index 8e305e24..389572f6 100644 --- a/styles.css +++ b/styles.css @@ -1,5 +1,6 @@ .codex-panel, -.codex-panel-settings { +.codex-panel-settings, +.codex-panel-rewrite-popover { --codex-panel-top-icon-size: var(--icon-s, 16px); --codex-panel-icon-button-inline-size: calc(var(--codex-panel-top-icon-size) + var(--size-2-3, 6px) * 2); --codex-panel-icon-button-block-size: calc(var(--codex-panel-top-icon-size) + var(--size-2-2, 4px) * 2); @@ -1397,8 +1398,6 @@ } .codex-panel-rewrite-popover { - --rewrite-icon-button-size: calc(var(--icon-s, 16px) + var(--size-2-3, 6px) * 2); - --rewrite-control-stack-size: calc(var(--rewrite-icon-button-size) * 2 + var(--size-2-1, 2px)); position: fixed; z-index: var(--layer-popover, 30); box-sizing: border-box; @@ -1416,38 +1415,17 @@ color: var(--text-normal); } -.codex-panel-rewrite-popover__instruction { - box-sizing: border-box; - display: block; - width: 100%; - height: var(--rewrite-control-stack-size); - min-height: var(--rewrite-control-stack-size); - max-height: min(168px, 28vh); - padding: var(--size-2-3, 6px) var(--size-4-2, 8px); - line-height: var(--line-height-normal); - resize: none; - overflow-y: hidden; -} - .codex-panel-rewrite-popover__prompt-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; - gap: var(--size-2-2, 4px); + gap: var(--codex-panel-section-gap); align-items: stretch; } -.codex-panel-rewrite-popover__controls { - display: flex; - flex-direction: column; - align-items: stretch; - justify-content: flex-start; - gap: var(--size-2-1, 2px); -} - .codex-panel-rewrite-popover__result-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; - gap: var(--size-2-2, 4px); + gap: var(--codex-panel-control-gap); align-items: start; } @@ -1456,30 +1434,10 @@ display: none; } -.codex-panel-rewrite-popover__icon-button { - --icon-size: var(--icon-s, 16px); - --icon-stroke: var(--icon-s-stroke-width, 2px); - box-sizing: border-box; - width: var(--rewrite-icon-button-size); - height: var(--rewrite-icon-button-size); - min-width: var(--rewrite-icon-button-size); - min-height: var(--rewrite-icon-button-size); - padding: var(--size-2-3, 6px); - border: 0; - border-radius: var(--clickable-icon-radius, var(--radius-s)); - line-height: 1; -} - .codex-panel-rewrite-popover__icon-button.is-hidden { display: none; } -.codex-panel-rewrite-popover__icon-button svg { - width: var(--icon-size); - height: var(--icon-size); - stroke-width: var(--icon-stroke); -} - .codex-panel-rewrite-popover__status { color: var(--text-muted); font-size: var(--font-ui-small);