mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-15 13:19:56 +00:00
wip
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import React from "react";
|
||||
import { HelpText } from "@/components/HelpText";
|
||||
import { Label } from "@/components/Label";
|
||||
import { ToggleSwitch } from "@/components/ToggleSwitch";
|
||||
import { cn } from "@/lib/cn";
|
||||
|
||||
interface Props {
|
||||
value: boolean;
|
||||
onChange: (value: boolean) => void;
|
||||
helpText?: React.ReactNode;
|
||||
label?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
dataCy?: string;
|
||||
className?: string;
|
||||
labelClassName?: string;
|
||||
textWrapperClassName?: string;
|
||||
}
|
||||
|
||||
export default function FancyToggleSwitch({
|
||||
value,
|
||||
onChange,
|
||||
helpText,
|
||||
label,
|
||||
children,
|
||||
disabled = false,
|
||||
dataCy,
|
||||
className,
|
||||
labelClassName,
|
||||
textWrapperClassName = "max-w-sm",
|
||||
}: Readonly<Props>) {
|
||||
const handleToggle = () => {
|
||||
if (disabled) return;
|
||||
onChange(!value);
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
||||
if (disabled) return;
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
handleToggle();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={handleToggle}
|
||||
onKeyDown={handleKeyDown}
|
||||
tabIndex={-1}
|
||||
role={"switch"}
|
||||
aria-checked={value}
|
||||
className={cn(
|
||||
"cursor-pointer transition-all duration-300 relative z-[1]",
|
||||
"inline-block text-left w-full",
|
||||
disabled && "opacity-50 pointer-events-none",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className={"flex justify-between gap-10"}>
|
||||
<div className={cn(textWrapperClassName)}>
|
||||
<Label className={labelClassName}>{label}</Label>
|
||||
<HelpText margin={false}>{helpText}</HelpText>
|
||||
</div>
|
||||
<div className={"mt-2 pr-1"}>
|
||||
<ToggleSwitch
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
dataCy={dataCy}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{children && value ? (
|
||||
<div className="mt-4" onClick={(e) => e.stopPropagation()}>
|
||||
{children}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ type Props = HTMLMotionProps<"button"> & {
|
||||
description?: string;
|
||||
active?: boolean;
|
||||
iconSize?: number;
|
||||
iconBackground?: boolean;
|
||||
};
|
||||
|
||||
export const NavItem = forwardRef<HTMLButtonElement, Props>(
|
||||
@@ -19,6 +20,7 @@ export const NavItem = forwardRef<HTMLButtonElement, Props>(
|
||||
description,
|
||||
active = false,
|
||||
iconSize = 15,
|
||||
iconBackground = true,
|
||||
className,
|
||||
type = "button",
|
||||
...props
|
||||
@@ -40,21 +42,33 @@ export const NavItem = forwardRef<HTMLButtonElement, Props>(
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"h-9 w-9 rounded-md flex items-center justify-center shrink-0",
|
||||
"transition-colors duration-150",
|
||||
active ? "bg-nb-gray-800" : "bg-nb-gray-920",
|
||||
)}
|
||||
>
|
||||
{iconBackground ? (
|
||||
<div
|
||||
className={cn(
|
||||
"h-9 w-9 rounded-md flex items-center justify-center shrink-0",
|
||||
"transition-colors duration-150",
|
||||
active ? "bg-nb-gray-800" : "bg-nb-gray-920",
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
size={iconSize}
|
||||
className={cn(
|
||||
"transition-colors duration-150",
|
||||
active
|
||||
? "text-nb-gray-200"
|
||||
: "text-nb-gray-400",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Icon
|
||||
size={iconSize}
|
||||
className={cn(
|
||||
"transition-colors duration-150",
|
||||
"shrink-0 ml-2 transition-colors duration-150",
|
||||
active ? "text-nb-gray-200" : "text-nb-gray-400",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={"min-w-0"}>
|
||||
<h2
|
||||
className={cn(
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export default function PlaceholderHeader() {
|
||||
return (
|
||||
<div
|
||||
className="h-[36px] shrink-0 cursor-default wails-draggable"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -124,9 +124,10 @@ export const ProfileSelector = ({ email = "" }: Props) => {
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
"h-7 w-7 flex items-center justify-center bg-nb-gray-900 rounded-md text-xs font-semibold"
|
||||
}
|
||||
className={cn(
|
||||
"flex items-center justify-center bg-nb-gray-900 rounded-md text-xs font-semibold",
|
||||
email ? "h-7 w-7" : "h-6 w-6",
|
||||
)}
|
||||
style={{ color: initialColor }}
|
||||
>
|
||||
{initial}
|
||||
|
||||
71
client/ui-wails/frontend/src/components/ToggleSwitch.tsx
Normal file
71
client/ui-wails/frontend/src/components/ToggleSwitch.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/cn";
|
||||
|
||||
type SwitchVariants = VariantProps<typeof switchVariants>;
|
||||
|
||||
const switchVariants = cva("", {
|
||||
variants: {
|
||||
size: {
|
||||
default: "h-[24px] w-[44px]",
|
||||
small: "h-[18px] w-[36px]",
|
||||
},
|
||||
variant: {
|
||||
default: [
|
||||
"dark:data-[state=checked]:bg-netbird dark:data-[state=unchecked]:bg-nb-gray-700",
|
||||
"data-[state=checked]:bg-neutral-900 data-[state=unchecked]:bg-neutral-200",
|
||||
],
|
||||
"red-green": [
|
||||
"dark:data-[state=checked]:bg-red-600 dark:data-[state=unchecked]:bg-nb-gray-700",
|
||||
"data-[state=checked]:bg-red-500 data-[state=unchecked]:bg-red-200",
|
||||
],
|
||||
red: [
|
||||
"dark:data-[state=checked]:bg-red-600 dark:data-[state=unchecked]:bg-nb-gray-700",
|
||||
"data-[state=checked]:bg-red-500 data-[state=unchecked]:bg-red-200",
|
||||
],
|
||||
},
|
||||
"thumb-size": {
|
||||
default: "h-5 w-5 data-[state=checked]:translate-x-5",
|
||||
small: "h-[14px] w-[14px] data-[state=checked]:translate-x-[17px]",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ToggleSwitch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> &
|
||||
SwitchVariants & { dataCy?: string }
|
||||
>(
|
||||
(
|
||||
{ className, size = "default", variant = "default", dataCy, ...props },
|
||||
ref,
|
||||
) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50 dark:focus-visible:ring-neutral-300 dark:focus-visible:ring-offset-neutral-950",
|
||||
className,
|
||||
switchVariants({ size, variant }),
|
||||
)}
|
||||
{...props}
|
||||
data-cy={dataCy}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
props.onClick?.(e);
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
switchVariants({ "thumb-size": size }),
|
||||
"pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0 dark:bg-white",
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
),
|
||||
);
|
||||
ToggleSwitch.displayName = SwitchPrimitives.Root.displayName;
|
||||
|
||||
export { ToggleSwitch };
|
||||
Reference in New Issue
Block a user