mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-20 23:59:55 +00:00
add default and advanced view items into dropdown
This commit is contained in:
@@ -1,9 +1,8 @@
|
|||||||
import { ComponentType, forwardRef } from "react";
|
import { ButtonHTMLAttributes, ComponentType, forwardRef } from "react";
|
||||||
import { motion, HTMLMotionProps } from "framer-motion";
|
|
||||||
import { LucideProps } from "lucide-react";
|
import { LucideProps } from "lucide-react";
|
||||||
import { cn } from "@/lib/cn";
|
import { cn } from "@/lib/cn";
|
||||||
|
|
||||||
type Props = HTMLMotionProps<"button"> & {
|
type Props = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||||
icon: ComponentType<LucideProps>;
|
icon: ComponentType<LucideProps>;
|
||||||
iconSize?: number;
|
iconSize?: number;
|
||||||
iconClassName?: string;
|
iconClassName?: string;
|
||||||
@@ -14,10 +13,9 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
|
|||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<motion.button
|
<button
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type={type}
|
type={type}
|
||||||
whileTap={{ scale: 0.95 }}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-10 w-10 flex items-center justify-center rounded-lg cursor-default outline-none",
|
"h-10 w-10 flex items-center justify-center rounded-lg cursor-default outline-none",
|
||||||
"text-nb-gray-400 hover:text-nb-gray-300 hover:bg-nb-gray-900",
|
"text-nb-gray-400 hover:text-nb-gray-300 hover:bg-nb-gray-900",
|
||||||
@@ -27,6 +25,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<Icon size={iconSize} className={iconClassName} />
|
<Icon size={iconSize} className={iconClassName} />
|
||||||
</motion.button>
|
</button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -82,6 +82,10 @@
|
|||||||
"profile.dialog.submit": "Add Profile",
|
"profile.dialog.submit": "Add Profile",
|
||||||
"profile.dialog.required": "Please enter a profile name, e.g. Work, Home",
|
"profile.dialog.required": "Please enter a profile name, e.g. Work, Home",
|
||||||
|
|
||||||
|
"header.menu.settings": "Settings",
|
||||||
|
"header.menu.defaultView": "Default View",
|
||||||
|
"header.menu.advancedView": "Advanced View",
|
||||||
|
|
||||||
"profile.deregister.title": "Deregister Profile",
|
"profile.deregister.title": "Deregister Profile",
|
||||||
"profile.deregister.message": "Are you sure you want to deregister \"{name}\"? You will need to log in again to use it.",
|
"profile.deregister.message": "Are you sure you want to deregister \"{name}\"? You will need to log in again to use it.",
|
||||||
"profile.deregister.confirm": "Deregister",
|
"profile.deregister.confirm": "Deregister",
|
||||||
|
|||||||
@@ -1,14 +1,42 @@
|
|||||||
import { SettingsIcon } from "lucide-react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import {
|
||||||
|
Check,
|
||||||
|
MoreVertical,
|
||||||
|
PanelTop,
|
||||||
|
PanelsRightBottom,
|
||||||
|
Settings,
|
||||||
|
type LucideIcon,
|
||||||
|
} from "lucide-react";
|
||||||
import { WindowManager } from "@bindings/services";
|
import { WindowManager } from "@bindings/services";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/DropdownMenu";
|
||||||
import { IconButton } from "@/components/IconButton";
|
import { IconButton } from "@/components/IconButton";
|
||||||
import { ProfileDropdown } from "@/components/ProfileDropdown";
|
import { ProfileDropdown } from "@/components/ProfileDropdown";
|
||||||
import { cn } from "@/lib/cn";
|
import { cn } from "@/lib/cn";
|
||||||
|
|
||||||
|
type ViewMode = "default" | "advanced";
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
const [viewMode, setViewMode] = useState<ViewMode>("default");
|
||||||
|
|
||||||
const openSettings = () => {
|
const openSettings = () => {
|
||||||
|
setMenuOpen(false);
|
||||||
void WindowManager.OpenSettings().catch(() => {});
|
void WindowManager.OpenSettings().catch(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectMode = (mode: ViewMode) => {
|
||||||
|
setMenuOpen(false);
|
||||||
|
setViewMode(mode);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -23,12 +51,53 @@ export const Header = () => {
|
|||||||
<ProfileDropdown />
|
<ProfileDropdown />
|
||||||
</div>
|
</div>
|
||||||
<div className={"flex justify-end"}>
|
<div className={"flex justify-end"}>
|
||||||
|
<DropdownMenu modal={false} open={menuOpen} onOpenChange={setMenuOpen}>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={SettingsIcon}
|
icon={MoreVertical}
|
||||||
iconClassName={"text-nb-gray-200"}
|
iconClassName={"text-nb-gray-200"}
|
||||||
onClick={openSettings}
|
|
||||||
/>
|
/>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" sideOffset={8} className="min-w-52">
|
||||||
|
<DropdownMenuItem onClick={openSettings}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Settings size={14} />
|
||||||
|
{t("header.menu.settings")}
|
||||||
|
</div>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ViewModeItem
|
||||||
|
icon={PanelTop}
|
||||||
|
label={t("header.menu.defaultView")}
|
||||||
|
selected={viewMode === "default"}
|
||||||
|
onSelect={() => selectMode("default")}
|
||||||
|
/>
|
||||||
|
<ViewModeItem
|
||||||
|
icon={PanelsRightBottom}
|
||||||
|
label={t("header.menu.advancedView")}
|
||||||
|
selected={viewMode === "advanced"}
|
||||||
|
onSelect={() => selectMode("advanced")}
|
||||||
|
/>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ViewModeItemProps = {
|
||||||
|
icon: LucideIcon;
|
||||||
|
label: string;
|
||||||
|
selected: boolean;
|
||||||
|
onSelect: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ViewModeItem = ({ icon: Icon, label, selected, onSelect }: ViewModeItemProps) => (
|
||||||
|
<DropdownMenuItem onClick={onSelect}>
|
||||||
|
<div className="flex items-center gap-2 w-full">
|
||||||
|
<Icon size={14} />
|
||||||
|
<span className="flex-1">{label}</span>
|
||||||
|
{selected && <Check size={14} className="text-netbird" />}
|
||||||
|
</div>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
);
|
||||||
|
|||||||
@@ -169,8 +169,8 @@ func main() {
|
|||||||
|
|
||||||
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
|
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
|
||||||
Title: "NetBird",
|
Title: "NetBird",
|
||||||
Width: 310,
|
Width: 380,
|
||||||
Height: 420,
|
Height: 590,
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
BackgroundColour: application.NewRGB(24, 26, 29),
|
BackgroundColour: application.NewRGB(24, 26, 29),
|
||||||
URL: "/",
|
URL: "/",
|
||||||
|
|||||||
Reference in New Issue
Block a user