Custom Title Bar for Windows (#2455)

* added custom title bar for windows

* Hid tooltips

* fixed commentary

* removed unused export

* removed not needed classes

* removed class for testing

* Updated configuration for Tauri v2

* updated german locale

* refactor, added an native icon swap if window maximized/minimized

* cleaning up

* missed condition on overview page

* fixed formatting

* removed unused keys

---------

Co-authored-by: Utku <74243531+utkubakir@users.noreply.github.com>
This commit is contained in:
Artsiom Voitas 2024-05-09 19:13:40 +03:00 committed by GitHub
parent 45ff38ee16
commit 46f518ccdc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 115 additions and 43 deletions

View file

@ -16,6 +16,9 @@
"webview:allow-internal-toggle-devtools",
"os:allow-os-type",
"window:allow-start-dragging",
"dialog:allow-open"
"dialog:allow-open",
"window:allow-close",
"window:allow-minimize",
"window:allow-toggle-maximize"
]
}

View file

@ -281,7 +281,7 @@ async fn main() -> tauri::Result<()> {
});
#[cfg(target_os = "windows")]
window.set_decorations(true).unwrap();
window.set_decorations(false).unwrap();
#[cfg(target_os = "macos")]
{

View file

@ -1,11 +1,14 @@
import { Cards, Minus, Square, X } from '@phosphor-icons/react';
import { getCurrent, Window } from '@tauri-apps/api/window';
import clsx from 'clsx';
import { useLayoutEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
import { ModifierKeys, Popover, Tooltip, usePopover } from '@sd/ui';
import { useIsDark, useOperatingSystem } from '~/hooks';
import TopBarButton from './TopBarButton';
import TopBarMobile from './TopBarMobile';
const appWindow = new Window('main');
export interface ToolOption {
icon: JSX.Element | ((props: { triggerOpen: () => void }) => JSX.Element);
onClick?: () => void;
@ -56,6 +59,7 @@ export default ({ options }: TopBarChildrenProps) => {
/>
))
)}
{os === 'windows' && <WindowsControls windowSize={windowSize} />}
</div>
<TopBarMobile
toolOptions={options}
@ -170,3 +174,49 @@ function ToolGroup({
</div>
);
}
export function WindowsControls({ windowSize }: { windowSize: number }) {
const [maximized, setMaximized] = useState(false);
const getWindowState = useCallback(async () => {
const isMaximized = await getCurrent().isMaximized();
setMaximized(isMaximized);
}, []);
useEffect(() => {
getWindowState().catch(console.error);
}, [getWindowState, windowSize]);
return (
<div className="mx-1 hidden items-center xl:flex">
<TopBarButton
className="mx-2"
rounding="both"
active={false}
onClick={() => appWindow.minimize()}
>
<Minus weight="regular" className={clsx(TOP_BAR_ICON_STYLE)} />
</TopBarButton>
<TopBarButton
rounding="both"
className="mx-2"
active={false}
onClick={() => {
appWindow.toggleMaximize();
}}
>
{maximized ? (
<Cards weight="regular" className={clsx(TOP_BAR_ICON_STYLE)} />
) : (
<Square weight="regular" className={clsx(TOP_BAR_ICON_STYLE)} />
)}
</TopBarButton>
<TopBarButton
rounding="both"
className="mx-2 hover:bg-red-500 *:hover:text-white"
active={false}
onClick={() => appWindow.close()}
>
<X weight="regular" className={clsx(TOP_BAR_ICON_STYLE, 'hover:text-white')} />
</TopBarButton>
</div>
);
}

View file

@ -1,5 +1,6 @@
import { redirect } from 'react-router';
import { type RouteObject } from 'react-router-dom';
import { guessOperatingSystem } from '~/hooks';
import { Platform } from '~/util/Platform';
import { debugRoutes } from './debug';
@ -31,11 +32,23 @@ const explorerRoutes: RouteObject[] = [
{ path: 'saved-search/:id', lazy: () => import('./saved-search/$id') }
];
function loadTopBarRoutes() {
const os = guessOperatingSystem();
if (os === 'windows') {
return [
...explorerRoutes,
pageRoutes,
{ path: 'settings', lazy: () => import('./settings/Layout'), children: settingsRoutes },
{ path: 'debug', children: debugRoutes }
];
} else return [...explorerRoutes, pageRoutes];
}
// Routes that should render with the top bar - pretty much everything except
// 404 and settings
// 404 and settings, which are rendered only for Windows with top bar
const topBarRoutes: RouteObject = {
lazy: () => import('./TopBar/Layout'),
children: [...explorerRoutes, pageRoutes]
children: loadTopBarRoutes()
};
export default (platform: Platform) =>

View file

