mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-21 16:36:50 +00:00
fix(ui): keep dialogs clear of window controls
This commit is contained in:
+7
-1
@@ -132,6 +132,10 @@ function App() {
|
|||||||
const { addToast } = useToast();
|
const { addToast } = useToast();
|
||||||
const isMacUserAgent = navigator.userAgent.includes('Mac');
|
const isMacUserAgent = navigator.userAgent.includes('Mac');
|
||||||
const usesCustomWindowControls = !isMacUserAgent && platform.os !== 'macos';
|
const usesCustomWindowControls = !isMacUserAgent && platform.os !== 'macos';
|
||||||
|
// Keep dialogs out of the titlebar area while platform detection is still
|
||||||
|
// resolving. The conservative fallback prevents a startup handoff from
|
||||||
|
// briefly rendering underneath native or custom window controls.
|
||||||
|
const hasWindowChrome = isMacUserAgent || ['macos', 'windows', 'linux', 'unknown'].includes(platform.os);
|
||||||
|
|
||||||
const acknowledgePairingTokenChange = () => {
|
const acknowledgePairingTokenChange = () => {
|
||||||
invoke('acknowledge_pairing_token_change').catch(error => {
|
invoke('acknowledge_pairing_token_change').catch(error => {
|
||||||
@@ -669,7 +673,9 @@ function App() {
|
|||||||
}, [coreReady]);
|
}, [coreReady]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app-shell flex h-screen w-screen overflow-hidden text-text-primary">
|
<div className={`app-shell flex h-screen w-screen overflow-hidden text-text-primary ${
|
||||||
|
hasWindowChrome ? 'app-shell--window-chrome' : ''
|
||||||
|
}`}>
|
||||||
{(platform.os === 'windows' || platform.os === 'linux') && <WindowControls />}
|
{(platform.os === 'windows' || platform.os === 'linux') && <WindowControls />}
|
||||||
<div
|
<div
|
||||||
className={`app-sidebar-shell relative z-20 shrink-0 transition-all duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${
|
className={`app-sidebar-shell relative z-20 shrink-0 transition-all duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ export const AddDownloadsModal = () => {
|
|||||||
const [speedLimitEnabled, setSpeedLimitEnabled] = useState(false);
|
const [speedLimitEnabled, setSpeedLimitEnabled] = useState(false);
|
||||||
const [speedLimit, setSpeedLimit] = useState('1024');
|
const [speedLimit, setSpeedLimit] = useState('1024');
|
||||||
const [freeSpace, setFreeSpace] = useState('Unknown');
|
const [freeSpace, setFreeSpace] = useState('Unknown');
|
||||||
|
const freeSpaceRequestRef = useRef(0);
|
||||||
|
|
||||||
const [useAuth, setUseAuth] = useState(false);
|
const [useAuth, setUseAuth] = useState(false);
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
@@ -156,6 +157,7 @@ export const AddDownloadsModal = () => {
|
|||||||
setPendingUseSharedDestination(false);
|
setPendingUseSharedDestination(false);
|
||||||
setPendingDestinationOverrides({});
|
setPendingDestinationOverrides({});
|
||||||
setConnections(perServerConnections);
|
setConnections(perServerConnections);
|
||||||
|
setFreeSpace('Unknown');
|
||||||
setSpeedLimitEnabled(false);
|
setSpeedLimitEnabled(false);
|
||||||
setSpeedLimit('1024');
|
setSpeedLimit('1024');
|
||||||
setUseAuth(false);
|
setUseAuth(false);
|
||||||
@@ -224,10 +226,20 @@ export const AddDownloadsModal = () => {
|
|||||||
}, [isQueueMenuOpen, showingDuplicates]);
|
}, [isQueueMenuOpen, showingDuplicates]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!saveLocation) return;
|
const requestId = ++freeSpaceRequestRef.current;
|
||||||
|
if (!isAddModalOpen || !saveLocation) return;
|
||||||
|
|
||||||
invoke('get_free_space', { path: saveLocation })
|
invoke('get_free_space', { path: saveLocation })
|
||||||
.then(space => setFreeSpace(space))
|
.then(space => {
|
||||||
.catch(() => setFreeSpace('Unknown'));
|
if (freeSpaceRequestRef.current === requestId) {
|
||||||
|
setFreeSpace(space);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (freeSpaceRequestRef.current === requestId) {
|
||||||
|
setFreeSpace('Unknown');
|
||||||
|
}
|
||||||
|
});
|
||||||
}, [saveLocation, isAddModalOpen]);
|
}, [saveLocation, isAddModalOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -826,7 +838,7 @@ export const AddDownloadsModal = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="app-modal-backdrop fixed inset-0 z-50 flex items-center justify-center">
|
<div className="app-modal-backdrop fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div className="app-modal add-download-modal w-[900px] h-[650px] flex flex-col overflow-hidden text-sm">
|
<div className="app-modal add-download-modal flex flex-col overflow-hidden text-sm">
|
||||||
|
|
||||||
{/* Main Content Split */}
|
{/* Main Content Split */}
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-1 overflow-hidden">
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ export const DeleteConfirmationModal: React.FC = () => {
|
|||||||
const handleDeleteFile = () => removeMany(true);
|
const handleDeleteFile = () => removeMany(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 animate-fade-in">
|
<div className="app-modal-backdrop fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||||
<div
|
<div
|
||||||
className="bg-bg-modal rounded-xl w-full max-w-md overflow-hidden flex flex-col shadow-2xl border border-border-modal scale-in"
|
className="window-safe-modal bg-bg-modal rounded-xl w-full max-w-md overflow-hidden flex flex-col shadow-2xl border border-border-modal scale-in"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div className="px-5 py-4 border-b border-border-modal flex items-center gap-3">
|
<div className="px-5 py-4 border-b border-border-modal flex items-center gap-3">
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ export const KeychainPermissionModal: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50 animate-fade-in">
|
<div className="app-modal-backdrop fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||||
<div
|
<div
|
||||||
className="bg-bg-modal rounded-xl w-full max-w-md overflow-hidden flex flex-col shadow-2xl border border-border-modal scale-in"
|
className="window-safe-modal bg-bg-modal rounded-xl w-full max-w-md overflow-hidden flex flex-col shadow-2xl border border-border-modal scale-in"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div className="px-5 py-4 border-b border-border-modal flex items-center gap-3">
|
<div className="px-5 py-4 border-b border-border-modal flex items-center gap-3">
|
||||||
@@ -68,7 +68,7 @@ export const KeychainPermissionModal: React.FC = () => {
|
|||||||
<h2 className="text-lg font-semibold text-text-primary m-0">Credential Storage Access Needed</h2>
|
<h2 className="text-lg font-semibold text-text-primary m-0">Credential Storage Access Needed</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-5 py-6 flex-1 text-sm text-text-secondary leading-relaxed space-y-4">
|
<div className="px-5 py-6 flex-1 min-h-0 overflow-y-auto text-sm text-text-secondary leading-relaxed space-y-4">
|
||||||
<p>
|
<p>
|
||||||
Firelink uses the browser extension to capture downloads. To keep the extension paired after restarts,
|
Firelink uses the browser extension to capture downloads. To keep the extension paired after restarts,
|
||||||
Firelink stores its pairing token in {storeName}.
|
Firelink stores its pairing token in {storeName}.
|
||||||
|
|||||||
@@ -496,6 +496,20 @@ html[data-list-density="relaxed"] {
|
|||||||
.app-modal-backdrop {
|
.app-modal-backdrop {
|
||||||
background: hsl(0 0% 0% / 0.2);
|
background: hsl(0 0% 0% / 0.2);
|
||||||
animation: fade-in 150ms ease-out;
|
animation: fade-in 150ms ease-out;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-shell--window-chrome .app-modal-backdrop {
|
||||||
|
padding-top: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-modal-backdrop > .app-modal,
|
||||||
|
.app-modal-backdrop > .window-safe-modal {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-modal {
|
.app-modal {
|
||||||
@@ -510,6 +524,10 @@ html[data-list-density="relaxed"] {
|
|||||||
|
|
||||||
/* Add Download window */
|
/* Add Download window */
|
||||||
.add-download-modal {
|
.add-download-modal {
|
||||||
|
width: min(900px, 100%);
|
||||||
|
height: min(650px, 100%);
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
--add-surface: hsl(var(--surface-raised) / 0.72);
|
--add-surface: hsl(var(--surface-raised) / 0.72);
|
||||||
--add-highlight: hsl(0 0% 100% / 0.08);
|
--add-highlight: hsl(0 0% 100% / 0.08);
|
||||||
background:
|
background:
|
||||||
@@ -525,12 +543,16 @@ html[data-list-density="relaxed"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.add-download-left {
|
.add-download-left {
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 18% 0%, hsl(var(--accent-color) / 0.055), transparent 34%),
|
radial-gradient(circle at 18% 0%, hsl(var(--accent-color) / 0.055), transparent 34%),
|
||||||
hsl(var(--main-bg) / 0.56);
|
hsl(var(--main-bg) / 0.56);
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-download-settings {
|
.add-download-settings {
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
background: hsl(var(--bg-modal) / 0.7);
|
background: hsl(var(--bg-modal) / 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user