FN-9197: Add padding to the chat tag filter

Improve the chat sidebar tag filter spacing while preserving token-based styling.

- Align the tag filter select padding with the sidebar search input.
- Add a stylesheet regression test covering all ChatView hosts.
- Record the operator-facing fix in a patch changeset.

Files changed:
 .changeset/chat-tag-filter-padding.md              |  7 +++
 packages/dashboard/app/components/ChatView.css     | 10 +++-
 .../__tests__/ChatView.tag-filter-padding.test.ts  | 60 ++++++++++++++++++++++
 3 files changed, 75 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-9197

Fusion-Task-Lineage: e2220b2d-b7e5-4de9-8751-da8e3a4a9e69

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-23 09:04:29 -07:00
parent 038f802ba4
commit bd93723d44
3 changed files with 75 additions and 2 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Give the chat sidebar tag filter proper inner padding so "All tags" is not cramped.
category: fix
dev: Updates `.chat-tag-filter select` padding in ChatView.css to `var(--space-sm) var(--space-md)`; pinned by a stylesheet-source regression test.

View File

@@ -2486,9 +2486,15 @@ Thinking-section text uses the defined muted text token across all themes. The m
border-color: color-mix(in srgb, var(--color-warning) 55%, transparent);
}
/* FNXC:ChatTags 2026-08-05-10:55: shared ChatView hosts expose Direct-only tag filters and compact chips without introducing a second sidebar layout. */
/*
FNXC:ChatTags 2026-08-05-10:55:
Shared ChatView hosts expose Direct-only tag filters and compact chips without introducing a second sidebar layout.
FNXC:ChatTags 2026-08-23-15:51:
The tag filter select must use the sibling sidebar search input's comfortable token-based inner padding so "All tags" is not flush against its border across desktop, narrow, and mobile hosts.
*/
.chat-tag-filter { display: flex; align-items: center; gap: var(--space-xs); color: var(--text-muted); }
.chat-tag-filter select { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg); color: var(--text); padding: var(--space-xs); }
.chat-tag-filter select { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg); color: var(--text); padding: var(--space-sm) var(--space-md); }
.chat-session-tags { display: flex; flex-wrap: wrap; gap: var(--space-xs); overflow: hidden; }
.chat-session-tag { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 var(--space-xs); border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text-muted); font-size: var(--font-size-xs); }
/* FNXC:ChatTags 2026-08-05-12:15: direct-conversation tag controls keep assignment, rename, and deletion in the existing context menu so shared Chat hosts do not grow another sidebar action row. */

View File

@@ -0,0 +1,60 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
/*
FNXC:ChatTags 2026-08-23-15:51:
The shared Direct-scope tag filter must preserve the sidebar search input's comfortable token-based padding in every ChatView host. jsdom does not compute cascaded external stylesheet padding, so this stylesheet-source assertion is the enforceable regression seam for the cramped "All tags" control.
*/
const chatViewCss = readFileSync(resolve(__dirname, "../ChatView.css"), "utf8");
function uncomment(css: string): string {
return css.replace(/\/\*[\s\S]*?\*\//g, "");
}
function collectTagFilterBlocks(css: string): Array<{ selector: string; block: string }> {
const blocks: Array<{ selector: string; block: string }> = [];
const rulePattern = /([^{}]+)\{([^{}]*)\}/g;
for (const match of uncomment(css).matchAll(rulePattern)) {
const selector = match[1].trim();
if (selector.split(",").some((part) => part.trim().includes(".chat-tag-filter select"))) {
blocks.push({ selector, block: match[2] });
}
}
return blocks;
}
function paddingDeclaration(block: string): string | undefined {
return block.match(/(?:^|;)\s*padding\s*:\s*([^;]+)/)?.[1]?.trim();
}
describe("ChatView tag filter padding", () => {
it("keeps the All tags select aligned with the sidebar search input across stylesheet rules", () => {
const blocks = collectTagFilterBlocks(chatViewCss);
expect(blocks.length).toBeGreaterThanOrEqual(1);
const base = blocks.find(({ selector }) => selector === ".chat-tag-filter select");
expect(base, "base .chat-tag-filter select rule must exist").toBeDefined();
const basePadding = paddingDeclaration(base!.block);
expect(basePadding).toContain("var(--space-sm)");
expect(basePadding).toContain("var(--space-md)");
for (const { selector, block } of blocks) {
const padding = paddingDeclaration(block);
if (!padding) continue;
expect(padding, `tag filter rule "${selector}" must not restore cramped padding`).not.toMatch(
/^var\(--space-xs\)$/,
);
expect(padding, `tag filter rule "${selector}" must use design tokens, not raw dimensions or colors`).not.toMatch(
/(?:\d(?:\.\d+)?(?:px|rem)|#[0-9a-f]{3,8})/i,
);
expect(padding, `tag filter rule "${selector}" must use only --space-* tokens`).toMatch(
/^var\(--space-[a-z0-9-]+\)(?:\s+var\(--space-[a-z0-9-]+\)){0,3}$/,
);
}
});
});