Skip to content

Commit 4782d5e

Browse files
authored
Merge pull request #42 from T-DAT-902-Homepedia/feat/carte-control-panel
feat(webapp): redesign price map control panel
2 parents e5355da + 0ee7b9a commit 4782d5e

3 files changed

Lines changed: 333 additions & 154 deletions

File tree

src/components/ui/checkbox.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as React from "react"
2+
import { Check } from "lucide-react"
3+
import { Checkbox as CheckboxPrimitive } from "radix-ui"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
/** Case à cocher du design system : accent à l'état coché. */
8+
function Checkbox({
9+
className,
10+
...props
11+
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
12+
return (
13+
<CheckboxPrimitive.Root
14+
data-slot="checkbox"
15+
className={cn(
16+
"flex size-4 shrink-0 items-center justify-center rounded border border-input bg-background outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-accent data-[state=checked]:bg-accent",
17+
className
18+
)}
19+
{...props}
20+
>
21+
<CheckboxPrimitive.Indicator>
22+
<Check className="size-3 text-accent-foreground" />
23+
</CheckboxPrimitive.Indicator>
24+
</CheckboxPrimitive.Root>
25+
)
26+
}
27+
28+
export { Checkbox }
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import * as React from "react"
2+
import { ToggleGroup } from "radix-ui"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
export interface SegmentedItem<T extends string> {
7+
value: T
8+
label: string
9+
/** Icône optionnelle (dimensionnée par le contrôle, ~14px). */
10+
icon?: React.ReactNode
11+
/** Info-bulle native — utile pour expliquer un terme (« Choroplèthe »). */
12+
title?: string
13+
}
14+
15+
/**
16+
* Contrôle segmenté (choix exclusif, toujours une option active) basé sur
17+
* Radix ToggleGroup type="single" : sémantique radio (role, aria-checked)
18+
* et navigation clavier fournies par Radix.
19+
*/
20+
export function SegmentedControl<T extends string>({
21+
value,
22+
onValueChange,
23+
items,
24+
className,
25+
...props
26+
}: {
27+
value: T
28+
onValueChange: (value: T) => void
29+
items: SegmentedItem<T>[]
30+
/** Libellé accessible du groupe. */
31+
"aria-label": string
32+
className?: string
33+
}) {
34+
return (
35+
<ToggleGroup.Root
36+
type="single"
37+
value={value}
38+
// Piège Radix : re-cliquer l'option active émet "" (désélection).
39+
// On l'ignore pour garantir qu'une option reste toujours sélectionnée.
40+
onValueChange={(v) => {
41+
if (v) onValueChange(v as T)
42+
}}
43+
data-slot="segmented-control"
44+
className={cn(
45+
"flex w-full items-center gap-0.5 rounded-lg border border-input bg-muted/60 p-0.5",
46+
className
47+
)}
48+
{...props}
49+
>
50+
{items.map((item) => (
51+
<ToggleGroup.Item
52+
key={item.value}
53+
value={item.value}
54+
title={item.title}
55+
className="inline-flex h-6 flex-1 items-center justify-center gap-1 rounded-md px-1.5 text-xs font-medium whitespace-nowrap text-muted-foreground transition-colors outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:size-3.5 [&_svg]:shrink-0"
56+
>
57+
{item.icon}
58+
{item.label}
59+
</ToggleGroup.Item>
60+
))}
61+
</ToggleGroup.Root>
62+
)
63+
}

0 commit comments

Comments
 (0)