mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
feat(ui): add InfoTooltip and PresetSlider shared components
This commit is contained in:
34
src/shared/components/InfoTooltip.tsx
Normal file
34
src/shared/components/InfoTooltip.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/shared/utils/cn";
|
||||
|
||||
interface InfoTooltipProps {
|
||||
text: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function InfoTooltip({ text, className }: InfoTooltipProps) {
|
||||
return (
|
||||
<span className={cn("relative inline-flex group", className)}>
|
||||
<span
|
||||
className="material-symbols-outlined text-[16px] text-text-muted cursor-help"
|
||||
aria-label={text}
|
||||
>
|
||||
info
|
||||
</span>
|
||||
<span
|
||||
role="tooltip"
|
||||
className={cn(
|
||||
"absolute bottom-full left-1/2 -translate-x-1/2 mb-2",
|
||||
"px-2.5 py-1.5 text-xs font-medium text-white bg-gray-900/95 rounded-md shadow-lg",
|
||||
"whitespace-nowrap pointer-events-none",
|
||||
"border border-white/10",
|
||||
"opacity-0 group-hover:opacity-100 transition-opacity duration-150",
|
||||
"z-50"
|
||||
)}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
64
src/shared/components/PresetSlider.tsx
Normal file
64
src/shared/components/PresetSlider.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/shared/utils/cn";
|
||||
|
||||
interface PresetSliderProps {
|
||||
value: number;
|
||||
onChange: (value: number) => void;
|
||||
presets: { label: string; value: number }[];
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function PresetSlider({
|
||||
value,
|
||||
onChange,
|
||||
presets,
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
className,
|
||||
}: PresetSliderProps) {
|
||||
return (
|
||||
<div className={cn("flex flex-col gap-3", className)}>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{presets.map((preset) => (
|
||||
<button
|
||||
key={preset.value}
|
||||
type="button"
|
||||
onClick={() => onChange(preset.value)}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-xs font-medium rounded-full transition-colors",
|
||||
"border",
|
||||
value === preset.value
|
||||
? "bg-primary text-white border-primary"
|
||||
: "bg-transparent text-text-muted border-black/10 dark:border-white/10 hover:border-primary/30 hover:text-text-main"
|
||||
)}
|
||||
>
|
||||
{preset.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={value}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
className={cn(
|
||||
"w-full h-1.5 rounded-full appearance-none cursor-pointer",
|
||||
"bg-black/10 dark:bg-white/10",
|
||||
"accent-primary"
|
||||
)}
|
||||
/>
|
||||
<div className="flex justify-between text-[10px] text-text-muted">
|
||||
<span>{min}</span>
|
||||
<span className="font-medium text-text-main">{value}</span>
|
||||
<span>{max}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -33,6 +33,8 @@ export { default as NotificationToast } from "./NotificationToast";
|
||||
export { default as FilterBar } from "./FilterBar";
|
||||
export { default as ColumnToggle } from "./ColumnToggle";
|
||||
export { default as DataTable } from "./DataTable";
|
||||
export { default as InfoTooltip } from "./InfoTooltip";
|
||||
export { default as PresetSlider } from "./PresetSlider";
|
||||
|
||||
// Layouts
|
||||
export * from "./layouts";
|
||||
|
||||
Reference in New Issue
Block a user