diff --git a/new-ui/package.json b/new-ui/package.json
index 9f1a1a99..c216d0f5 100644
--- a/new-ui/package.json
+++ b/new-ui/package.json
@@ -62,6 +62,6 @@
"stylelint-config-standard-scss": "^17.0.0",
"stylelint-scss": "^7.2.0",
"typescript": "~6.0.3",
- "vite": "^8.1.0"
+ "vite": "^8.1.1"
}
}
diff --git a/new-ui/pnpm-lock.yaml b/new-ui/pnpm-lock.yaml
index fa50734c..cdf8b658 100644
--- a/new-ui/pnpm-lock.yaml
+++ b/new-ui/pnpm-lock.yaml
@@ -31,7 +31,7 @@ importers:
version: 1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
'@tanstack/router-plugin':
specifier: ^1.168.18
- version: 1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(rolldown@1.1.3)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
+ version: 1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(rolldown@1.1.3)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
'@tauri-apps/api':
specifier: ^2.11.1
version: 2.11.1
@@ -116,7 +116,7 @@ importers:
devDependencies:
'@tanstack/devtools-vite':
specifier: ^0.8.1
- version: 0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
+ version: 0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
'@types/byte-size':
specifier: ^8.1.2
version: 8.1.2
@@ -131,7 +131,7 @@ importers:
version: 19.2.3(@types/react@19.2.17)
'@vitejs/plugin-react':
specifier: ^6.0.3
- version: 6.0.3(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
+ version: 6.0.3(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
autoprefixer:
specifier: ^10.5.2
version: 10.5.2(postcss@8.5.16)
@@ -151,8 +151,8 @@ importers:
specifier: ~6.0.3
version: 6.0.3
vite:
- specifier: ^8.1.0
- version: 8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
+ specifier: ^8.1.1
+ version: 8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
packages:
@@ -1025,8 +1025,8 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
- caniuse-lite@1.0.30001799:
- resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==}
+ caniuse-lite@1.0.30001800:
+ resolution: {integrity: sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==}
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -1133,8 +1133,8 @@ packages:
resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
engines: {node: '>=0.3.1'}
- electron-to-chromium@1.5.381:
- resolution: {integrity: sha512-n9Wa6yB+vDsGuA8AKbl/0z7HbvWqt5jxIdvr1IUicd0ryPrk7/xzwqLv8D9AbbvZ6avVNtXYLTfmgFHkwkyelg==}
+ electron-to-chromium@1.5.382:
+ resolution: {integrity: sha512-8ETaWbV6SZOrno+G93Ffd9ENsMtetqdnqj4nlfxFW90Sm5GgnuV28Kf62hqQVD6VUgzm7qFQKsTsAPmeUiU3Ug==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1994,8 +1994,8 @@ packages:
vfile@6.0.3:
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
- vite@8.1.0:
- resolution: {integrity: sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==}
+ vite@8.1.1:
+ resolution: {integrity: sha512-X/05/cT+VITy2AeDc1der6smvGWWREtL4hPbPTaVbjSBuuWkmNOjR6HP3NzqcQA2nF6VHGUPaFRJyft/2AE9Kg==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -2578,7 +2578,7 @@ snapshots:
'@tanstack/devtools-event-client@0.5.0': {}
- '@tanstack/devtools-vite@0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
+ '@tanstack/devtools-vite@0.8.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
dependencies:
'@tanstack/devtools-client': 0.0.8
'@tanstack/devtools-event-bus': 0.4.2
@@ -2587,7 +2587,7 @@ snapshots:
magic-string: 0.30.21
oxc-parser: 0.120.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
picomatch: 4.0.4
- vite: 8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
+ vite: 8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
transitivePeerDependencies:
- '@emnapi/core'
- '@emnapi/runtime'
@@ -2662,7 +2662,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(rolldown@1.1.3)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
+ '@tanstack/router-plugin@1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(rolldown@1.1.3)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
dependencies:
'@babel/core': 7.29.7
'@babel/template': 7.29.7
@@ -2671,11 +2671,11 @@ snapshots:
'@tanstack/router-generator': 1.167.17
'@tanstack/router-utils': 1.162.2
chokidar: 5.0.0
- unplugin: 3.3.0(rolldown@1.1.3)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
+ unplugin: 3.3.0(rolldown@1.1.3)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))
zod: 4.4.3
optionalDependencies:
'@tanstack/react-router': 1.170.16(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
- vite: 8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
+ vite: 8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
transitivePeerDependencies:
- '@farmfe/core'
- '@rspack/core'
@@ -2785,10 +2785,10 @@ snapshots:
'@ungap/structured-clone@1.3.2': {}
- '@vitejs/plugin-react@6.0.3(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
+ '@vitejs/plugin-react@6.0.3(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0))':
dependencies:
'@rolldown/pluginutils': 1.0.1
- vite: 8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
+ vite: 8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
ajv@8.20.0:
dependencies:
@@ -2814,7 +2814,7 @@ snapshots:
autoprefixer@10.5.2(postcss@8.5.16):
dependencies:
browserslist: 4.28.4
- caniuse-lite: 1.0.30001799
+ caniuse-lite: 1.0.30001800
fraction.js: 5.3.4
picocolors: 1.1.1
postcss: 8.5.16
@@ -2840,8 +2840,8 @@ snapshots:
browserslist@4.28.4:
dependencies:
baseline-browser-mapping: 2.10.40
- caniuse-lite: 1.0.30001799
- electron-to-chromium: 1.5.381
+ caniuse-lite: 1.0.30001800
+ electron-to-chromium: 1.5.382
node-releases: 2.0.50
update-browserslist-db: 1.2.3(browserslist@4.28.4)
@@ -2857,7 +2857,7 @@ snapshots:
callsites@3.1.0: {}
- caniuse-lite@1.0.30001799: {}
+ caniuse-lite@1.0.30001800: {}
ccount@2.0.1: {}
@@ -2935,7 +2935,7 @@ snapshots:
diff@8.0.4: {}
- electron-to-chromium@1.5.381: {}
+ electron-to-chromium@1.5.382: {}
emoji-regex@8.0.0: {}
@@ -3881,14 +3881,14 @@ snapshots:
unist-util-is: 6.0.1
unist-util-visit-parents: 6.0.2
- unplugin@3.3.0(rolldown@1.1.3)(vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)):
+ unplugin@3.3.0(rolldown@1.1.3)(vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)):
dependencies:
'@jridgewell/remapping': 2.3.5
picomatch: 4.0.4
webpack-virtual-modules: 0.6.2
optionalDependencies:
rolldown: 1.1.3
- vite: 8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
+ vite: 8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0)
update-browserslist-db@1.2.3(browserslist@4.28.4):
dependencies:
@@ -3912,7 +3912,7 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
- vite@8.1.0(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0):
+ vite@8.1.1(@types/node@26.0.1)(jiti@2.7.0)(sass@1.101.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
diff --git a/new-ui/src/app/App.tsx b/new-ui/src/app/App.tsx
index f73839e6..ec5f23f4 100644
--- a/new-ui/src/app/App.tsx
+++ b/new-ui/src/app/App.tsx
@@ -1,6 +1,7 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { RouterProvider } from '@tanstack/react-router';
import { MainBackground } from '../shared/components/MainBackground/MainBackground';
+import { WindowDecorations } from '../shared/components/WindowDecorations/WindowDecorations';
import { queryClient } from './query';
import { router } from './router';
@@ -8,6 +9,7 @@ function App() {
return (
+
diff --git a/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaEmail/ConnectModalMfaEmail.tsx b/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaEmail/ConnectModalMfaEmail.tsx
index a2e0399b..f17cf6ef 100644
--- a/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaEmail/ConnectModalMfaEmail.tsx
+++ b/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaEmail/ConnectModalMfaEmail.tsx
@@ -36,17 +36,22 @@ export const ConnectModalMfaEmail = () => {
const [emailCode, setEmailCode] = useState(null);
const [error, setError] = useState(null);
- const handleVerify = useCallback(() => {
- if (!isPresent(emailCode)) {
- setError('Enter code');
- return;
- }
- if (emailCode.length !== 6) {
- setError('6 digits are required');
- return;
- }
- verifyCode(emailCode);
- }, [emailCode, verifyCode]);
+ const handleVerify = useCallback(
+ (initCode?: string | null) => {
+ const codeToVerify = initCode ?? emailCode;
+
+ if (!isPresent(codeToVerify)) {
+ setError('Enter code');
+ return;
+ }
+ if (codeToVerify.length !== 6) {
+ setError('6 digits are required');
+ return;
+ }
+ verifyCode(codeToVerify);
+ },
+ [emailCode, verifyCode],
+ );
// biome-ignore lint/correctness/useExhaustiveDependencies: side effect of code input
useEffect(() => {
@@ -76,6 +81,9 @@ export const ConnectModalMfaEmail = () => {
value={emailCode}
onChange={setEmailCode}
error={startError ?? error}
+ onSuccessPaste={(value) => {
+ handleVerify(value);
+ }}
/>
diff --git a/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaTotp/ConnectModalMfaTotp.tsx b/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaTotp/ConnectModalMfaTotp.tsx
index 037d8a67..dba16211 100644
--- a/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaTotp/ConnectModalMfaTotp.tsx
+++ b/new-ui/src/pages/full/OverviewPage/components/ConnectModal/views/ConnectModalMfaTotp/ConnectModalMfaTotp.tsx
@@ -36,17 +36,21 @@ export const ConnectModalMfaTotp = () => {
const [totpCode, setTotpCode] = useState
(null);
const [error, setError] = useState(null);
- const handleVerify = useCallback(() => {
- if (!isPresent(totpCode)) {
- setError('Enter code');
- return;
- }
- if (totpCode.replaceAll(' ', '').length !== 6) {
- setError('6 digits are required');
- return;
- }
- verifyCode(totpCode);
- }, [totpCode, verifyCode]);
+ const handleVerify = useCallback(
+ (initCode?: string | null) => {
+ const codeToVerify = initCode ?? totpCode;
+ if (!isPresent(codeToVerify)) {
+ setError('Enter code');
+ return;
+ }
+ if (codeToVerify.replaceAll(' ', '').length !== 6) {
+ setError('6 digits are required');
+ return;
+ }
+ verifyCode(codeToVerify);
+ },
+ [totpCode, verifyCode],
+ );
// biome-ignore lint/correctness/useExhaustiveDependencies: side effect of code input
useEffect(() => {
@@ -74,8 +78,11 @@ export const ConnectModalMfaTotp = () => {
setTotpCode(val)}
error={startError ?? error}
+ onSuccessPaste={(value) => {
+ handleVerify(value);
+ }}
/>
{
handleVerify()}
loading={isVerifying}
disabled={isStarting}
/>
diff --git a/new-ui/src/shared/components/FloatingMenu/style.scss b/new-ui/src/shared/components/FloatingMenu/style.scss
index 05de2885..e3e69ee1 100644
--- a/new-ui/src/shared/components/FloatingMenu/style.scss
+++ b/new-ui/src/shared/components/FloatingMenu/style.scss
@@ -4,5 +4,5 @@
padding: 8px;
background-color: var(--c-saturated-dark-blue-60);
box-shadow: 0 4px 12px 0 rgb(0 0 0 / 7%);
- backdrop-filter: blur(4px);
+ backdrop-filter: blur(10px);
}
diff --git a/new-ui/src/shared/components/Menu/style.scss b/new-ui/src/shared/components/Menu/style.scss
index ec2776f5..e948189a 100644
--- a/new-ui/src/shared/components/Menu/style.scss
+++ b/new-ui/src/shared/components/Menu/style.scss
@@ -8,7 +8,7 @@
border: 0;
background-color: var(--c-saturated-dark-blue-60);
box-shadow: 0 4px 12px 0 rgb(0 0 0 / 7%);
- backdrop-filter: blur(4px);
+ backdrop-filter: blur(10px);
overflow: hidden auto;
z-index: 5;
diff --git a/new-ui/src/shared/components/ModalFoundation/style.scss b/new-ui/src/shared/components/ModalFoundation/style.scss
index 2224e38a..4bdf7e72 100644
--- a/new-ui/src/shared/components/ModalFoundation/style.scss
+++ b/new-ui/src/shared/components/ModalFoundation/style.scss
@@ -6,18 +6,22 @@
.backdrop {
position: fixed;
- inset: 0;
+ left: 0;
+ top: var(--window-decorations-height);
display: block;
content: ' ';
width: 100%;
- height: 100%;
+ height: calc(100dvh - var(--window-decorations-height));
z-index: 4;
}
.modal-positioner {
overflow: auto;
position: fixed;
- inset: 0;
+ left: 0;
+ top: var(--window-decorations-height);
+ width: 100%;
+ height: calc(100dvh - var(--window-decorations-height));
z-index: 4;
display: flex;
flex-flow: column;
diff --git a/new-ui/src/shared/components/OverviewLocationCard/OverviewLocationCard.tsx b/new-ui/src/shared/components/OverviewLocationCard/OverviewLocationCard.tsx
index 557f2ef5..961efa25 100644
--- a/new-ui/src/shared/components/OverviewLocationCard/OverviewLocationCard.tsx
+++ b/new-ui/src/shared/components/OverviewLocationCard/OverviewLocationCard.tsx
@@ -161,6 +161,7 @@ export const OverviewLocationCard = ({ location, instance }: Props) => {
view: ConnectModalView.MfaSettings,
location: location,
perviousView: null,
+ mfaMethod: location.mfa_method,
});
}
}}
diff --git a/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx b/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx
new file mode 100644
index 00000000..dd60b622
--- /dev/null
+++ b/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx
@@ -0,0 +1,159 @@
+import './style.scss';
+import { getCurrentWindow } from '@tauri-apps/api/window';
+import { type as getOsType } from '@tauri-apps/plugin-os';
+import clsx from 'clsx';
+import { useEffect, useState } from 'react';
+import { WindowId } from '../../consts';
+
+const osType = getOsType();
+
+const isWindows = osType === 'windows';
+const isMac = osType === 'macos';
+const osCheck = isWindows || isMac;
+
+const appWindow = getCurrentWindow();
+
+const isFullView = appWindow.label === WindowId.FullView;
+
+const decorationsHeight = 33;
+
+export const WindowDecorations = () => {
+ const [isMaximized, setIsMaximized] = useState(false);
+ const [isDecorated, setIsDecorated] = useState(true);
+
+ useEffect(() => {
+ void appWindow.isDecorated().then(setIsDecorated);
+ }, []);
+
+ useEffect(() => {
+ document.documentElement.style.setProperty(
+ '--window-decorations-height',
+ !isDecorated && isFullView && osCheck ? `${decorationsHeight}px` : '0',
+ );
+ }, [isDecorated]);
+
+ useEffect(() => {
+ if (!osCheck || !isFullView || isDecorated) return;
+
+ void appWindow.isMaximized().then(setIsMaximized);
+
+ const unlisten = appWindow.onResized(() => {
+ void appWindow.isMaximized().then(setIsMaximized);
+ });
+
+ return () => {
+ void unlisten.then((fn) => fn());
+ };
+ }, [isDecorated]);
+
+ if (isDecorated || !isFullView) {
+ return null;
+ }
+
+ return (
+
+
+
+
void appWindow.minimize()}
+ >
+
+
+
+ void (isMaximized ? appWindow.unmaximize() : appWindow.maximize())
+ }
+ >
+ {isMaximized && (
+
+ )}
+ {!isMaximized && (
+
+ )}
+
+
void appWindow.close()}
+ >
+
+
+
+
+ );
+};
diff --git a/new-ui/src/shared/components/WindowDecorations/style.scss b/new-ui/src/shared/components/WindowDecorations/style.scss
new file mode 100644
index 00000000..e5920f08
--- /dev/null
+++ b/new-ui/src/shared/components/WindowDecorations/style.scss
@@ -0,0 +1,75 @@
+#window-decorations {
+ --controls-display: none;
+
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
+ justify-content: flex-end;
+ width: 100%;
+ height: var(--window-decorations-height);
+ border-bottom: 1px solid var(--border-disabled);
+ box-sizing: border-box;
+
+ &.macos {
+ > .window-drag {
+ margin-left: 100px;
+ }
+ }
+
+ &.windows {
+ --controls-display: flex;
+ }
+
+ > .window-drag {
+ content: ' ';
+ display: flex;
+ flex: 1 1 auto;
+ flex-flow: row;
+ min-width: 0;
+ height: 100%;
+ }
+
+ > .window-controls {
+ display: var(--controls-display);
+ flex-flow: row nowrap;
+ }
+
+ button {
+ --bg: transparent;
+ --icon: var(--fg-white-80);
+
+ border: 0;
+ background-color: var(--bg);
+ width: 46px;
+ height: 32px;
+ display: inline-flex;
+ flex-flow: row nowrap;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+
+ @include animate(background-color);
+
+ &:not(.close):hover {
+ --bg: var(--bg-white-10);
+ --icon: var(--fg-white-100);
+ }
+
+ &.close:hover {
+ --bg: var(--bg-critical);
+ --icon: var(--fg-white-100);
+ }
+
+ &.minimize svg path {
+ stroke: var(--icon);
+ }
+
+ &.maximize svg rect {
+ stroke: var(--icon);
+ }
+
+ &.close svg path {
+ fill: var(--icon);
+ }
+ }
+}
diff --git a/new-ui/src/shared/components/wizard/WizardPage/style.scss b/new-ui/src/shared/components/wizard/WizardPage/style.scss
index a6b87db6..4d909fd7 100644
--- a/new-ui/src/shared/components/wizard/WizardPage/style.scss
+++ b/new-ui/src/shared/components/wizard/WizardPage/style.scss
@@ -1,7 +1,7 @@
.wizard-page {
--page-content-limit: 536px;
- height: 100dvh;
+ height: calc(100dvh - var(--window-decorations-height));
overflow-y: auto;
> .page-grid {
diff --git a/new-ui/src/shared/layouts/FullPageLayout/style.scss b/new-ui/src/shared/layouts/FullPageLayout/style.scss
index 9acccdcb..59e4fd14 100644
--- a/new-ui/src/shared/layouts/FullPageLayout/style.scss
+++ b/new-ui/src/shared/layouts/FullPageLayout/style.scss
@@ -2,7 +2,7 @@
display: grid;
grid-template-columns: 52px 1fr;
grid-template-rows: 50px 1fr;
- height: 100dvh;
+ height: calc(100dvh - var(--window-decorations-height));
overflow: hidden;
#window-header {
diff --git a/new-ui/src/shared/scss/_shared_tokens.scss b/new-ui/src/shared/scss/_shared_tokens.scss
index a46acbc6..70e43b41 100644
--- a/new-ui/src/shared/scss/_shared_tokens.scss
+++ b/new-ui/src/shared/scss/_shared_tokens.scss
@@ -21,6 +21,11 @@ $jetbrains:
#{$font-fallback};
/* stylelint-disable value-keyword-case */
:root {
+ // sizings
+ // set by WindowDecorations component via effect on window metadata
+ // --window-decorations-height: 33px;
+ --window-header-height: 50px;
+
// font settings
--font-family-title: #{$geist};
--font-family-body: #{$geist};
diff --git a/nix/package.nix b/nix/package.nix
index b7621cb2..f5d7c5c4 100644
--- a/nix/package.nix
+++ b/nix/package.nix
@@ -99,7 +99,7 @@
inherit version pnpm;
src = ../new-ui;
fetcherVersion = 3;
- hash = "sha256-Xi71thwlHXUSQYYIX62hLk3Sw5bEtRE28PJSLQaHJ8g=";
+ hash = "sha256-k2trjKO1SQB7VR2da2SwXk9D032bGQOcqcPXoBdC8hs=";
};
# Pre-build the new UI frontend so Tauri can serve it as WebviewUrl::App("compact/") and "full/".
diff --git a/src-tauri/.env b/src-tauri/.env
index 4303819c..b921a712 100644
--- a/src-tauri/.env
+++ b/src-tauri/.env
@@ -1 +1,3 @@
DATABASE_URL=sqlite:dev.db
+DEFGUARD_CLIENT_LOG_LEVEL="debug"
+DEFGUARD_CLIENT_DEV="1"
\ No newline at end of file
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json
index 853bdf68..0bc984fe 100644
--- a/src-tauri/capabilities/default.json
+++ b/src-tauri/capabilities/default.json
@@ -43,6 +43,7 @@
"core:window:allow-set-cursor-position",
"core:window:allow-set-ignore-cursor-events",
"core:window:allow-start-dragging",
+ "core:window:allow-toggle-maximize",
"core:webview:allow-print",
"deep-link:default",
"fs:default",
diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs
index 6e3e397f..5fb225d0 100644
--- a/src-tauri/src/commands.rs
+++ b/src-tauri/src/commands.rs
@@ -1131,10 +1131,10 @@ pub async fn delete_tunnel(tunnel_id: Id, handle: AppHandle) -> Result<(), Error
))
})?;
info!(
- "Network interface {} has been removed and the connection to tunnel {tunnel} has been \
+ "Network interface {} has been removed and the connection to tunnel {tunnel} has been \
closed.",
- connection.interface_name
- );
+ connection.interface_name
+ );
if let Some(post_down) = &tunnel.post_down {
debug!(
"Executing defined PostDown command after removing the interface {} for the \
diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs
index d8cebd5a..c880778f 100644
--- a/src-tauri/src/tray.rs
+++ b/src-tauri/src/tray.rs
@@ -303,7 +303,7 @@ pub async fn configure_tray_icon(app_handle: &AppHandle) -> Result<(), Error> {
.next()
.and_then(|w| w.theme().ok());
resource_str.push_str(match theme {
- Some(Theme::Dark) => "dark",
+ Some(Theme::Dark) => "white",
_ => "white",
});
}
diff --git a/src-tauri/src/window_manager/macos.rs b/src-tauri/src/window_manager/macos.rs
index aebb24a3..47eb2cc6 100644
--- a/src-tauri/src/window_manager/macos.rs
+++ b/src-tauri/src/window_manager/macos.rs
@@ -1,12 +1,17 @@
use objc2_app_kit::{NSWindow, NSWindowButton, NSWindowStyleMask};
+use objc2_foundation::NSPoint;
use tauri::{
AppHandle, LogicalPosition, LogicalSize, Manager, Monitor, Position, Runtime, WebviewWindow,
};
use crate::{appstate::AppState, window_manager::WINDOW_GAP};
-/// Enforce rounded window corners. Not yet available in Tauri.
-pub(crate) fn enable_rounded_corners(window: &WebviewWindow) -> Result<(), String> {
+const TRAFFIC_LIGHT_Y: f64 = 4.0;
+
+pub(crate) fn enable_rounded_corners(
+ window: &WebviewWindow,
+ enable_system_controls: bool,
+) -> Result<(), String> {
window
.with_webview(move |webview| {
let ns_window = unsafe { &*webview.ns_window().cast::() };
@@ -19,18 +24,28 @@ pub(crate) fn enable_rounded_corners(window: &WebviewWindow) -> R
ns_window.setStyleMask(style_mask);
ns_window.setTitlebarAppearsTransparent(true);
- // Hide the standard window buttons (close, minimize, zoom)
- if let Some(close_button) = ns_window.standardWindowButton(NSWindowButton::CloseButton)
- {
- close_button.setHidden(true);
- }
- if let Some(miniaturize_button) =
- ns_window.standardWindowButton(NSWindowButton::MiniaturizeButton)
- {
- miniaturize_button.setHidden(true);
- }
- if let Some(zoom_button) = ns_window.standardWindowButton(NSWindowButton::ZoomButton) {
- zoom_button.setHidden(true);
+ // Traffic light buttons, positioned 20px from left.
+ let buttons = [
+ (
+ ns_window.standardWindowButton(NSWindowButton::CloseButton),
+ 20.0,
+ ),
+ (
+ ns_window.standardWindowButton(NSWindowButton::MiniaturizeButton),
+ 40.0,
+ ),
+ (
+ ns_window.standardWindowButton(NSWindowButton::ZoomButton),
+ 60.0,
+ ),
+ ];
+ for (button, x) in buttons {
+ if let Some(btn) = button {
+ btn.setHidden(!enable_system_controls);
+ if enable_system_controls {
+ btn.setFrameOrigin(NSPoint::new(x, TRAFFIC_LIGHT_Y));
+ }
+ }
}
})
.map_err(|err| err.to_string())
diff --git a/src-tauri/src/window_manager/mod.rs b/src-tauri/src/window_manager/mod.rs
index d600f1c6..3ae52dd5 100644
--- a/src-tauri/src/window_manager/mod.rs
+++ b/src-tauri/src/window_manager/mod.rs
@@ -58,7 +58,7 @@ impl WindowManager {
let window = window.build()?;
#[cfg(target_os = "macos")]
- if let Err(err) = macos::enable_rounded_corners(&window) {
+ if let Err(err) = macos::enable_rounded_corners(&window, false) {
warn!("Failed to enable rounded corners on tray window: {err}");
}
@@ -66,13 +66,23 @@ impl WindowManager {
}
pub fn build_full_view_window(app: &AppHandle) -> tauri::Result {
- WebviewWindowBuilder::new(app, FULL_VIEW_WINDOW_ID, full_view_ui_url())
+ let window = WebviewWindowBuilder::new(app, FULL_VIEW_WINDOW_ID, full_view_ui_url())
.title(WINDOW_TITLE)
.inner_size(FULL_VIEW_WINDOW_WIDTH, FULL_VIEW_WINDOW_HEIGHT)
.min_inner_size(FULL_VIEW_WINDOW_WIDTH, FULL_VIEW_WINDOW_HEIGHT)
- .decorations(true)
- .visible(false)
- .build()
+ .decorations(cfg!(not(any(windows, target_os = "macos"))))
+ .visible(false);
+ #[cfg(target_os = "macos")]
+ let window = window.hidden_title(true);
+
+ let window = window.build()?;
+
+ #[cfg(target_os = "macos")]
+ if let Err(err) = macos::enable_rounded_corners(&window, true) {
+ warn!("Failed to enable rounded corners on full view window: {err}");
+ }
+
+ Ok(window)
}
}
diff --git a/src-tauri/tauri.local.conf.json b/src-tauri/tauri.local.conf.json
index 0176062c..b817d460 100644
--- a/src-tauri/tauri.local.conf.json
+++ b/src-tauri/tauri.local.conf.json
@@ -1,5 +1,9 @@
{
+ "build": {
+ "beforeBundleCommand": null
+ },
"bundle": {
+ "targets": ["msi"],
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": null,