@ -1,13 +1,14 @@
import { Link } from 'react-router-dom';
import { useBridgeQuery, useLibraryQuery } from '@sd/client';
import { useLocale } from '~/hooks';
import { useLocale, useOperatingSystem } from '~/hooks';
import { useRouteTitle } from '~/hooks/useRouteTitle';
import { hardwareModelToIcon } from '~/util/hardware';
import { SearchContextProvider, useSearch, useSearchFromSearchParams } from '../search';
import { SearchContextProvider, useSearchFromSearchParams } from '../search';
import SearchBar from '../search/SearchBar';
import { AddLocationButton } from '../settings/library/locations/AddLocationButton';
import { TopBarPortal } from '../TopBar/Portal';
import TopBarOptions from '../TopBar/TopBarOptions';
import FileKindStatistics from './FileKindStats';
import OverviewSection from './Layout/Section';
import LibraryStatistics from './LibraryStats';
@ -16,6 +17,7 @@ import StatisticItem from './StatCard';
export const Component = () => {
useRouteTitle('Overview');
const os = useOperatingSystem();
const { t } = useLocale();
@ -40,35 +42,36 @@ export const Component = () => {
</div>
}
center={<SearchBar redirectToSearch />}
// right={
// <TopBarOptions
// options={[
// [
// {
// toolTipLabel: 'Spacedrop',
// onClick: () => {},
// icon: <Broadcast className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// },
// {
// toolTipLabel: 'Key Manager',
// onClick: () => {},
// icon: <Key className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// },
// {
// toolTipLabel: 'Overview Display Settings',
// onClick: () => {},
// icon: <SlidersHorizontal className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// }
// ]
// ]}
// />
// }
right={
os === 'windows' && <TopBarOptions />
// <TopBarOptions
// options={[
// [
// {
// toolTipLabel: 'Spacedrop',
// onClick: () => {},
// icon: <Broadcast className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// },
// {
// toolTipLabel: 'Key Manager',
// onClick: () => {},
// icon: <Key className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// },
// {
// toolTipLabel: 'Overview Display Settings',
// onClick: () => {},
// icon: <SlidersHorizontal className={TOP_BAR_ICON_STYLE} />,
// individual: true,
// showAtResolution: 'sm:flex'
// }
// ]
// ]}
// />
}
/>
<div className="mt-4 flex flex-col gap-3 pt-3">
<OverviewSection>

View file

@ -5,6 +5,8 @@ import { useOperatingSystem } from '~/hooks/useOperatingSystem';
import { useWindowState } from '~/hooks/useWindowState';
import DragRegion from '../../../components/DragRegion';
import { TopBarPortal } from '../TopBar/Portal';
import TopBarOptions from '../TopBar/TopBarOptions';
import Sidebar from './Sidebar';
export const Component = () => {
@ -14,7 +16,8 @@ export const Component = () => {
useRouteTitle('Settings');
return (
<div className="flex w-full flex-row bg-app">
<div className={`flex w-full flex-row bg-app ${os === 'windows' && 'mt-6'}`}>
{os === 'windows' && <TopBarPortal right={<TopBarOptions />} />}
<Sidebar />
<div className="relative w-full">
<Suspense>

View file

@ -49,7 +49,7 @@ export default () => {
sidebar.collapsed && os === 'macOS' && 'justify-end'
)}
>
<NavigationButtons />
{os !== 'windows' && <NavigationButtons />}
</div>
) : (
<div className="h-3" />

View file

@ -269,7 +269,7 @@
"full_reindex": "Поўнае пераіндэксаванне",
"full_reindex_info": "Выканайце поўнае паўторнае сканаванне гэтай лакацыі.",
"general": "Галоўнае",
"general_settings": "Асноўныя налады",
"general_settings": "Агульныя налады",
"general_settings_description": "Агульныя налады, што адносяцца да дадзенага кліента.",
"general_shortcut_description": "Агульныя спалучэнні клавіш",
"generatePreviewMedia_label": "Стварыце папярэдні прагляд медыяфайлаў для гэтай лакацыі",

View file

@ -50,7 +50,7 @@
"celcius": "Celsius",
"change": "Ändern",
"change_view_setting_description": "Ändere die Standard-Exploreransicht",
"changelog": "Änderungsprotokoll",
"changelog": "Änderungsverlauf",
"changelog_page_description": "Sehe, welche coolen neuen Funktionen wir machen",
"changelog_page_title": "Änderungsprotokoll",
"chapters": "Chapters",
@ -327,7 +327,7 @@
"key": "Schlüssel",
"key_manager": "Schlüsselverwaltung",
"key_manager_description": "Erstelle einen Verschlüsselungsschlüssel, mounten und unmounte deine Schlüssel, um Dateien entschlüsselt in Echtzeit zu sehen.",
"keybinds": "Tastenkombinationen",
"keybinds": "Tastenbelegung",
"keybinds_description": "Client-Tastenkombinationen anzeigen und verwalten",
"keys": "Schlüssel",
"kilometers": "Kilometer",
@ -618,7 +618,7 @@
"total_bytes_capacity_description": "Die Gesamtkapazität aller mit der Bibliothek verbundenen Knoten. Kann während Alpha falsche Werte anzeigen.",
"total_bytes_free": "Freier Speicherplatz",
"total_bytes_free_description": "Frei verfügbarer Speicherplatz auf allen mit der Bibliothek verbundenen Knoten.",
"total_bytes_used": "Genutzter Raum insgesamt",
"total_bytes_used": "Genutzter Raum",
"total_bytes_used_description": "Insgesamt belegter Speicherplatz auf allen mit der Bibliothek verbundenen Knoten.",
"trash": "Müll",
"type": "Typ",

View file

@ -376,7 +376,7 @@
"logging_in": "ログイン中...",
"logout": "ログアウト",
"manage_library": "ライブラリの設定",
"managed": "Managed",
"managed": "マネージド",
"media": "メディア",
"media_view": "メディアビュー",
"media_view_context": "メディア ビュー",