feat(FN-1601): merge fusion/fn-1601
This commit is contained in:
@@ -373,13 +373,13 @@ describe("tablet header controls", () => {
|
||||
expect(screen.queryByTestId("project-selector-trigger")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render split project button on tablet", () => {
|
||||
it("does not render back to projects button on tablet", () => {
|
||||
renderTabletHeader({
|
||||
projects: [{ id: "1", name: "Project One", path: "/path/one", status: "active" as const }],
|
||||
currentProject: { id: "1", name: "Project One", path: "/path/one", status: "active" as const },
|
||||
onViewAllProjects: noop,
|
||||
});
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows switch project in overflow menu when multiple projects on tablet", () => {
|
||||
|
||||
@@ -927,66 +927,73 @@ describe("Header", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Projects button", () => {
|
||||
describe("Back to All Projects button", () => {
|
||||
const singleProject = [
|
||||
{ id: "1", name: "Test Project", path: "/path/to/project", status: "active" as const },
|
||||
];
|
||||
|
||||
it("renders Projects button when projects exist", () => {
|
||||
it("renders Back to All Projects button when currentProject is set", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
onViewAllProjects: noop,
|
||||
}, "desktop");
|
||||
expect(screen.getByTestId("header-projects-btn")).toBeDefined();
|
||||
expect(screen.getByTestId("back-to-projects-btn")).toBeDefined();
|
||||
});
|
||||
|
||||
it("calls onViewAllProjects when Projects button is clicked", () => {
|
||||
it("calls onViewAllProjects when Back button is clicked", () => {
|
||||
const onViewAllProjects = vi.fn();
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
onViewAllProjects,
|
||||
}, "desktop");
|
||||
fireEvent.click(screen.getByTestId("header-projects-btn"));
|
||||
fireEvent.click(screen.getByTestId("back-to-projects-btn"));
|
||||
expect(onViewAllProjects).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not render Projects button when no projects", () => {
|
||||
renderHeader({
|
||||
projects: [],
|
||||
onViewAllProjects: noop,
|
||||
}, "desktop");
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render Projects button on mobile", () => {
|
||||
it("does not render Back button when no currentProject", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: null,
|
||||
onViewAllProjects: noop,
|
||||
}, "desktop");
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render Back button on mobile", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
onViewAllProjects: noop,
|
||||
}, "mobile");
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render Projects button on tablet", () => {
|
||||
it("does not render Back button on tablet", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
onViewAllProjects: noop,
|
||||
}, "tablet");
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render Projects button when onViewAllProjects is not provided", () => {
|
||||
it("does not render Back button when onViewAllProjects is not provided", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
}, "desktop");
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders Projects button with correct title", () => {
|
||||
it("renders Back button with correct title", () => {
|
||||
renderHeader({
|
||||
projects: singleProject,
|
||||
currentProject: singleProject[0],
|
||||
onViewAllProjects: noop,
|
||||
}, "desktop");
|
||||
expect(screen.getByTitle("View all projects")).toBeDefined();
|
||||
expect(screen.getByTitle("Back to All Projects")).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ const PROJECT_STATUS_CONFIG: Record<ProjectStatus, { color: string }> = {
|
||||
};
|
||||
|
||||
/**
|
||||
* SplitProjectButton - A two-stage button for project navigation.
|
||||
* Left half: navigates to "all projects" view.
|
||||
* Right half: opens a dropdown to select a specific project.
|
||||
* ProjectSelector - A component for project navigation.
|
||||
* Shows "Back to All Projects" button with ChevronLeft icon when currentProject is set.
|
||||
* Shows project dropdown for switching when 2+ projects exist.
|
||||
*/
|
||||
function SplitProjectButton({
|
||||
function ProjectSelector({
|
||||
projects,
|
||||
currentProject,
|
||||
onViewAll,
|
||||
@@ -69,23 +69,25 @@ function SplitProjectButton({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="split-project-btn" ref={dropdownRef}>
|
||||
{/* Left half: projects view button */}
|
||||
<button
|
||||
className="split-project-btn__left"
|
||||
onClick={onViewAll}
|
||||
title="View all projects"
|
||||
data-testid="header-projects-btn"
|
||||
>
|
||||
<Grid3X3 size={14} />
|
||||
<span>{currentProject?.name || "Projects"}</span>
|
||||
</button>
|
||||
{/* Right half: dropdown arrow (only when multiple projects) */}
|
||||
<div className="project-selector" ref={dropdownRef}>
|
||||
{/* Back to All Projects button - shown when a project is selected */}
|
||||
{currentProject && (
|
||||
<button
|
||||
className="header-back-button"
|
||||
onClick={onViewAll}
|
||||
title="Back to All Projects"
|
||||
data-testid="back-to-projects-btn"
|
||||
>
|
||||
<ChevronLeft size={14} />
|
||||
<span>Back to All Projects</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Project dropdown - shown when 2+ projects exist */}
|
||||
{projects.length > 1 && (
|
||||
<>
|
||||
<div className="split-project-btn__divider" />
|
||||
<button
|
||||
className={`split-project-btn__right${isOpen ? " split-project-btn__right--open" : ""}`}
|
||||
className={`project-selector-trigger${isOpen ? " project-selector-trigger--open" : ""}`}
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
title="Switch project"
|
||||
aria-label="Switch project"
|
||||
@@ -93,11 +95,11 @@ function SplitProjectButton({
|
||||
aria-haspopup="listbox"
|
||||
data-testid="project-selector-trigger"
|
||||
>
|
||||
<ChevronDown size={12} className={`split-project-btn__chevron${isOpen ? " split-project-btn__chevron--open" : ""}`} />
|
||||
<ChevronDown size={12} className={`project-selector-chevron${isOpen ? " project-selector-chevron--open" : ""}`} />
|
||||
</button>
|
||||
{isOpen && (
|
||||
<div
|
||||
className="split-project-btn__dropdown"
|
||||
className="project-selector-dropdown"
|
||||
role="listbox"
|
||||
aria-label="Select project"
|
||||
data-testid="project-selector-dropdown"
|
||||
@@ -108,22 +110,22 @@ function SplitProjectButton({
|
||||
return (
|
||||
<button
|
||||
key={project.id}
|
||||
className={`split-project-btn__item${isCurrent ? " split-project-btn__item--current" : ""}`}
|
||||
className={`project-selector-item${isCurrent ? " project-selector-item--current" : ""}`}
|
||||
onClick={() => handleSelectProject(project)}
|
||||
role="option"
|
||||
aria-selected={isCurrent}
|
||||
>
|
||||
<span
|
||||
className="split-project-btn__item-dot"
|
||||
className="project-selector-dot"
|
||||
style={{ backgroundColor: statusColor || "var(--text-muted)" }}
|
||||
/>
|
||||
<div className="split-project-btn__item-info">
|
||||
<span className="split-project-btn__item-name">{project.name}</span>
|
||||
<span className="split-project-btn__item-path">
|
||||
<div className="project-selector-info">
|
||||
<span className="project-selector-name">{project.name}</span>
|
||||
<span className="project-selector-path">
|
||||
{project.path.split("/").slice(-2).join("/")}
|
||||
</span>
|
||||
</div>
|
||||
{isCurrent && <Check size={14} className="split-project-btn__item-check" />}
|
||||
{isCurrent && <Check size={14} className="project-selector-check" />}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -436,9 +438,9 @@ export function Header({
|
||||
<h1 className="logo">Fusion</h1>
|
||||
</div>
|
||||
|
||||
{/* Split-button Project Selector - left: projects view, right: project dropdown (desktop only) */}
|
||||
{/* Project Selector - Back button when project selected, dropdown when 2+ projects (desktop only) */}
|
||||
{!isCompact && projects.length >= 1 && onViewAllProjects && (
|
||||
<SplitProjectButton
|
||||
<ProjectSelector
|
||||
projects={projects}
|
||||
currentProject={currentProject ?? null}
|
||||
onViewAll={onViewAllProjects}
|
||||
|
||||
@@ -837,7 +837,8 @@ describe("Header", () => {
|
||||
onViewAllProjects={vi.fn()}
|
||||
/>
|
||||
);
|
||||
expect(screen.queryByTestId("header-projects-btn")).toBeNull();
|
||||
// On mobile/tablet, back button is hidden (shown in overflow menu instead)
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows switch project item in overflow menu on mobile when multiple projects", () => {
|
||||
@@ -999,17 +1000,25 @@ describe("Header", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ── Split Project Button ────────────────────────────────────
|
||||
// ── Project Selector ────────────────────────────────────
|
||||
|
||||
it("shows split project button when 1+ projects provided with onViewAllProjects", () => {
|
||||
it("shows back to projects button when currentProject is set", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
render(<Header projects={projects} onViewAllProjects={vi.fn()} />);
|
||||
expect(screen.getByTestId("header-projects-btn")).toBeDefined();
|
||||
render(<Header projects={projects} currentProject={projects[0]} onViewAllProjects={vi.fn()} />);
|
||||
expect(screen.getByTestId("back-to-projects-btn")).toBeDefined();
|
||||
});
|
||||
|
||||
it("renders split project button within header-left when projects exist", () => {
|
||||
it("does not show back button when no currentProject", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
render(<Header projects={projects} currentProject={null} onViewAllProjects={vi.fn()} />);
|
||||
expect(screen.queryByTestId("back-to-projects-btn")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders project selector within header-left when projects exist", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
{ id: "proj_2", name: "Project Two", path: "/path/2", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
@@ -1022,25 +1031,25 @@ describe("Header", () => {
|
||||
onViewAllProjects={vi.fn()}
|
||||
/>
|
||||
);
|
||||
// SplitProjectButton should be inside header-left
|
||||
// ProjectSelector should be inside header-left
|
||||
const headerLeft = container.querySelector(".header-left");
|
||||
expect(headerLeft).not.toBeNull();
|
||||
const splitBtn = headerLeft!.querySelector(".split-project-btn");
|
||||
expect(splitBtn).not.toBeNull();
|
||||
expect(splitBtn!.querySelector("[data-testid='header-projects-btn']")).not.toBeNull();
|
||||
const projectSelector = headerLeft!.querySelector(".project-selector");
|
||||
expect(projectSelector).not.toBeNull();
|
||||
expect(projectSelector!.querySelector("[data-testid='back-to-projects-btn']")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("does not show split project button when no projects", () => {
|
||||
it("does not show project selector when no projects", () => {
|
||||
const { container } = render(<Header projects={[]} />);
|
||||
expect(container.querySelector(".split-project-btn")).toBeNull();
|
||||
expect(container.querySelector(".project-selector")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not show split project button without onViewAllProjects", () => {
|
||||
it("does not show project selector without onViewAllProjects", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
const { container } = render(<Header projects={projects} />);
|
||||
expect(container.querySelector(".split-project-btn")).toBeNull();
|
||||
expect(container.querySelector(".project-selector")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows project dropdown arrow only when 2+ projects", () => {
|
||||
@@ -1048,7 +1057,7 @@ describe("Header", () => {
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
{ id: "proj_2", name: "Project Two", path: "/path/2", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
render(<Header projects={projects} onViewAllProjects={vi.fn()} />);
|
||||
render(<Header projects={projects} currentProject={projects[0]} onViewAllProjects={vi.fn()} />);
|
||||
expect(screen.getByTestId("project-selector-trigger")).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -1056,11 +1065,11 @@ describe("Header", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
render(<Header projects={projects} onViewAllProjects={vi.fn()} />);
|
||||
render(<Header projects={projects} currentProject={projects[0]} onViewAllProjects={vi.fn()} />);
|
||||
expect(screen.queryByTestId("project-selector-trigger")).toBeNull();
|
||||
});
|
||||
|
||||
it("left button calls onViewAllProjects when clicked", () => {
|
||||
it("back button calls onViewAllProjects when clicked", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
{ id: "proj_2", name: "Project Two", path: "/path/2", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
@@ -1073,7 +1082,7 @@ describe("Header", () => {
|
||||
onViewAllProjects={onViewAllProjects}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(screen.getByTestId("header-projects-btn"));
|
||||
fireEvent.click(screen.getByTestId("back-to-projects-btn"));
|
||||
expect(onViewAllProjects).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1099,7 +1108,7 @@ describe("Header", () => {
|
||||
expect(onSelectProject).toHaveBeenCalledWith(projects[1]);
|
||||
});
|
||||
|
||||
it("shows current project name in left button", () => {
|
||||
it("shows 'Back to All Projects' text in back button", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
{ id: "proj_2", name: "Project Two", path: "/path/2", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
@@ -1113,25 +1122,9 @@ describe("Header", () => {
|
||||
/>
|
||||
);
|
||||
|
||||
// Left button should show current project name
|
||||
const leftBtn = screen.getByTestId("header-projects-btn");
|
||||
expect(leftBtn.textContent).toContain("Project One");
|
||||
});
|
||||
|
||||
it("shows 'Projects' label when no current project", () => {
|
||||
const projects = [
|
||||
{ id: "proj_1", name: "Project One", path: "/path/1", status: "active" as const, isolationMode: "in-process" as const, createdAt: "", updatedAt: "" },
|
||||
];
|
||||
render(
|
||||
<Header
|
||||
projects={projects}
|
||||
currentProject={null}
|
||||
onViewAllProjects={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
const leftBtn = screen.getByTestId("header-projects-btn");
|
||||
expect(leftBtn.textContent).toContain("Projects");
|
||||
// Back button should show "Back to All Projects"
|
||||
const backBtn = screen.getByTestId("back-to-projects-btn");
|
||||
expect(backBtn.textContent).toContain("Back to All Projects");
|
||||
});
|
||||
|
||||
// ── Modal Overlay Visibility ──────────────────────────────────
|
||||
|
||||
@@ -111,7 +111,7 @@ describe("MultiProjectFlow", () => {
|
||||
expect(storage[taskViewKey]).toBe("board");
|
||||
});
|
||||
|
||||
describe("Projects button navigation", () => {
|
||||
describe("Back to All Projects button navigation", () => {
|
||||
const singleProject: ProjectInfo = {
|
||||
id: "proj_1",
|
||||
name: "Solo Project",
|
||||
@@ -122,7 +122,7 @@ describe("MultiProjectFlow", () => {
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
};
|
||||
|
||||
it("shows Projects button and navigates to overview on click", () => {
|
||||
it("shows Back to All Projects button and navigates to overview on click", () => {
|
||||
mockDesktopMatchMedia();
|
||||
|
||||
let viewMode: "overview" | "project" = "project";
|
||||
@@ -139,21 +139,22 @@ describe("MultiProjectFlow", () => {
|
||||
onToggleGlobalPause={noop}
|
||||
onToggleEnginePause={noop}
|
||||
projects={[singleProject]}
|
||||
currentProject={singleProject}
|
||||
onViewAllProjects={handleViewAllProjects}
|
||||
/>
|
||||
);
|
||||
|
||||
// The Projects button should be visible for single-project users
|
||||
const projectsBtn = screen.getByTestId("header-projects-btn");
|
||||
expect(projectsBtn).toBeDefined();
|
||||
// The Back to All Projects button should be visible when currentProject is set
|
||||
const backBtn = screen.getByTestId("back-to-projects-btn");
|
||||
expect(backBtn).toBeDefined();
|
||||
|
||||
// Clicking should trigger navigation to overview
|
||||
fireEvent.click(projectsBtn);
|
||||
fireEvent.click(backBtn);
|
||||
expect(handleViewAllProjects).toHaveBeenCalled();
|
||||
expect(viewMode).toBe("overview");
|
||||
});
|
||||
|
||||
it("shows Projects button with current project name when currentProject is set", () => {
|
||||
it("shows Back to All Projects button text when currentProject is set", () => {
|
||||
mockDesktopMatchMedia();
|
||||
|
||||
render(
|
||||
@@ -170,10 +171,10 @@ describe("MultiProjectFlow", () => {
|
||||
/>
|
||||
);
|
||||
|
||||
// The split button should show the current project name
|
||||
const projectsBtn = screen.getByTestId("header-projects-btn");
|
||||
expect(projectsBtn).toBeDefined();
|
||||
expect(projectsBtn.textContent).toContain("Solo Project");
|
||||
// The back button should show "Back to All Projects"
|
||||
const backBtn = screen.getByTestId("back-to-projects-btn");
|
||||
expect(backBtn).toBeDefined();
|
||||
expect(backBtn.textContent).toContain("Back to All Projects");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6476,8 +6476,8 @@ body {
|
||||
padding-top: max(var(--space-md), env(safe-area-inset-top, 0px));
|
||||
}
|
||||
|
||||
/* Hide split project button on mobile (belt-and-suspenders with conditional rendering) */
|
||||
.split-project-btn {
|
||||
/* Hide project selector on mobile (belt-and-suspenders with conditional rendering) */
|
||||
.project-selector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -6947,8 +6947,8 @@ body {
|
||||
padding: var(--space-md) var(--space-lg);
|
||||
}
|
||||
|
||||
/* Hide split project button on tablet (controlled by React rendering too) */
|
||||
.split-project-btn {
|
||||
/* Hide project selector on tablet (controlled by React rendering too) */
|
||||
.project-selector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -18332,79 +18332,70 @@ html .column.drag-over * {
|
||||
}
|
||||
|
||||
/* === Split Project Button === */
|
||||
.split-project-btn {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: stretch;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
overflow: visible;
|
||||
transition: border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.split-project-btn:hover {
|
||||
border-color: var(--text-dim);
|
||||
}
|
||||
|
||||
.split-project-btn__left {
|
||||
/* === Header Back Button === */
|
||||
.header-back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 10px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), color var(--transition-fast);
|
||||
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
|
||||
white-space: nowrap;
|
||||
border-radius: var(--radius-md) 0 0 var(--radius-md);
|
||||
}
|
||||
|
||||
.split-project-btn__left:hover {
|
||||
.header-back-button:hover {
|
||||
background: var(--card-hover);
|
||||
color: var(--text);
|
||||
border-color: var(--text-dim);
|
||||
}
|
||||
|
||||
.split-project-btn__divider {
|
||||
width: 1px;
|
||||
background: var(--border);
|
||||
align-self: stretch;
|
||||
margin: 4px 0;
|
||||
/* === Project Selector === */
|
||||
.project-selector {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.split-project-btn__right {
|
||||
.project-selector-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px 6px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), color var(--transition-fast);
|
||||
border-radius: 0 var(--radius-md) var(--radius-md) 0;
|
||||
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.split-project-btn__right:hover {
|
||||
.project-selector-trigger:hover {
|
||||
background: var(--card-hover);
|
||||
color: var(--text);
|
||||
border-color: var(--text-dim);
|
||||
}
|
||||
|
||||
.split-project-btn__right--open {
|
||||
.project-selector-trigger--open {
|
||||
color: var(--text);
|
||||
border-color: var(--text-dim);
|
||||
}
|
||||
|
||||
.split-project-btn__chevron {
|
||||
.project-selector-chevron {
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.split-project-btn__chevron--open {
|
||||
.project-selector-chevron--open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.split-project-btn__dropdown {
|
||||
.project-selector-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 0;
|
||||
@@ -18418,7 +18409,7 @@ html .column.drag-over * {
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.split-project-btn__item {
|
||||
.project-selector-item {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -18434,22 +18425,22 @@ html .column.drag-over * {
|
||||
transition: background var(--transition-fast);
|
||||
}
|
||||
|
||||
.split-project-btn__item:hover {
|
||||
.project-selector-item:hover {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
.split-project-btn__item--current {
|
||||
.project-selector-item--current {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
.split-project-btn__item-dot {
|
||||
.project-selector-dot {
|
||||
flex-shrink: 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.split-project-btn__item-info {
|
||||
.project-selector-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
@@ -18457,14 +18448,14 @@ html .column.drag-over * {
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.split-project-btn__item-name {
|
||||
.project-selector-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.split-project-btn__item-path {
|
||||
.project-selector-path {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
overflow: hidden;
|
||||
@@ -18472,33 +18463,25 @@ html .column.drag-over * {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.split-project-btn__item-check {
|
||||
.project-selector-check {
|
||||
flex-shrink: 0;
|
||||
color: var(--todo);
|
||||
}
|
||||
|
||||
/* Light theme overrides for split project button */
|
||||
[data-theme="light"] .split-project-btn {
|
||||
/* Light theme overrides for project selector */
|
||||
[data-theme="light"] .project-selector-trigger:hover {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
[data-theme="light"] .project-selector-dropdown {
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
[data-theme="light"] .split-project-btn__left:hover {
|
||||
[data-theme="light"] .project-selector-item:hover {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
[data-theme="light"] .split-project-btn__right:hover {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
[data-theme="light"] .split-project-btn__dropdown {
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
[data-theme="light"] .split-project-btn__item:hover {
|
||||
background: var(--card-hover);
|
||||
}
|
||||
|
||||
[data-theme="light"] .split-project-btn__item--current {
|
||||
[data-theme="light"] .project-selector-item--current {
|
||||
background: rgba(88, 166, 255, 0.1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user