merge(frontend): fix #339 — renforce la couleur projet dans les onglets non sélectionnés, teinte 5% + hover thématisé (QA verte)
This commit is contained in:
@ -7,9 +7,15 @@
|
|||||||
|
|
||||||
import { cn } from "../lib/cn";
|
import { cn } from "../lib/cn";
|
||||||
import { IconButton } from "./IconButton";
|
import { IconButton } from "./IconButton";
|
||||||
import type { ReactNode } from "react";
|
import type { CSSProperties, ReactNode } from "react";
|
||||||
import { useI18n } from "@/i18n";
|
import { useI18n } from "@/i18n";
|
||||||
|
|
||||||
|
interface ThemedTabStyle extends CSSProperties {
|
||||||
|
"--tab-theme-active-bg": string;
|
||||||
|
"--tab-theme-inactive-bg": string;
|
||||||
|
"--tab-theme-hover-bg": string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TabItem {
|
export interface TabItem {
|
||||||
/** Stable id, returned by `onSelect`/`onClose`. */
|
/** Stable id, returned by `onSelect`/`onClose`. */
|
||||||
id: string;
|
id: string;
|
||||||
@ -44,22 +50,32 @@ export function Tabs({ items, value, onSelect, onClose, className }: TabsProps)
|
|||||||
>
|
>
|
||||||
{items.map((tab) => {
|
{items.map((tab) => {
|
||||||
const active = tab.id === value;
|
const active = tab.id === value;
|
||||||
|
const themedStyle: ThemedTabStyle | undefined = tab.themeColor
|
||||||
|
? {
|
||||||
|
"--tab-theme-active-bg": `color-mix(in srgb, var(--color-raised) 90%, ${tab.themeColor})`,
|
||||||
|
// 5% project colour is 25% stronger than the previous 4% tint.
|
||||||
|
"--tab-theme-inactive-bg": `color-mix(in srgb, var(--color-raised) 95%, ${tab.themeColor})`,
|
||||||
|
"--tab-theme-hover-bg": `color-mix(in srgb, var(--color-raised) 93%, ${tab.themeColor})`,
|
||||||
|
...(active ? { borderColor: tab.themeAccent ?? tab.themeColor } : {}),
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
style={
|
style={themedStyle}
|
||||||
tab.themeColor
|
|
||||||
? {
|
|
||||||
backgroundColor: `color-mix(in srgb, var(--color-raised) ${active ? 90 : 96}%, ${tab.themeColor})`,
|
|
||||||
...(active ? { borderColor: tab.themeAccent ?? tab.themeColor } : {}),
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex items-center gap-1 rounded-md border px-1 transition-colors",
|
"group flex items-center gap-1 rounded-md border px-1 transition-colors",
|
||||||
active
|
active
|
||||||
? "border-border-strong bg-raised"
|
? cn(
|
||||||
: "border-transparent hover:bg-raised",
|
"border-border-strong",
|
||||||
|
tab.themeColor ? "bg-[var(--tab-theme-active-bg)]" : "bg-raised",
|
||||||
|
)
|
||||||
|
: cn(
|
||||||
|
"border-transparent",
|
||||||
|
tab.themeColor
|
||||||
|
? "bg-[var(--tab-theme-inactive-bg)] hover:bg-[var(--tab-theme-hover-bg)]"
|
||||||
|
: "hover:bg-raised",
|
||||||
|
),
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -115,6 +115,35 @@ describe("Tabs", () => {
|
|||||||
fireEvent.click(screen.getByRole("button", { name: "fermer beta" }));
|
fireEvent.click(screen.getByRole("button", { name: "fermer beta" }));
|
||||||
expect(onClose).toHaveBeenCalledWith("b");
|
expect(onClose).toHaveBeenCalledWith("b");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps themed inactive, hover and active backgrounds visually ordered (#339)", () => {
|
||||||
|
render(
|
||||||
|
<Tabs
|
||||||
|
items={[
|
||||||
|
{ id: "a", label: "alpha", themeColor: "#AA3366", themeAccent: "#CC5588" },
|
||||||
|
{ id: "b", label: "beta", themeColor: "#22AA66", themeAccent: "#44CC88" },
|
||||||
|
]}
|
||||||
|
value="a"
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const active = screen.getByRole("tab", { name: "alpha" }).parentElement!;
|
||||||
|
const inactive = screen.getByRole("tab", { name: "beta" }).parentElement!;
|
||||||
|
|
||||||
|
expect(active.style.getPropertyValue("--tab-theme-active-bg"))
|
||||||
|
.toBe("color-mix(in srgb, var(--color-raised) 90%, #AA3366)");
|
||||||
|
expect(active.className).toContain("bg-[var(--tab-theme-active-bg)]");
|
||||||
|
expect(active.style.borderColor).toBe("rgb(204, 85, 136)");
|
||||||
|
|
||||||
|
expect(inactive.style.getPropertyValue("--tab-theme-inactive-bg"))
|
||||||
|
.toBe("color-mix(in srgb, var(--color-raised) 95%, #22AA66)");
|
||||||
|
expect(inactive.style.getPropertyValue("--tab-theme-hover-bg"))
|
||||||
|
.toBe("color-mix(in srgb, var(--color-raised) 93%, #22AA66)");
|
||||||
|
expect(inactive.className).toContain("bg-[var(--tab-theme-inactive-bg)]");
|
||||||
|
expect(inactive.className).toContain("hover:bg-[var(--tab-theme-hover-bg)]");
|
||||||
|
expect(inactive.style.borderColor).toBe("");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("SmallDropdown", () => {
|
describe("SmallDropdown", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user