mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-21 08:09: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 { motion, HTMLMotionProps } from "framer-motion";
|
||||
import { ButtonHTMLAttributes, ComponentType, forwardRef } from "react";
|
||||
import { LucideProps } from "lucide-react";
|
||||
import { cn } from "@/lib/cn";
|
||||
|
||||
type Props = HTMLMotionProps<"button"> & {
|
||||
type Props = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
icon: ComponentType<LucideProps>;
|
||||
iconSize?: number;
|
||||
iconClassName?: string;
|
||||
@@ -14,10 +13,9 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
|
||||
ref,
|
||||
) {
|
||||
return (
|
||||
<motion.button
|
||||
<button
|
||||
ref={ref}
|
||||
type={type}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className={cn(
|
||||
"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",
|
||||
@@ -27,6 +25,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
|
||||
{...props}
|
||||
>
|
||||
<Icon size={iconSize} className={iconClassName} />
|
||||
</motion.button>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -82,6 +82,10 @@
|
||||
"profile.dialog.submit": "Add Profile",
|
||||
"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.message": "Are you sure you want to deregister \"{name}\"? You will need to log in again to use it.",
|
||||
"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 {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/DropdownMenu";
|
||||
import { IconButton } from "@/components/IconButton";
|
||||
import { ProfileDropdown } from "@/components/ProfileDropdown";
|
||||
import { cn } from "@/lib/cn";
|
||||
|
||||
type ViewMode = "default" | "advanced";
|
||||
|
||||
export const Header = () => {
|
||||
const { t } = useTranslation();
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [viewMode, setViewMode] = useState<ViewMode>("default");
|
||||
|
||||
const openSettings = () => {
|
||||
setMenuOpen(false);
|
||||
void WindowManager.OpenSettings().catch(() => {});
|
||||
};
|
||||
|
||||
const selectMode = (mode: ViewMode) => {
|
||||
setMenuOpen(false);
|
||||
setViewMode(mode);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -23,12 +51,53 @@ export const Header = () => {
|
||||
<ProfileDropdown />
|
||||
</div>
|
||||
<div className={"flex justify-end"}>
|
||||
<IconButton
|
||||
icon={SettingsIcon}
|
||||
iconClassName={"text-nb-gray-200"}
|
||||
onClick={openSettings}
|
||||
/>
|
||||
<DropdownMenu modal={false} open={menuOpen} onOpenChange={setMenuOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<IconButton
|
||||
icon={MoreVertical}
|
||||
iconClassName={"text-nb-gray-200"}
|
||||
/>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
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{
|
||||
Title: "NetBird",
|
||||
Width: 310,
|
||||
Height: 420,
|
||||
Width: 380,
|
||||
Height: 590,
|
||||
Hidden: true,
|
||||
BackgroundColour: application.NewRGB(24, 26, 29),
|
||||
URL: "/",
|
||||
|
||||
Reference in New Issue
Block a user