From 0b5fa75549840e900fcd63fd554bcc2a8c80670c Mon Sep 17 00:00:00 2001 From: Eduard Gert Date: Thu, 18 Jun 2026 13:11:08 +0200 Subject: [PATCH] lint and add frontend-ui workflow --- .github/workflows/frontend-ui.yml | 94 +++++++++++++++++++ client/ui/frontend/src/components/Badge.tsx | 2 +- .../src/components/CopyToClipboard.tsx | 10 +- .../frontend/src/components/DropdownMenu.tsx | 8 +- .../src/components/LanguagePicker.tsx | 42 +++++---- .../src/components/ManagementServerSwitch.tsx | 2 +- .../ui/frontend/src/components/SquareIcon.tsx | 2 +- .../frontend/src/components/VerticalTabs.tsx | 10 +- .../src/components/buttons/Button.tsx | 74 +++++++-------- .../src/components/buttons/IconButton.tsx | 6 +- .../src/components/dialog/ConfirmDialog.tsx | 6 +- .../frontend/src/components/dialog/Dialog.tsx | 17 ++-- .../src/components/dialog/DialogActions.tsx | 2 +- .../components/dialog/DialogDescription.tsx | 2 +- .../src/components/dialog/DialogHeading.tsx | 2 +- .../empty-state/DaemonOutdatedOverlay.tsx | 10 +- .../empty-state/DaemonUnavailableOverlay.tsx | 10 +- .../src/components/empty-state/EmptyState.tsx | 4 +- .../src/components/empty-state/NoResults.tsx | 2 +- .../empty-state/NotConnectedState.tsx | 2 +- .../frontend/src/components/inputs/Input.tsx | 60 ++++++------ .../src/components/inputs/SearchInput.tsx | 8 +- .../components/switches/FancyToggleSwitch.tsx | 10 +- .../components/switches/SwitchItemGroup.tsx | 4 +- .../src/components/switches/ToggleSwitch.tsx | 6 +- .../src/components/typography/HelpText.tsx | 4 +- .../src/components/typography/Label.tsx | 4 +- .../frontend/src/contexts/SettingsContext.tsx | 2 +- .../ui/frontend/src/layouts/AppRightPanel.tsx | 6 +- .../src/modules/auto-update/UpdateBadge.tsx | 4 +- .../modules/auto-update/UpdateVersionCard.tsx | 6 +- .../login/LoginWaitingForBrowserDialog.tsx | 4 +- .../main/MainConnectionStatusSwitch.tsx | 36 +++---- .../src/modules/main/MainExitNodeSwitcher.tsx | 38 ++++---- .../frontend/src/modules/main/MainHeader.tsx | 24 +++-- .../ui/frontend/src/modules/main/MainPage.tsx | 12 +-- .../src/modules/main/advanced/Navigation.tsx | 4 +- .../main/advanced/networks/NetworkFilters.tsx | 8 +- .../main/advanced/networks/Networks.tsx | 59 +++++++----- .../main/advanced/peers/PeerFilters.tsx | 8 +- .../src/modules/profiles/ProfileDropdown.tsx | 51 ++++++---- .../src/modules/profiles/ProfilesTab.tsx | 36 +++---- .../session/SessionExpirationDialog.tsx | 4 +- .../src/modules/settings/SettingsAbout.tsx | 32 +++++-- .../src/modules/settings/SettingsAccent.tsx | 2 +- .../src/modules/settings/SettingsGeneral.tsx | 4 +- .../modules/settings/SettingsNavigation.tsx | 2 +- .../src/modules/settings/SettingsPage.tsx | 12 ++- .../src/modules/settings/SettingsSSH.tsx | 6 +- .../src/modules/settings/SettingsSection.tsx | 10 +- .../src/modules/settings/SettingsSkeleton.tsx | 2 +- .../settings/SettingsTroubleshooting.tsx | 28 +++--- .../src/modules/welcome/WelcomeStepTray.tsx | 4 +- 53 files changed, 499 insertions(+), 308 deletions(-) create mode 100644 .github/workflows/frontend-ui.yml diff --git a/.github/workflows/frontend-ui.yml b/.github/workflows/frontend-ui.yml new file mode 100644 index 000000000..1290abe8a --- /dev/null +++ b/.github/workflows/frontend-ui.yml @@ -0,0 +1,94 @@ +name: UI Frontend + +on: + pull_request: + paths: + - "client/ui/frontend/**" + - "client/ui/i18n/**" + - "client/ui/**/*.go" + - ".github/workflows/frontend-ui.yml" + push: + branches: + - main + paths: + - "client/ui/frontend/**" + - "client/ui/i18n/**" + - "client/ui/**/*.go" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }} + cancel-in-progress: true + +jobs: + lint-and-build: + name: Lint & Build + runs-on: ubuntu-latest + timeout-minutes: 15 + defaults: + run: + working-directory: client/ui/frontend + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Set up pnpm + uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 + with: + version: 11 + + # Bindings are generated by wails3 from the Go service definitions and + # are not checked in (see client/ui/frontend/bindings/). Without them, + # typecheck/build fail on missing module imports. + - name: Set up Go + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + with: + go-version-file: "go.mod" + cache: false + + - name: Install wails3 CLI + # Version derived from go.mod so the binding generator always matches + # the wails runtime the daemon links against. + working-directory: ${{ github.workspace }} + run: | + WAILS_VERSION=$(go list -m -f '{{.Version}}' github.com/wailsapp/wails/v3) + go install github.com/wailsapp/wails/v3/cmd/wails3@$WAILS_VERSION + + - name: Get pnpm store directory + id: pnpm-store + run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT" + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-store.outputs.path }} + key: ${{ runner.os }}-pnpm-${{ hashFiles('client/ui/frontend/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate Wails bindings + run: pnpm run bindings + + - name: ESLint + run: pnpm lint + + - name: Type-check + run: pnpm typecheck + + - name: Prettier check + run: pnpm format:check + + - name: Build + run: pnpm build diff --git a/client/ui/frontend/src/components/Badge.tsx b/client/ui/frontend/src/components/Badge.tsx index a87efadbc..5f0df23e4 100644 --- a/client/ui/frontend/src/components/Badge.tsx +++ b/client/ui/frontend/src/components/Badge.tsx @@ -28,7 +28,7 @@ export const Badge = forwardRef(function Badge( ref={ref} className={cn( "relative top-px inline-flex items-center gap-1 rounded-full px-1.5 py-[0.15rem]", - "text-[0.64rem] leading-none font-semibold shrink-0", + "shrink-0 text-[0.64rem] font-semibold leading-none", VARIANT_CLASSES[variant], className, )} diff --git a/client/ui/frontend/src/components/CopyToClipboard.tsx b/client/ui/frontend/src/components/CopyToClipboard.tsx index 9f5b928a9..1b2a87da4 100644 --- a/client/ui/frontend/src/components/CopyToClipboard.tsx +++ b/client/ui/frontend/src/components/CopyToClipboard.tsx @@ -76,14 +76,14 @@ export const CopyToClipboard = ({ aria-label={resolvedLabel} aria-live={"polite"} className={cn( - "inline-flex gap-2 items-center group/copy cursor-default wails-no-draggable text-left pointer-events-auto rounded-sm outline-none", + "group/copy wails-no-draggable pointer-events-auto inline-flex cursor-default items-center gap-2 rounded-sm text-left outline-none", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", className, )} > -
+
+
{t("settings.general.language.help")}
@@ -91,10 +91,10 @@ export function LanguagePicker() { aria-haspopup={"listbox"} aria-expanded={open} className={cn( - "inline-flex items-center gap-2 h-[40px] px-3 min-w-[240px]", + "inline-flex h-[40px] min-w-[240px] items-center gap-2 px-3", "rounded-md border bg-white dark:bg-nb-gray-900", "border-neutral-200 dark:border-nb-gray-700", - "text-xs font-semibold text-nb-gray-100 cursor-default outline-none", + "cursor-default text-xs font-semibold text-nb-gray-100 outline-none", "hover:border-nb-gray-600 data-[state=open]:border-nb-gray-600", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", "disabled:opacity-50", @@ -103,15 +103,15 @@ export function LanguagePicker() { - + {current ? labelFor(current) : "—"} @@ -122,7 +122,7 @@ export function LanguagePicker() { sideOffset={6} className={cn( "w-[var(--radix-popover-trigger-width)]", - "rounded-lg border border-nb-gray-850 bg-nb-gray-920 shadow-lg p-1 z-50", + "z-50 rounded-lg border border-nb-gray-850 bg-nb-gray-920 p-1 shadow-lg", "data-[side=bottom]:origin-top data-[side=top]:origin-bottom", "data-[state=open]:animate-in", "data-[state=open]:fade-in-0", @@ -142,12 +142,12 @@ export function LanguagePicker() {
- +
{t("settings.general.language.empty")}
@@ -180,17 +182,19 @@ export function LanguagePicker() { value={`${lang.displayName} ${lang.englishName} ${lang.code}`} onSelect={() => void select(lang.code)} className={cn( - "flex items-center gap-2 px-2 py-2 rounded-md cursor-default outline-none my-0.5", + "my-0.5 flex cursor-default items-center gap-2 rounded-md px-2 py-2 outline-none", "text-xs font-semibold text-nb-gray-200", "data-[selected=true]:bg-nb-gray-850 data-[selected=true]:text-nb-gray-50", )} > - + {labelFor(lang)} {checked && (
diff --git a/client/ui/frontend/src/components/ManagementServerSwitch.tsx b/client/ui/frontend/src/components/ManagementServerSwitch.tsx index c59b0a425..0083a767a 100644 --- a/client/ui/frontend/src/components/ManagementServerSwitch.tsx +++ b/client/ui/frontend/src/components/ManagementServerSwitch.tsx @@ -26,7 +26,7 @@ export const ManagementServerSwitch = ({ value, onChange, fullWidth = false }: P src={netbirdLogo} alt={""} aria-hidden={"true"} - className={"h-[0.8rem] aspect-[31/23] shrink-0"} + className={"aspect-[31/23] h-[0.8rem] shrink-0"} /> {t("settings.general.management.cloud")} diff --git a/client/ui/frontend/src/components/SquareIcon.tsx b/client/ui/frontend/src/components/SquareIcon.tsx index 0ae339694..e904d2de5 100644 --- a/client/ui/frontend/src/components/SquareIcon.tsx +++ b/client/ui/frontend/src/components/SquareIcon.tsx @@ -27,7 +27,7 @@ export const SquareIcon = ({
>( ); @@ -23,7 +23,7 @@ const List = forwardRef(function VerticalTab return ( ); @@ -44,7 +44,7 @@ const Trigger = forwardRef(function VerticalTab (function VerticalTab size={iconSize} aria-hidden={"true"} className={cn( - "shrink-0 ml-2 transition-colors duration-150", + "ml-2 shrink-0 transition-colors duration-150", "text-nb-gray-400 group-data-[state=active]:text-nb-gray-100", )} /> diff --git a/client/ui/frontend/src/components/buttons/Button.tsx b/client/ui/frontend/src/components/buttons/Button.tsx index 9b927a915..6b151c17b 100644 --- a/client/ui/frontend/src/components/buttons/Button.tsx +++ b/client/ui/frontend/src/components/buttons/Button.tsx @@ -16,88 +16,88 @@ interface ButtonProps extends ButtonHTMLAttributes, ButtonVar const buttonVariants = cva( [ "relative", - "text-sm focus:z-10 focus:ring-2 font-medium focus:outline-none whitespace-nowrap shadow-sm select-none cursor-default", - "inline-flex gap-2 items-center justify-center transition-colors focus:ring-offset-1", - "disabled:opacity-40 disabled:cursor-not-allowed disabled:dark:text-nb-gray-300 dark:ring-offset-neutral-950/50", + "cursor-default select-none whitespace-nowrap text-sm font-medium shadow-sm focus:z-10 focus:outline-none focus:ring-2", + "inline-flex items-center justify-center gap-2 transition-colors focus:ring-offset-1", + "disabled:cursor-not-allowed disabled:opacity-40 dark:ring-offset-neutral-950/50 disabled:dark:text-nb-gray-300", ], { variants: { variant: { default: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900", - "dark:focus:ring-zinc-800/50 dark:bg-nb-gray dark:text-gray-400 dark:border-gray-700/30 dark:hover:text-white dark:hover:bg-zinc-800/50", + "border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", + "dark:border-gray-700/30 dark:bg-nb-gray dark:text-gray-400 dark:hover:bg-zinc-800/50 dark:hover:text-white dark:focus:ring-zinc-800/50", ], primary: [ - "dark:focus:ring-netbird-600/50 dark:ring-offset-neutral-950/50 enabled:dark:bg-netbird disabled:dark:bg-nb-gray-900 dark:text-gray-100 enabled:dark:hover:text-white enabled:dark:hover:bg-netbird-500/80", - "enabled:bg-netbird enabled:text-white enabled:focus:ring-netbird-400/50 enabled:hover:bg-netbird-500", + "dark:text-gray-100 dark:ring-offset-neutral-950/50 dark:focus:ring-netbird-600/50 enabled:dark:bg-netbird enabled:dark:hover:bg-netbird-500/80 enabled:dark:hover:text-white disabled:dark:bg-nb-gray-900", + "enabled:bg-netbird enabled:text-white enabled:hover:bg-netbird-500 enabled:focus:ring-netbird-400/50", ], secondary: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900", + "border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", "dark:ring-offset-neutral-950/50 dark:focus:ring-neutral-500/20", - "dark:bg-nb-gray-920 dark:text-gray-400 dark:border-gray-700/40 dark:hover:text-white dark:hover:bg-nb-gray-910", + "dark:border-gray-700/40 dark:bg-nb-gray-920 dark:text-gray-400 dark:hover:bg-nb-gray-910 dark:hover:text-white", ], secondaryLighter: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900", + "border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", "dark:ring-offset-neutral-950/50 dark:focus:ring-neutral-500/20", - "dark:bg-nb-gray-900/70 dark:text-gray-400 dark:border-gray-700/70 dark:hover:text-white dark:hover:bg-nb-gray-800/60", + "dark:border-gray-700/70 dark:bg-nb-gray-900/70 dark:text-gray-400 dark:hover:bg-nb-gray-800/60 dark:hover:text-white", ], subtle: [ - "bg-nb-gray-50 hover:bg-nb-gray-100 focus:ring-nb-gray-200/60 border-nb-gray-200 text-nb-gray-900", + "border-nb-gray-200 bg-nb-gray-50 text-nb-gray-900 hover:bg-nb-gray-100 focus:ring-nb-gray-200/60", "dark:ring-offset-neutral-950/50 dark:focus:ring-nb-gray-200/40", - "dark:bg-nb-gray-50 dark:text-nb-gray-900 dark:border-nb-gray-200 dark:hover:bg-nb-gray-100 dark:hover:text-nb-gray-950", + "dark:border-nb-gray-200 dark:bg-nb-gray-50 dark:text-nb-gray-900 dark:hover:bg-nb-gray-100 dark:hover:text-nb-gray-950", ], input: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-neutral-200 text-gray-900", + "border-neutral-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", "dark:ring-offset-neutral-950/50 dark:focus:ring-neutral-500/20", - "dark:bg-nb-gray-900 dark:text-gray-400 dark:border-nb-gray-700 dark:hover:bg-nb-gray-900/80", + "dark:border-nb-gray-700 dark:bg-nb-gray-900 dark:text-gray-400 dark:hover:bg-nb-gray-900/80", ], dropdown: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-neutral-200 text-gray-900", + "border-neutral-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", "dark:ring-offset-neutral-950/50 dark:focus:ring-neutral-500/20", - "dark:bg-nb-gray-900/40 dark:text-gray-400 dark:border-nb-gray-900 dark:hover:bg-nb-gray-900/50", + "dark:border-nb-gray-900 dark:bg-nb-gray-900/40 dark:text-gray-400 dark:hover:bg-nb-gray-900/50", ], dotted: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900 border-dashed", + "border-dashed border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", "dark:ring-offset-neutral-950/50 dark:focus:ring-neutral-500/20", - "dark:bg-nb-gray-900/30 dark:text-gray-400 dark:border-gray-500/40 dark:hover:text-white dark:hover:bg-nb-gray-900/50", + "dark:border-gray-500/40 dark:bg-nb-gray-900/30 dark:text-gray-400 dark:hover:bg-nb-gray-900/50 dark:hover:text-white", ], tertiary: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900", - "dark:focus:ring-zinc-800/50 dark:bg-white dark:text-gray-800 dark:border-gray-700/40 dark:hover:bg-neutral-200 disabled:dark:bg-nb-gray-920 disabled:dark:text-nb-gray-300", + "border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", + "dark:border-gray-700/40 dark:bg-white dark:text-gray-800 dark:hover:bg-neutral-200 dark:focus:ring-zinc-800/50 disabled:dark:bg-nb-gray-920 disabled:dark:text-nb-gray-300", ], white: [ - "focus:ring-white/50 bg-white text-gray-800 border-white outline-none hover:bg-neutral-200 disabled:dark:bg-nb-gray-920 disabled:dark:text-nb-gray-300", - "disabled:dark:bg-nb-gray-900 disabled:dark:text-nb-gray-300 disabled:dark:border-nb-gray-900", + "border-white bg-white text-gray-800 outline-none hover:bg-neutral-200 focus:ring-white/50 disabled:dark:bg-nb-gray-920 disabled:dark:text-nb-gray-300", + "disabled:dark:border-nb-gray-900 disabled:dark:bg-nb-gray-900 disabled:dark:text-nb-gray-300", ], outline: [ - "bg-white hover:text-black focus:ring-zinc-200/50 hover:bg-gray-100 border-gray-200 text-gray-900", - "dark:focus:ring-zinc-800/50 dark:bg-transparent dark:text-netbird dark:border-netbird dark:hover:bg-nb-gray-900/30", + "border-gray-200 bg-white text-gray-900 hover:bg-gray-100 hover:text-black focus:ring-zinc-200/50", + "dark:border-netbird dark:bg-transparent dark:text-netbird dark:hover:bg-nb-gray-900/30 dark:focus:ring-zinc-800/50", ], "danger-outline": [ - "enabled:dark:focus:ring-red-800/20 enabled:dark:focus:bg-red-950/40 enabled:hover:dark:bg-red-950/50 enabled:dark:hover:border-red-800/50 dark:bg-transparent dark:text-red-500", + "dark:bg-transparent dark:text-red-500 enabled:dark:hover:border-red-800/50 enabled:hover:dark:bg-red-950/50 enabled:dark:focus:bg-red-950/40 enabled:dark:focus:ring-red-800/20", ], "danger-text": [ - "dark:bg-transparent dark:text-red-500 dark:hover:text-red-600 dark:border-transparent !px-0 !shadow-none !py-0 focus:ring-red-500/30 dark:ring-offset-neutral-950/50 rounded-sm", + "rounded-sm !px-0 !py-0 !shadow-none focus:ring-red-500/30 dark:border-transparent dark:bg-transparent dark:text-red-500 dark:ring-offset-neutral-950/50 dark:hover:text-red-600", ], "default-outline": [ "dark:ring-offset-nb-gray-950/50 dark:focus:ring-nb-gray-500/20", - "dark:bg-transparent dark:text-nb-gray-400 dark:border-transparent dark:hover:text-white dark:hover:bg-nb-gray-900/30 dark:hover:border-nb-gray-800/50", - "data-[state=open]:dark:text-white data-[state=open]:dark:bg-nb-gray-900/30 data-[state=open]:dark:border-nb-gray-800/50", + "dark:border-transparent dark:bg-transparent dark:text-nb-gray-400 dark:hover:border-nb-gray-800/50 dark:hover:bg-nb-gray-900/30 dark:hover:text-white", + "data-[state=open]:dark:border-nb-gray-800/50 data-[state=open]:dark:bg-nb-gray-900/30 data-[state=open]:dark:text-white", ], ghost: [ "dark:ring-offset-nb-gray-950/50 dark:focus:ring-nb-gray-500/20", - "dark:bg-transparent dark:text-nb-gray-400 dark:border-transparent dark:hover:text-white dark:hover:bg-nb-gray-900/30", + "dark:border-transparent dark:bg-transparent dark:text-nb-gray-400 dark:hover:bg-nb-gray-900/30 dark:hover:text-white", ], danger: [ - "dark:focus:ring-red-700/20 dark:focus:bg-red-700 hover:dark:bg-red-700 dark:hover:border-red-800/50 dark:bg-red-600 dark:text-red-100", + "dark:bg-red-600 dark:text-red-100 dark:hover:border-red-800/50 hover:dark:bg-red-700 dark:focus:bg-red-700 dark:focus:ring-red-700/20", ], }, size: { - xs: "text-xs py-2.5 px-3.5", - xs2: "text-[0.78rem] py-[1.1rem] px-4 leading-[0]", - sm: "text-sm py-[9px] px-4", - md: "py-[9px] px-4", - lg: "text-lg py-[9px] px-4", + xs: "px-3.5 py-2.5 text-xs", + xs2: "px-4 py-[1.1rem] text-[0.78rem] leading-[0]", + sm: "px-4 py-[9px] text-sm", + md: "px-4 py-[9px]", + lg: "px-4 py-[9px] text-lg", }, rounded: { true: "rounded-md", @@ -106,7 +106,7 @@ const buttonVariants = cva( border: { 0: "border", 1: "border border-transparent", - 2: "border border-t-0 border-b-0", + 2: "border border-b-0 border-t-0", }, }, }, diff --git a/client/ui/frontend/src/components/buttons/IconButton.tsx b/client/ui/frontend/src/components/buttons/IconButton.tsx index 86e4a2de3..c91ef70e4 100644 --- a/client/ui/frontend/src/components/buttons/IconButton.tsx +++ b/client/ui/frontend/src/components/buttons/IconButton.tsx @@ -19,10 +19,10 @@ export const IconButton = forwardRef(function IconButt disabled={disabled} tabIndex={disabled ? -1 : 0} 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", + "flex h-10 w-10 cursor-default items-center justify-center rounded-lg outline-none", + "text-nb-gray-400 hover:bg-nb-gray-900 hover:text-nb-gray-300", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", - "transition-colors duration-150 wails-no-draggable", + "wails-no-draggable transition-colors duration-150", className, )} {...props} diff --git a/client/ui/frontend/src/components/dialog/ConfirmDialog.tsx b/client/ui/frontend/src/components/dialog/ConfirmDialog.tsx index 285af53cb..caf98c2c8 100644 --- a/client/ui/frontend/src/components/dialog/ConfirmDialog.tsx +++ b/client/ui/frontend/src/components/dialog/ConfirmDialog.tsx @@ -17,12 +17,14 @@ export const ConfirmDialog = forwardRef(func open aria-label={ariaLabel} aria-labelledby={ariaLabelledBy} - className={"wails-draggable select-none flex flex-col items-center static bg-transparent text-inherit p-0 m-0 max-w-none max-h-none border-0 w-full"} + className={ + "wails-draggable static m-0 flex max-h-none w-full max-w-none select-none flex-col items-center border-0 bg-transparent p-0 text-inherit" + } >
diff --git a/client/ui/frontend/src/components/dialog/Dialog.tsx b/client/ui/frontend/src/components/dialog/Dialog.tsx index 04b15ca26..fa8007d9f 100644 --- a/client/ui/frontend/src/components/dialog/Dialog.tsx +++ b/client/ui/frontend/src/components/dialog/Dialog.tsx @@ -1,4 +1,9 @@ -import { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes } from "react"; +import { + forwardRef, + type ComponentPropsWithoutRef, + type ElementRef, + type HTMLAttributes, +} from "react"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import { X } from "lucide-react"; @@ -60,9 +65,9 @@ export const Content = forwardRef, Co ); @@ -140,7 +145,7 @@ type FooterProps = HTMLAttributes & { }; export const Footer = ({ className, separator = true, ...props }: FooterProps) => ( -
+
( -
+
{children}
); diff --git a/client/ui/frontend/src/components/dialog/DialogDescription.tsx b/client/ui/frontend/src/components/dialog/DialogDescription.tsx index a645e364c..12c358043 100644 --- a/client/ui/frontend/src/components/dialog/DialogDescription.tsx +++ b/client/ui/frontend/src/components/dialog/DialogDescription.tsx @@ -20,7 +20,7 @@ export const DialogDescription = ({ className, align = "center", }: DialogDescriptionProps) => ( -

+

{children}

); diff --git a/client/ui/frontend/src/components/dialog/DialogHeading.tsx b/client/ui/frontend/src/components/dialog/DialogHeading.tsx index fccccef9c..b9dda72a9 100644 --- a/client/ui/frontend/src/components/dialog/DialogHeading.tsx +++ b/client/ui/frontend/src/components/dialog/DialogHeading.tsx @@ -25,7 +25,7 @@ export const DialogHeading = ({

{ return (
-
+
diff --git a/client/ui/frontend/src/components/empty-state/DaemonUnavailableOverlay.tsx b/client/ui/frontend/src/components/empty-state/DaemonUnavailableOverlay.tsx index 84a934fb4..89c121e21 100644 --- a/client/ui/frontend/src/components/empty-state/DaemonUnavailableOverlay.tsx +++ b/client/ui/frontend/src/components/empty-state/DaemonUnavailableOverlay.tsx @@ -18,11 +18,15 @@ export const DaemonUnavailableOverlay = () => { return (
-
+
diff --git a/client/ui/frontend/src/components/empty-state/EmptyState.tsx b/client/ui/frontend/src/components/empty-state/EmptyState.tsx index 817203149..7d6890a98 100644 --- a/client/ui/frontend/src/components/empty-state/EmptyState.tsx +++ b/client/ui/frontend/src/components/empty-state/EmptyState.tsx @@ -19,11 +19,11 @@ export const EmptyState = ({ icon, title, description, className }: Props) => { return (
-

{title}

+

{title}

{description &&

{description}

}
diff --git a/client/ui/frontend/src/components/empty-state/NoResults.tsx b/client/ui/frontend/src/components/empty-state/NoResults.tsx index 07a2f587b..cf0995b37 100644 --- a/client/ui/frontend/src/components/empty-state/NoResults.tsx +++ b/client/ui/frontend/src/components/empty-state/NoResults.tsx @@ -16,7 +16,7 @@ export const NoResults = ({ icon = FunnelXIcon, title, description }: Props) => icon={icon} title={title ?? t("common.noResults.title")} description={description ?? t("common.noResults.description")} - className={"relative -top-[3.8rem] pointer-events-none"} + className={"pointer-events-none relative -top-[3.8rem]"} /> ); }; diff --git a/client/ui/frontend/src/components/empty-state/NotConnectedState.tsx b/client/ui/frontend/src/components/empty-state/NotConnectedState.tsx index 229a33cd9..2bcf70376 100644 --- a/client/ui/frontend/src/components/empty-state/NotConnectedState.tsx +++ b/client/ui/frontend/src/components/empty-state/NotConnectedState.tsx @@ -5,7 +5,7 @@ import { EmptyState } from "./EmptyState"; export const NotConnectedState = () => { const { t } = useTranslation(); return ( -
+
@@ -138,7 +138,7 @@ function InputSuffixSlot({ return (
@@ -156,11 +156,11 @@ function NumberStepper({ return (
@@ -178,7 +180,7 @@ function NumberStepper({ aria-label={t("common.decrease")} onClick={() => onStep(-1)} className={cn( - "flex-1 flex items-center justify-center w-9 hover:bg-nb-gray-800 transition-colors text-nb-gray-300 cursor-default", + "flex w-9 flex-1 cursor-default items-center justify-center text-nb-gray-300 transition-colors hover:bg-nb-gray-800", "border-t border-neutral-200 dark:border-nb-gray-700", )} > @@ -193,7 +195,7 @@ function FieldMessage({ error, warning }: Readonly<{ error?: string; warning?: s return ( @@ -264,7 +266,7 @@ export const Input = forwardRef(function Input( diff --git a/client/ui/frontend/src/modules/login/LoginWaitingForBrowserDialog.tsx b/client/ui/frontend/src/modules/login/LoginWaitingForBrowserDialog.tsx index 9b426f717..efbd1ee84 100644 --- a/client/ui/frontend/src/modules/login/LoginWaitingForBrowserDialog.tsx +++ b/client/ui/frontend/src/modules/login/LoginWaitingForBrowserDialog.tsx @@ -65,7 +65,9 @@ export default function LoginWaitingForBrowserDialog() { type={"button"} onClick={tryAgain} disabled={!uri} - className={"wails-no-draggable text-netbird hover:underline disabled:opacity-40 disabled:cursor-not-allowed"} + className={ + "wails-no-draggable text-netbird hover:underline disabled:cursor-not-allowed disabled:opacity-40" + } > {t("browserLogin.tryAgain")} diff --git a/client/ui/frontend/src/modules/main/MainConnectionStatusSwitch.tsx b/client/ui/frontend/src/modules/main/MainConnectionStatusSwitch.tsx index e8b13f4ec..d6159a549 100644 --- a/client/ui/frontend/src/modules/main/MainConnectionStatusSwitch.tsx +++ b/client/ui/frontend/src/modules/main/MainConnectionStatusSwitch.tsx @@ -220,13 +220,13 @@ export const MainConnectionStatusSwitch = () => { return (
{"NetBird"} @@ -246,7 +246,9 @@ export const MainConnectionStatusSwitch = () => { id={"nb-connection-status"} role={"status"} aria-live={"polite"} - className={"text-sm font-medium text-nb-gray-200 tracking-wide transition-colors duration-300 select-none wails-no-draggable mb-1"} + className={ + "wails-no-draggable mb-1 select-none text-sm font-medium tracking-wide text-nb-gray-200 transition-colors duration-300" + } > {t(STATUS_KEY[connState])}

@@ -256,14 +258,16 @@ export const MainConnectionStatusSwitch = () => { iconClassName={"-top-px"} tabIndex={show && fqdn ? 0 : -1} className={cn( - "min-h-[1em] max-h-[1em] mt-1 transition-opacity duration-300 max-w-full", + "mt-1 max-h-[1em] min-h-[1em] max-w-full transition-opacity duration-300", "relative left-[0.55rem]", - show && fqdn ? "opacity-100" : "opacity-0 pointer-events-none", + show && fqdn ? "opacity-100" : "pointer-events-none opacity-0", )} > @@ -284,9 +288,9 @@ const LocalIpLine = ({ ip, ipv6, show }: { ip: string; ipv6: string; show: boole variant={"bright"} tabIndex={show && ip ? 0 : -1} className={cn( - "min-h-[1em] max-h-[1em] mt-1 transition-opacity duration-300", + "mt-1 max-h-[1em] min-h-[1em] transition-opacity duration-300", "relative left-[0.55rem]", - show && ip ? "opacity-100" : "opacity-0 pointer-events-none", + show && ip ? "opacity-100" : "pointer-events-none opacity-0", )} > @@ -299,9 +303,9 @@ const LocalIpLine = ({ ip, ipv6, show }: { ip: string; ipv6: string; show: boole return (
@@ -313,7 +317,7 @@ const LocalIpLine = ({ ip, ipv6, show }: { ip: string; ipv6: string; show: boole aria-haspopup={"dialog"} aria-expanded={open} className={cn( - "group relative inline-flex items-center outline-none cursor-default rounded-sm", + "group relative inline-flex cursor-default items-center rounded-sm outline-none", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", "transition-colors", )} @@ -348,7 +352,7 @@ const LocalIpLine = ({ ip, ipv6, show }: { ip: string; ipv6: string; show: boole className={cn( "z-50 min-w-64 max-w-[280px] overflow-hidden", "rounded-lg border border-nb-gray-900 bg-nb-gray-935", - "p-1 shadow-lg outline-none text-nb-gray-200", + "p-1 text-nb-gray-200 shadow-lg outline-none", "flex flex-col", )} > @@ -385,14 +389,14 @@ const IpRow = ({ value }: { value: string }) => { "group/iprow relative flex items-center justify-between gap-3", "rounded-md px-2 py-1.5 text-left", "text-nb-gray-200 hover:bg-nb-gray-900 hover:text-nb-gray-50", - "transition-colors outline-none cursor-default", + "cursor-default outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/60", )} > - {value} + {value} {copied ? : } diff --git a/client/ui/frontend/src/modules/main/MainExitNodeSwitcher.tsx b/client/ui/frontend/src/modules/main/MainExitNodeSwitcher.tsx index 05326e8d1..c0d763eac 100644 --- a/client/ui/frontend/src/modules/main/MainExitNodeSwitcher.tsx +++ b/client/ui/frontend/src/modules/main/MainExitNodeSwitcher.tsx @@ -78,7 +78,7 @@ export const MainExitNodeSwitcher = () => { }} style={{ width: "var(--radix-popover-trigger-width)" }} className={cn( - "z-50 overflow-hidden rounded-lg border border-nb-gray-900 bg-nb-gray-935 p-1 text-nb-gray-200 shadow-lg select-none wails-no-draggable", + "wails-no-draggable z-50 select-none overflow-hidden rounded-lg border border-nb-gray-900 bg-nb-gray-935 p-1 text-nb-gray-200 shadow-lg", "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", @@ -100,7 +100,7 @@ export const MainExitNodeSwitcher = () => { handleSelect(NONE_VALUE)} /> {hasAny &&
} {hasAny && ( - + {exitNodes.map((n) => ( { @@ -151,14 +153,14 @@ const ExitNodeTriggerCard = forwardRef( tabIndex={0} disabled={disabled} className={cn( - "w-full flex items-center gap-3 p-2.5 pr-5 rounded-xl outline-none text-left", + "flex w-full items-center gap-3 rounded-xl p-2.5 pr-5 text-left outline-none", "border border-nb-gray-920 bg-nb-gray-940", "transition-colors duration-150", "wails-no-draggable", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", disabled - ? "opacity-60 cursor-not-allowed" - : "cursor-default hover:bg-nb-gray-935 hover:border-nb-gray-900 data-[state=open]:bg-nb-gray-935 data-[state=open]:border-nb-gray-900", + ? "cursor-not-allowed opacity-60" + : "cursor-default hover:border-nb-gray-900 hover:bg-nb-gray-935 data-[state=open]:border-nb-gray-900 data-[state=open]:bg-nb-gray-935", className, )} {...props} @@ -166,7 +168,7 @@ const ExitNodeTriggerCard = forwardRef(
(
- + {title}
); @@ -205,13 +209,15 @@ const NoneRow = ({ isActive, onSelect }: NoneRowProps) => { value={NONE_VALUE} onSelect={onSelect} className={cn( - "flex gap-2 items-center px-2 py-2 pr-3", - "rounded-md outline-none cursor-default text-sm", + "flex items-center gap-2 px-2 py-2 pr-3", + "cursor-default rounded-md text-sm outline-none", "data-[selected=true]:bg-nb-gray-900", )} > {t("exitNodes.dropdown.noneTitle")} - {isActive && } + {isActive && ( + + )} ); }; @@ -228,8 +234,8 @@ const ExitNodeRow = ({ id, label, isActive, onSelect }: ExitNodeRowProps) => ( value={id} onSelect={onSelect} className={cn( - "flex gap-2 items-center px-2 py-2 pr-3", - "rounded-md outline-none cursor-default text-sm", + "flex items-center gap-2 px-2 py-2 pr-3", + "cursor-default rounded-md text-sm outline-none", "data-[selected=true]:bg-nb-gray-900", )} > diff --git a/client/ui/frontend/src/modules/main/MainHeader.tsx b/client/ui/frontend/src/modules/main/MainHeader.tsx index 5aa9c91f2..afe056ec4 100644 --- a/client/ui/frontend/src/modules/main/MainHeader.tsx +++ b/client/ui/frontend/src/modules/main/MainHeader.tsx @@ -82,7 +82,9 @@ export const MainHeader = () => { {updateAvailable && ( <> @@ -102,7 +104,7 @@ export const MainHeader = () => { )} -
+
{t("header.menu.settings")} @@ -132,10 +134,14 @@ export const MainHeader = () => { {updateAvailable && ( @@ -146,20 +152,20 @@ export const MainHeader = () => { return (
{/* Windows narrower width compensates for the OS frame Wails counts differently than macOS. See https://github.com/wailsapp/wails/issues/3260 */}
-
{profileSlot}
+
{profileSlot}
{settingsSlot}
@@ -176,7 +182,7 @@ type ViewModeItemProps = { const ViewModeItem = ({ icon: Icon, label, selected, onSelect }: ViewModeItemProps) => ( -
+
{label} {selected && } diff --git a/client/ui/frontend/src/modules/main/MainPage.tsx b/client/ui/frontend/src/modules/main/MainPage.tsx index d8ba85d35..c1330220d 100644 --- a/client/ui/frontend/src/modules/main/MainPage.tsx +++ b/client/ui/frontend/src/modules/main/MainPage.tsx @@ -44,18 +44,18 @@ const MainBody = () => { const isAdvanced = viewMode === "advanced"; return ( -
+
{/* Windows narrower width compensates for the OS frame Wails counts differently than macOS. See https://github.com/wailsapp/wails/issues/3260 */}
{!features.disableNetworks && ( -
+
)} @@ -88,7 +88,7 @@ const AdvancedAppRightPanel = () => { else el.setAttribute("inert", ""); }} className={cn( - "flex-1 min-h-0 min-w-0 flex flex-col", + "flex min-h-0 min-w-0 flex-1 flex-col", !isConnected && "pointer-events-none select-none", )} aria-hidden={!isConnected} @@ -98,14 +98,14 @@ const AdvancedAppRightPanel = () => { role={"tabpanel"} id={`nb-tabpanel-${section}`} aria-labelledby={`nb-tab-${section}`} - className={"flex-1 min-h-0 flex flex-col"} + className={"flex min-h-0 flex-1 flex-col"} > {section === "peers" && } {section === "networks" && }
{!isConnected && ( -
+
)} diff --git a/client/ui/frontend/src/modules/main/advanced/Navigation.tsx b/client/ui/frontend/src/modules/main/advanced/Navigation.tsx index bee324fdd..8d69f3580 100644 --- a/client/ui/frontend/src/modules/main/advanced/Navigation.tsx +++ b/client/ui/frontend/src/modules/main/advanced/Navigation.tsx @@ -79,7 +79,7 @@ export const Navigation = () => { role={"tablist"} aria-orientation={"horizontal"} aria-label={t("nav.peers.title")} - className={"wails-no-draggable shrink-0 flex items-stretch "} + className={"wails-no-draggable flex shrink-0 items-stretch"} > {tabs.map((tab, index) => { const isActive = tab.value === section; @@ -110,7 +110,7 @@ export const Navigation = () => { isLast && "rounded-tr-xl", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/60", isActive ? "text-netbird" : "text-nb-gray-400 hover:text-nb-gray-300", - isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-default", + isDisabled ? "cursor-not-allowed opacity-50" : "cursor-default", )} > diff --git a/client/ui/frontend/src/modules/main/advanced/networks/NetworkFilters.tsx b/client/ui/frontend/src/modules/main/advanced/networks/NetworkFilters.tsx index c301855f8..ec1823f0b 100644 --- a/client/ui/frontend/src/modules/main/advanced/networks/NetworkFilters.tsx +++ b/client/ui/frontend/src/modules/main/advanced/networks/NetworkFilters.tsx @@ -40,11 +40,11 @@ export const NetworkFilters = ({ value, onChange, counts, disabled }: Props) => tabIndex={0} aria-label={t("common.filter")} className={cn( - "inline-flex items-center gap-1.5 h-9 px-2 rounded-md", + "inline-flex h-9 items-center gap-1.5 rounded-md px-2", "text-sm text-nb-gray-200", - "outline-none hover:bg-nb-gray-900 data-[state=open]:bg-nb-gray-900 transition-colors duration-150", + "outline-none transition-colors duration-150 hover:bg-nb-gray-900 data-[state=open]:bg-nb-gray-900", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", - "disabled:opacity-50 disabled:pointer-events-none", + "disabled:pointer-events-none disabled:opacity-50", "wails-no-draggable cursor-default", )} > @@ -71,7 +71,7 @@ export const NetworkFilters = ({ value, onChange, counts, disabled }: Props) => {checked && } diff --git a/client/ui/frontend/src/modules/main/advanced/networks/Networks.tsx b/client/ui/frontend/src/modules/main/advanced/networks/Networks.tsx index 946bc7024..f6fe23aaf 100644 --- a/client/ui/frontend/src/modules/main/advanced/networks/Networks.tsx +++ b/client/ui/frontend/src/modules/main/advanced/networks/Networks.tsx @@ -160,9 +160,9 @@ export const Networks = () => { }; return ( -
-
-
+
+
+
{ {filtered.length === 0 ? ( ) : ( - + {scrollParent && ( { @@ -205,7 +207,7 @@ export const Networks = () => { "border-t border-nb-gray-910", )} > - + {t("networks.bulk.selectionCount", { selected: selectedInView, total: filtered.length, @@ -217,10 +219,10 @@ export const Networks = () => { onClick={onBulkClick} aria-label={t("networks.bulk.label")} className={cn( - "inline-flex items-center h-8 px-3 rounded-md", + "inline-flex h-8 items-center rounded-md px-3", "text-xs font-medium text-nb-gray-100", - "bg-nb-gray-920 hover:bg-nb-gray-910 border border-nb-gray-900 hover:border-nb-gray-850", - "transition-colors outline-none wails-no-draggable cursor-pointer", + "border border-nb-gray-900 bg-nb-gray-920 hover:border-nb-gray-850 hover:bg-nb-gray-910", + "wails-no-draggable cursor-pointer outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", )} > @@ -341,8 +343,8 @@ const NetworkRow = ({ network: n, index, onKeyDown, onToggle, setRowRef }: Netwo return (
@@ -361,19 +363,26 @@ const NetworkRow = ({ network: n, index, onKeyDown, onToggle, setRowRef }: Netwo />
-
+
@@ -386,8 +395,8 @@ const ResourceIconBadge = ({ type }: { type: ResourceType }) => {
@@ -413,7 +422,9 @@ const Subtitle = ({ network, onKeyDown }: SubtitleProps) => {
@@ -431,7 +442,7 @@ type DomainSubtitleProps = { const DomainSubtitle = ({ domain, ips, onKeyDown }: DomainSubtitleProps) => { const span = ( - + {domain} ); @@ -449,7 +460,7 @@ const DomainSubtitle = ({ domain, ips, onKeyDown }: DomainSubtitleProps) => { interactive keepOpenOnClick contentClassName={cn( - "max-w-[18rem] max-h-72 overflow-auto", + "max-h-72 max-w-[18rem] overflow-auto", "rounded-lg border border-nb-gray-900 bg-nb-gray-935", "p-2 pr-4", )} @@ -476,7 +487,9 @@ const ResolvedIpsTooltip = ({ ips }: { ips: string[] }) => {
  • {ip} @@ -498,8 +511,8 @@ const NetworkToggle = ({ checked, mixed }: ToggleProps) => { return ( { tabIndex={0} aria-label={t("common.filter")} className={cn( - "inline-flex items-center gap-1.5 h-9 px-2 rounded-md", + "inline-flex h-9 items-center gap-1.5 rounded-md px-2", "text-sm text-nb-gray-200", - "outline-none hover:bg-nb-gray-900 data-[state=open]:bg-nb-gray-900 transition-colors duration-150", + "outline-none transition-colors duration-150 hover:bg-nb-gray-900 data-[state=open]:bg-nb-gray-900", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", - "disabled:opacity-50 disabled:pointer-events-none", + "disabled:pointer-events-none disabled:opacity-50", "wails-no-draggable cursor-default", )} > @@ -71,7 +71,7 @@ export const PeerFilters = ({ value, onChange, counts, disabled }: Props) => { {checked && } diff --git a/client/ui/frontend/src/modules/profiles/ProfileDropdown.tsx b/client/ui/frontend/src/modules/profiles/ProfileDropdown.tsx index e11aa77b1..77ad08bcb 100644 --- a/client/ui/frontend/src/modules/profiles/ProfileDropdown.tsx +++ b/client/ui/frontend/src/modules/profiles/ProfileDropdown.tsx @@ -88,7 +88,7 @@ export const ProfileDropdown = ({ onManageProfiles }: ProfileDropdownProps) => { listRef.current?.focus(); }} className={cn( - "z-50 min-w-64 overflow-hidden rounded-lg border border-nb-gray-900 bg-nb-gray-935 p-1 text-nb-gray-200 shadow-lg select-none wails-no-draggable", + "wails-no-draggable z-50 min-w-64 select-none overflow-hidden rounded-lg border border-nb-gray-900 bg-nb-gray-935 p-1 text-nb-gray-200 shadow-lg", "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", @@ -111,7 +111,10 @@ export const ProfileDropdown = ({ onManageProfiles }: ProfileDropdownProps) => { > {sortedProfiles.length > 0 && ( <> - + {sortedProfiles.map((profile) => ( { - +
    @@ -143,13 +150,17 @@ export const ProfileDropdown = ({ onManageProfiles }: ProfileDropdownProps) => { disabled={!onManageProfiles} className={cn( "flex items-center gap-2 px-2 py-1.5", - "rounded-md outline-none cursor-default text-sm", + "cursor-default rounded-md text-sm outline-none", "data-[selected=true]:bg-nb-gray-900", - "data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none", + "data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50", )} > - - + + {t("profile.dropdown.manageProfiles")} @@ -167,13 +178,13 @@ const ProfileTriggerSkeleton = () => ( role={"status"} aria-busy={"true"} aria-live={"polite"} - className={"h-10 flex items-center gap-2 px-3 rounded-lg select-none wails-no-draggable"} + className={"wails-no-draggable flex h-10 select-none items-center gap-2 rounded-lg px-3"} >
    -
    +
    ); @@ -194,12 +205,12 @@ const ProfileTriggerButton = forwardRef - + {name} ); @@ -235,13 +246,13 @@ const ProfileRow = ({ profile, isActive, onSelect }: ProfileRowProps) => { value={profile.id} onSelect={() => onSelect(profile.id)} className={cn( - "flex gap-2 px-2 py-2 pr-3 w-auto last:mb-1", - "rounded-md outline-none cursor-default text-sm", + "flex w-auto gap-2 px-2 py-2 pr-3 last:mb-1", + "cursor-default rounded-md text-sm outline-none", "data-[selected=true]:bg-nb-gray-900", showEmail ? "items-start" : "items-center", )} > -
    +
    {profile.name} {showEmail && }
    @@ -267,7 +278,7 @@ const TruncatedEmail = ({ email }: { email: string }) => { }, [email]); const span = ( - + {email} ); diff --git a/client/ui/frontend/src/modules/profiles/ProfilesTab.tsx b/client/ui/frontend/src/modules/profiles/ProfilesTab.tsx index ccd970c46..b6c5c50e3 100644 --- a/client/ui/frontend/src/modules/profiles/ProfilesTab.tsx +++ b/client/ui/frontend/src/modules/profiles/ProfilesTab.tsx @@ -125,7 +125,7 @@ export function ProfilesTab() {

    {t("settings.profiles.emptyTitle")}

    -

    +

    {t("settings.profiles.emptyDescription")}

    @@ -271,7 +273,7 @@ const ProfilesTable = ({ return ( {ordered.map((profile, index) => ( @@ -347,19 +349,21 @@ const ProfileRow = ({ >
    -
    -
    +
    +
    {profile.name} @@ -397,7 +401,7 @@ const TruncatedEmail = ({ email }: { email: string }) => { const span = ( {email} @@ -490,15 +494,15 @@ const ActionIconButton = ({ aria-disabled={disabled || undefined} tabIndex={hidden || !tabbable ? -1 : 0} className={cn( - "h-9 w-9 inline-flex items-center justify-center rounded-md cursor-default outline-none", + "inline-flex h-9 w-9 cursor-default items-center justify-center rounded-md outline-none", "transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", variant === "danger" - ? "text-nb-gray-400 hover:text-red-500 hover:bg-red-500/10" - : "text-nb-gray-400 hover:text-nb-gray-100 hover:bg-nb-gray-900", - hidden && "opacity-0 pointer-events-none", + ? "text-nb-gray-400 hover:bg-red-500/10 hover:text-red-500" + : "text-nb-gray-400 hover:bg-nb-gray-900 hover:text-nb-gray-100", + hidden && "pointer-events-none opacity-0", disabled && - "opacity-40 cursor-not-allowed hover:!text-nb-gray-400 hover:!bg-transparent", + "cursor-not-allowed opacity-40 hover:!bg-transparent hover:!text-nb-gray-400", )} > diff --git a/client/ui/frontend/src/modules/session/SessionExpirationDialog.tsx b/client/ui/frontend/src/modules/session/SessionExpirationDialog.tsx index 8cf6459ca..2ceb958d4 100644 --- a/client/ui/frontend/src/modules/session/SessionExpirationDialog.tsx +++ b/client/ui/frontend/src/modules/session/SessionExpirationDialog.tsx @@ -167,7 +167,9 @@ export default function SessionExpirationDialog() { {!expired && (
    {formatRemaining(remaining)} diff --git a/client/ui/frontend/src/modules/settings/SettingsAbout.tsx b/client/ui/frontend/src/modules/settings/SettingsAbout.tsx index e59a24e81..8ba1009ba 100644 --- a/client/ui/frontend/src/modules/settings/SettingsAbout.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsAbout.tsx @@ -8,14 +8,18 @@ import netbirdFull from "@/assets/logos/netbird-full.svg"; const GithubIcon = (props: SVGProps) => ( ); const SlackIcon = (props: SVGProps) => ( ); @@ -82,19 +86,23 @@ export function SettingsAbout() { return (
    {t("common.netbird")}
    -

    +

    {guiVersion === "development" ? ( {t("settings.about.guiName")}{" "} - + {t("settings.about.development")} @@ -118,7 +126,7 @@ export function SettingsAbout() { -

    +

    {t("settings.about.copyright", { year: new Date().getFullYear() })}

    openUrl(url)} - className={"inline-flex items-center gap-1.5 rounded-sm outline-none decoration-[0.5px] underline-offset-4 hover:text-nb-gray-100 hover:underline transition focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940"} + className={ + "inline-flex items-center gap-1.5 rounded-sm decoration-[0.5px] underline-offset-4 outline-none transition hover:text-nb-gray-100 hover:underline focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940" + } > {label} @@ -146,7 +156,9 @@ export function SettingsAbout() { type={"button"} tabIndex={0} onClick={() => openUrl(link.url)} - className={"rounded-sm outline-none decoration-[0.5px] underline-offset-4 hover:text-nb-gray-100 hover:underline transition focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940"} + className={ + "rounded-sm decoration-[0.5px] underline-offset-4 outline-none transition hover:text-nb-gray-100 hover:underline focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940" + } > {link.label} diff --git a/client/ui/frontend/src/modules/settings/SettingsAccent.tsx b/client/ui/frontend/src/modules/settings/SettingsAccent.tsx index 08e3eac97..b7d9c96c8 100644 --- a/client/ui/frontend/src/modules/settings/SettingsAccent.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsAccent.tsx @@ -108,7 +108,7 @@ function Accent({ onDone }: Readonly<{ onDone: () => void }>) { return (
    diff --git a/client/ui/frontend/src/modules/settings/SettingsGeneral.tsx b/client/ui/frontend/src/modules/settings/SettingsGeneral.tsx index 7c77a4fcc..05d40e15c 100644 --- a/client/ui/frontend/src/modules/settings/SettingsGeneral.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsGeneral.tsx @@ -63,7 +63,7 @@ export function SettingsGeneral() {
    -
    +
    @@ -72,7 +72,7 @@ export function SettingsGeneral() {
    {mode === ManagementMode.SelfHosted && ( -
    +
    { ) : undefined; return ( -
    +
    { return ( <> {isMacOS() ? ( -
    +
    ) : (
    )} @@ -95,10 +95,10 @@ export const SettingsPage = () => { -
    +
    {visibleTabs.map((tab) => ( {TAB_CONTENT[tab]} @@ -109,12 +109,14 @@ export const SettingsPage = () => { diff --git a/client/ui/frontend/src/modules/settings/SettingsSSH.tsx b/client/ui/frontend/src/modules/settings/SettingsSSH.tsx index 51e91330e..f18fd9493 100644 --- a/client/ui/frontend/src/modules/settings/SettingsSSH.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsSSH.tsx @@ -93,11 +93,11 @@ export function SettingsSSH() { />
    -
    +
    {t("settings.ssh.jwtTtl.help")}
    diff --git a/client/ui/frontend/src/modules/settings/SettingsSection.tsx b/client/ui/frontend/src/modules/settings/SettingsSection.tsx index b6fafe305..adba65cdc 100644 --- a/client/ui/frontend/src/modules/settings/SettingsSection.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsSection.tsx @@ -15,12 +15,12 @@ export const SectionGroup = ({ tabIndex={disabled ? -1 : 0} {...(disabled ? { inert: "" } : {})} className={cn( - "mb-8 last:mb-1 px-1 rounded-md outline-none", + "mb-8 rounded-md px-1 outline-none last:mb-1", "focus-visible:ring-2 focus-visible:ring-white/60 focus-visible:ring-offset-2 focus-visible:ring-offset-nb-gray-940", - disabled && "opacity-30 pointer-events-none", + disabled && "pointer-events-none opacity-30", )} > -

    +

    {title}

    {children}
    @@ -32,7 +32,9 @@ export const SettingsBottomBar = ({ children }: { children: ReactNode }) => (
    {children}
    diff --git a/client/ui/frontend/src/modules/settings/SettingsSkeleton.tsx b/client/ui/frontend/src/modules/settings/SettingsSkeleton.tsx index 4eb646ee8..afce192e6 100644 --- a/client/ui/frontend/src/modules/settings/SettingsSkeleton.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsSkeleton.tsx @@ -2,7 +2,7 @@ import Skeleton from "react-loading-skeleton"; export const SettingsSkeleton = () => { return ( -
    +
    diff --git a/client/ui/frontend/src/modules/settings/SettingsTroubleshooting.tsx b/client/ui/frontend/src/modules/settings/SettingsTroubleshooting.tsx index 0cbf6fcf8..991937719 100644 --- a/client/ui/frontend/src/modules/settings/SettingsTroubleshooting.tsx +++ b/client/ui/frontend/src/modules/settings/SettingsTroubleshooting.tsx @@ -94,10 +94,10 @@ export function SettingsTroubleshooting() { disabled={!capture} />
    -
    +
    @@ -136,7 +136,9 @@ export function SettingsTroubleshooting() { function CenteredPanel({ children }: Readonly<{ children: ReactNode }>) { return (
    {children}
    @@ -153,7 +155,7 @@ function ProgressSection({ -
    +
    {stageLabel(stage, t)} {t("settings.troubleshooting.progress.description")} @@ -162,7 +164,9 @@ function ProgressSection({ {stage.kind === "capturing" && (
    {formatRemaining(stage.remainingSec)} @@ -207,7 +211,7 @@ function DoneResult({ -
    +
    {showKey ? t("settings.troubleshooting.done.uploadedTitle") @@ -221,9 +225,7 @@ function DoneResult({ docs: ( { e.preventDefault(); Browser.OpenURL(SUPPORT_DOCS_URL).catch(() => @@ -244,7 +246,7 @@ function DoneResult({
    -
    +
    {showKey && } {result.path && !showKey && ( @@ -256,7 +258,7 @@ function DoneResult({