feat(FN-2628): merge fusion/fn-2628

This commit is contained in:
gsxdsm
2026-04-26 22:21:18 -07:00
parent 6d2cf27410
commit 7c3e5dde29
4 changed files with 139 additions and 73 deletions

View File

@@ -0,0 +1,110 @@
.comments-header-row {
justify-content: space-between;
gap: var(--space-md);
}
.comments-author-row {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.comments-actions-row {
display: flex;
gap: var(--space-sm);
}
.comments-edit-form {
display: grid;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.comments-edit-actions {
display: flex;
gap: var(--space-sm);
justify-content: flex-end;
}
.comments-outcome-text {
white-space: pre-wrap;
}
.comments-compose-form {
display: grid;
gap: var(--space-sm);
margin-top: var(--space-md);
}
.comments-type-toggle {
display: flex;
gap: var(--space-sm);
}
.comments-guidance-hint {
font-size: 0.875rem;
color: var(--text-muted);
}
.comments-footer-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.comments-char-count {
font-size: 0.75rem;
}
.comments-char-count--over {
color: var(--color-error);
}
.comments-textarea {
width: 100%;
padding: var(--space-sm) var(--space-md);
background: var(--surface);
border: var(--btn-border-width) solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
font-family: inherit;
font-size: 0.8125rem;
line-height: 1.5;
resize: vertical;
outline: none;
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.comments-textarea:focus,
.comments-textarea:focus-visible {
border-color: var(--todo);
box-shadow: var(--focus-ring-strong);
}
.comments-textarea::placeholder {
color: var(--text-dim);
}
.comments-textarea:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.ai-guidance-badge {
display: inline-flex;
align-items: center;
padding: calc(var(--space-xs) / 4) var(--space-sm);
background: color-mix(in srgb, var(--color-info) 15%, transparent);
color: var(--color-info);
border-radius: var(--radius-pill);
font-size: 0.6875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.02em;
}
@media (max-width: 768px) {
.comments-textarea {
font-size: 1rem;
}
}

View File

@@ -1,6 +1,7 @@
import { useMemo, useState } from "react";
import type { Task, TaskComment } from "@fusion/core";
import { getErrorMessage } from "@fusion/core";
import "./TaskComments.css";
import { addSteeringComment, updateTaskComment, deleteTaskComment } from "../api";
import type { ToastType } from "../hooks/useToast";
@@ -143,7 +144,7 @@ export function TaskComments({ task, onTaskUpdated, addToast, currentAuthor = "u
value={editingText}
onChange={(event) => setEditingText(event.target.value)}
rows={3}
className="spec-editor-feedback"
className="comments-textarea"
/>
<div className="comments-edit-actions">
<button
@@ -183,7 +184,7 @@ export function TaskComments({ task, onTaskUpdated, addToast, currentAuthor = "u
onKeyDown={handleKeyDown}
rows={3}
placeholder={placeholder}
className="spec-editor-feedback"
className="comments-textarea"
/>
<div className="comments-footer-row">
<span className={`comments-char-count${isOverLimit ? " comments-char-count--over" : ""}`}>

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { loadAllAppCssBaseOnly } from "../../test/cssFixture";
import { TaskComments } from "../TaskComments";
vi.mock("../../api", () => ({
@@ -215,4 +216,29 @@ describe("TaskComments", () => {
expect(screen.getByText("Agent guidance")).toBeTruthy();
});
});
describe("CSS styling", () => {
const css = loadAllAppCssBaseOnly();
it.each([
{
selector: "comments-textarea",
assertions: [/\.comments-textarea\s*\{[^}]*background:\s*var\(--surface\);/, /\.comments-textarea\s*\{[^}]*border:\s*var\(--btn-border-width\)\s+solid\s+var\(--border\);/],
},
{
selector: "ai-guidance-badge",
assertions: [/\.ai-guidance-badge\s*\{[^}]*color:\s*var\(--color-info\);/],
},
])("uses tokenized styles for $selector", ({ assertions }) => {
for (const assertion of assertions) {
expect(css).toMatch(assertion);
}
});
it("does not rely on spec-editor-feedback for comment textareas", () => {
expect(css).toMatch(/\.comments-textarea\s*\{/);
expect(css).not.toContain(".comments-compose-form .spec-editor-feedback");
expect(css).not.toContain(".comments-edit-form .spec-editor-feedback");
});
});
});

View File

@@ -1418,77 +1418,6 @@ input[type="range"]:focus-visible {
}
/* === Task Comments === */
.comments-header-row {
justify-content: space-between;
gap: var(--space-md);
}
.comments-author-row {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.comments-actions-row {
display: flex;
gap: var(--space-sm);
}
.comments-edit-form {
display: grid;
gap: var(--space-sm);
margin-top: var(--space-sm);
}
.comments-edit-actions {
display: flex;
gap: var(--space-sm);
justify-content: flex-end;
}
.comments-outcome-text {
white-space: pre-wrap;
}
.comments-compose-form {
display: grid;
gap: var(--space-sm);
margin-top: var(--space-md);
}
/* Comment textareas use --surface so they remain visible against the
task detail modal's --card / --bg panels (in light mode --bg and
--card are both #ffffff, which made the box blend in). */
.comments-compose-form .spec-editor-feedback,
.comments-edit-form .spec-editor-feedback {
background: var(--surface);
}
.comments-type-toggle {
display: flex;
gap: var(--space-sm);
}
.comments-guidance-hint {
font-size: 0.875rem;
color: var(--text-muted);
}
.comments-footer-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.comments-char-count {
font-size: 0.75rem;
}
.comments-char-count--over {
color: var(--color-error);
}
/* === PR Section === */
.pr-section-icon {
vertical-align: middle;