summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-10-15 14:48:19 +0900
committerAdam Malczewski <[email protected]>2026-10-15 14:48:19 +0900
commitc23aa41d1ffa71ac905da8ac9488b07322327695 (patch)
tree1b8ca4699b991e462093c287bb40164cff6de76f /src
parentc4c1d76fec972e5d902a669f0cb1953eaa528f16 (diff)
downloaddispatch-web-c23aa41d1ffa71ac905da8ac9488b07322327695.tar.gz
dispatch-web-c23aa41d1ffa71ac905da8ac9488b07322327695.zip
fix(tabs): even group-box padding on all sides + 50% black background; test parent reverts to half width when its subagents close
Diffstat (limited to 'src')
-rw-r--r--src/features/tabs/ui.test.ts58
-rw-r--r--src/features/tabs/ui/TabGroupBox.svelte7
2 files changed, 59 insertions, 6 deletions
diff --git a/src/features/tabs/ui.test.ts b/src/features/tabs/ui.test.ts
index 7c8b0db..49d70f2 100644
--- a/src/features/tabs/ui.test.ts
+++ b/src/features/tabs/ui.test.ts
@@ -371,11 +371,63 @@ describe("TabList", () => {
expect(inner?.contains(card("g"))).toBe(true);
// Inner boxes bleed less than outer ones, so nested edges stay visible
// while the cards keep identical widths.
- const pad = (el: HTMLElement | null) => el?.style.getPropertyValue("padding-inline") ?? "";
- const bleed = (el: HTMLElement | null) => Number.parseFloat(pad(el));
+ const bleed = (el: HTMLElement | null) => Number.parseFloat(el?.style.paddingLeft ?? "");
expect(bleed(inner)).toBeGreaterThan(0);
expect(bleed(outer)).toBeGreaterThan(bleed(inner));
- expect(outer?.style.getPropertyValue("margin-inline")).toBe(`-${pad(outer)}`);
+ // Equal internal padding on all four sides (an even-looking box).
+ for (const box of [outer, inner]) {
+ const s = box?.style;
+ expect([s?.paddingTop, s?.paddingRight, s?.paddingBottom]).toEqual([
+ s?.paddingLeft,
+ s?.paddingLeft,
+ s?.paddingLeft,
+ ]);
+ expect(box).toHaveClass("bg-black/50");
+ }
+ expect(outer?.style.getPropertyValue("margin-inline")).toBe(`-${outer?.style.paddingLeft}`);
+ });
+
+ it("returns the group parent to a half-width card once all its subagent tabs close", async () => {
+ const props = {
+ tabs: grouped,
+ activeConversationId: "p",
+ onSelect: vi.fn(),
+ onClose: vi.fn(),
+ onNewDraft: vi.fn(),
+ onSetTabGroup: vi.fn(),
+ };
+ const { rerender } = render(TabList, { props });
+ expect(card("p")).toHaveClass("col-span-2");
+
+ // Close one subagent: still a group (1 left).
+ await rerender({ ...props, tabs: grouped.filter((t) => t.conversationId !== "c2") });
+ expect(card("p")).toHaveClass("col-span-2");
+ expect(card("p")).toHaveTextContent("1 subagent");
+
+ // Close the rest (c1 + its own subagent g): back to a plain half-width card.
+ await rerender({
+ ...props,
+ tabs: grouped.filter((t) => ["p", "solo"].includes(t.conversationId)),
+ });
+ expect(card("p")).not.toHaveClass("col-span-2");
+ expect(card("p")).not.toHaveTextContent("subagent");
+ expect(document.querySelector("[data-tab-group]")).toBeNull();
+ });
+
+ it("keeps the parent wide while a nested descendant's own parent remains open", async () => {
+ const props = {
+ tabs: grouped,
+ activeConversationId: "p",
+ onSelect: vi.fn(),
+ onClose: vi.fn(),
+ onNewDraft: vi.fn(),
+ };
+ const { rerender } = render(TabList, { props });
+ // Close the grandchild only: c1 goes back to half width, p stays a group.
+ await rerender({ ...props, tabs: grouped.filter((t) => t.conversationId !== "g") });
+ expect(card("c1")).not.toHaveClass("col-span-2");
+ expect(document.querySelector('[data-tab-group="c1"]')).toBeNull();
+ expect(card("p")).toHaveClass("col-span-2");
});
it("right-click opens the menu; 'Remove from group' ungroups the tab", async () => {
diff --git a/src/features/tabs/ui/TabGroupBox.svelte b/src/features/tabs/ui/TabGroupBox.svelte
index 5cbfb27..0bf3ad2 100644
--- a/src/features/tabs/ui/TabGroupBox.svelte
+++ b/src/features/tabs/ui/TabGroupBox.svelte
@@ -11,7 +11,8 @@
* a subagent with its own subagents renders a nested box. The box BLEEDS
* outward (negative margin + equal padding, `groupBleedPx`) so the cards
* inside stay on the same two columns as top-level cards: every card keeps
- * identical dimensions at every depth. The translucent black background
+ * identical dimensions at every depth. The padding is EQUAL on all four
+ * sides (= the bleed) so the box looks even. The 50%-black background
* compounds, so each nesting level reads darker than the one around it.
*/
let {
@@ -32,9 +33,9 @@
</script>
<div
- class="col-span-2 rounded-lg border border-black/50 bg-black/40 py-1.5 shadow-inner"
+ class="col-span-2 rounded-lg bg-black/50"
style:margin-inline="-{bleed}px"
- style:padding-inline="{bleed}px"
+ style:padding="{bleed}px"
role="group"
aria-label={`Subagents of ${node.tab.title}`}
data-tab-group={node.tab.conversationId}