mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 09:18:30 +02:00
HeaderSize as shared component
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -10309,6 +10309,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
"tauri-plugin-os",
|
||||||
"yaak-proxy",
|
"yaak-proxy",
|
||||||
"yaak-window",
|
"yaak-window",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { CountBadge } from '../core/CountBadge';
|
|||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { HStack } from '../core/Stacks';
|
import { HStack } from '../core/Stacks';
|
||||||
import { TabContent, type TabItem, Tabs } from '../core/Tabs/Tabs';
|
import { TabContent, type TabItem, Tabs } from '../core/Tabs/Tabs';
|
||||||
import { HeaderSize } from '../HeaderSize';
|
import { HeaderSize } from '@yaakapp-internal/ui';
|
||||||
import { SettingsCertificates } from './SettingsCertificates';
|
import { SettingsCertificates } from './SettingsCertificates';
|
||||||
import { SettingsGeneral } from './SettingsGeneral';
|
import { SettingsGeneral } from './SettingsGeneral';
|
||||||
import { SettingsHotkeys } from './SettingsHotkeys';
|
import { SettingsHotkeys } from './SettingsHotkeys';
|
||||||
@@ -77,6 +77,10 @@ export default function Settings({ hide }: Props) {
|
|||||||
onlyXWindowControl
|
onlyXWindowControl
|
||||||
size="md"
|
size="md"
|
||||||
className="x-theme-appHeader bg-surface text-text-subtle flex items-center justify-center border-b border-border-subtle text-sm font-semibold"
|
className="x-theme-appHeader bg-surface text-text-subtle flex items-center justify-center border-b border-border-subtle text-sm font-semibold"
|
||||||
|
osType={type()}
|
||||||
|
hideWindowControls={settings.hideWindowControls}
|
||||||
|
useNativeTitlebar={settings.useNativeTitlebar}
|
||||||
|
interfaceScale={settings.interfaceScale}
|
||||||
>
|
>
|
||||||
<HStack
|
<HStack
|
||||||
space={2}
|
space={2}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { workspacesAtom } from '@yaakapp-internal/models';
|
import { type } from '@tauri-apps/plugin-os';
|
||||||
|
import { settingsAtom, workspacesAtom } from '@yaakapp-internal/models';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import * as m from 'motion/react-m';
|
import * as m from 'motion/react-m';
|
||||||
@@ -39,7 +40,7 @@ import { HStack } from './core/Stacks';
|
|||||||
import { ErrorBoundary } from './ErrorBoundary';
|
import { ErrorBoundary } from './ErrorBoundary';
|
||||||
import { FolderLayout } from './FolderLayout';
|
import { FolderLayout } from './FolderLayout';
|
||||||
import { GrpcConnectionLayout } from './GrpcConnectionLayout';
|
import { GrpcConnectionLayout } from './GrpcConnectionLayout';
|
||||||
import { HeaderSize } from './HeaderSize';
|
import { HeaderSize } from '@yaakapp-internal/ui';
|
||||||
import { HttpRequestLayout } from './HttpRequestLayout';
|
import { HttpRequestLayout } from './HttpRequestLayout';
|
||||||
import { Overlay } from './Overlay';
|
import { Overlay } from './Overlay';
|
||||||
import type { ResizeHandleEvent } from './ResizeHandle';
|
import type { ResizeHandleEvent } from './ResizeHandle';
|
||||||
@@ -59,6 +60,8 @@ export function Workspace() {
|
|||||||
useGlobalWorkspaceHooks();
|
useGlobalWorkspaceHooks();
|
||||||
|
|
||||||
const workspaces = useAtomValue(workspacesAtom);
|
const workspaces = useAtomValue(workspacesAtom);
|
||||||
|
const settings = useAtomValue(settingsAtom);
|
||||||
|
const osType = type();
|
||||||
const [width, setWidth, resetWidth] = useSidebarWidth();
|
const [width, setWidth, resetWidth] = useSidebarWidth();
|
||||||
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
||||||
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
||||||
@@ -146,7 +149,7 @@ export function Workspace() {
|
|||||||
'grid grid-rows-[auto_1fr]',
|
'grid grid-rows-[auto_1fr]',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<HeaderSize hideControls size="lg" className="border-transparent flex items-center">
|
<HeaderSize hideControls size="lg" className="border-transparent flex items-center" osType={osType} hideWindowControls={settings.hideWindowControls} useNativeTitlebar={settings.useNativeTitlebar} interfaceScale={settings.interfaceScale}>
|
||||||
<SidebarActions />
|
<SidebarActions />
|
||||||
</HeaderSize>
|
</HeaderSize>
|
||||||
<ErrorBoundary name="Sidebar (Floating)">
|
<ErrorBoundary name="Sidebar (Floating)">
|
||||||
@@ -178,6 +181,10 @@ export function Workspace() {
|
|||||||
size="lg"
|
size="lg"
|
||||||
className="relative x-theme-appHeader bg-surface"
|
className="relative x-theme-appHeader bg-surface"
|
||||||
style={head}
|
style={head}
|
||||||
|
osType={osType}
|
||||||
|
hideWindowControls={settings.hideWindowControls}
|
||||||
|
useNativeTitlebar={settings.useNativeTitlebar}
|
||||||
|
interfaceScale={settings.interfaceScale}
|
||||||
>
|
>
|
||||||
<div className="absolute inset-0 pointer-events-none">
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
<div // Add subtle background
|
<div // Add subtle background
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type } from '@tauri-apps/plugin-os';
|
import { type } from '@tauri-apps/plugin-os';
|
||||||
import { useIsFullscreen } from './useIsFullscreen';
|
import { useIsFullscreen } from '@yaakapp-internal/ui';
|
||||||
|
|
||||||
export function useStoplightsVisible() {
|
export function useStoplightsVisible() {
|
||||||
const fullscreen = useIsFullscreen();
|
const fullscreen = useIsFullscreen();
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import "./main.css";
|
import "./main.css";
|
||||||
import { Button } from "@yaakapp-internal/ui";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { type } from "@tauri-apps/plugin-os";
|
||||||
|
import { Button, HeaderSize } from "@yaakapp-internal/ui";
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
type ProxyStartResult = {
|
type ProxyStartResult = {
|
||||||
port: number;
|
port: number;
|
||||||
alreadyRunning: boolean;
|
alreadyRunning: boolean;
|
||||||
@@ -14,6 +18,7 @@ function App() {
|
|||||||
const [status, setStatus] = useState("Idle");
|
const [status, setStatus] = useState("Idle");
|
||||||
const [port, setPort] = useState<number | null>(null);
|
const [port, setPort] = useState<number | null>(null);
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
|
const osType = type();
|
||||||
|
|
||||||
async function startProxy() {
|
async function startProxy() {
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
@@ -46,46 +51,61 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="h-full w-full overflow-auto p-6">
|
<div className="h-full w-full grid grid-rows-[auto_1fr]">
|
||||||
<section className="flex items-start">
|
<HeaderSize
|
||||||
<div className="flex w-full max-w-xl flex-col gap-4">
|
size="lg"
|
||||||
<div>
|
osType={osType}
|
||||||
<h1 className="text-2xl font-semibold text-text">Yaak Proxy</h1>
|
hideWindowControls={false}
|
||||||
<p className="mt-2 text-sm text-text-subtle">Status: {status}</p>
|
useNativeTitlebar={false}
|
||||||
<p className="mt-1 text-sm text-text-subtle">
|
interfaceScale={1}
|
||||||
Port: {port ?? "Not running"}
|
className="x-theme-appHeader bg-surface"
|
||||||
</p>
|
>
|
||||||
</div>
|
<div
|
||||||
|
data-tauri-drag-region
|
||||||
<div className="flex flex-wrap gap-3">
|
className="flex items-center h-full px-2 text-sm font-semibold text-text-subtle"
|
||||||
<Button
|
>
|
||||||
disabled={busy}
|
Yaak Proxy
|
||||||
onClick={startProxy}
|
|
||||||
size="sm"
|
|
||||||
tone="primary"
|
|
||||||
>
|
|
||||||
Start Proxy
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={busy}
|
|
||||||
onClick={stopProxy}
|
|
||||||
size="sm"
|
|
||||||
variant="border"
|
|
||||||
>
|
|
||||||
Stop Proxy
|
|
||||||
</Button>
|
|
||||||
<Button size="sm" type="button">
|
|
||||||
Shared Button
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</HeaderSize>
|
||||||
</main>
|
<main className="overflow-auto p-6">
|
||||||
|
<section className="flex items-start">
|
||||||
|
<div className="flex w-full max-w-xl flex-col gap-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-text-subtle">Status: {status}</p>
|
||||||
|
<p className="mt-1 text-sm text-text-subtle">
|
||||||
|
Port: {port ?? "Not running"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-3">
|
||||||
|
<Button
|
||||||
|
disabled={busy}
|
||||||
|
onClick={startProxy}
|
||||||
|
size="sm"
|
||||||
|
tone="primary"
|
||||||
|
>
|
||||||
|
Start Proxy
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
disabled={busy}
|
||||||
|
onClick={stopProxy}
|
||||||
|
size="sm"
|
||||||
|
variant="border"
|
||||||
|
>
|
||||||
|
Stop Proxy
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoot(document.getElementById("root") as HTMLElement).render(
|
createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<App />
|
||||||
|
</QueryClientProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
"lint": "tsc --noEmit"
|
"lint": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^5.90.5",
|
||||||
|
"@tauri-apps/api": "^2.9.1",
|
||||||
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
"@yaakapp-internal/theme": "^1.0.0",
|
"@yaakapp-internal/theme": "^1.0.0",
|
||||||
"@yaakapp-internal/ui": "^1.0.0",
|
"@yaakapp-internal/ui": "^1.0.0",
|
||||||
"@tauri-apps/api": "^2.9.1",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0"
|
"react-dom": "^19.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@yaakapp-internal/theme": ["../../packages/theme/src/index.ts"],
|
"@yaakapp-internal/theme": ["../../packages/theme/src/index.ts"],
|
||||||
"@yaakapp-internal/theme/*": ["../../packages/theme/src/*"],
|
"@yaakapp-internal/theme/*": ["../../packages/theme/src/*"],
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ tauri-build = { version = "2.5.3", features = [] }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
tauri = { workspace = true }
|
tauri = { workspace = true }
|
||||||
|
tauri-plugin-os = "2.3.2"
|
||||||
yaak-proxy = { workspace = true }
|
yaak-proxy = { workspace = true }
|
||||||
yaak-window = { workspace = true }
|
yaak-window = { workspace = true }
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
"*"
|
"*"
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default"
|
"core:default",
|
||||||
|
"os:allow-os-type",
|
||||||
|
"core:window:allow-close",
|
||||||
|
"core:window:allow-is-fullscreen",
|
||||||
|
"core:window:allow-is-maximized",
|
||||||
|
"core:window:allow-maximize",
|
||||||
|
"core:window:allow-minimize",
|
||||||
|
"core:window:allow-start-dragging",
|
||||||
|
"core:window:allow-unmaximize"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ fn proxy_stop(state: State<'_, ProxyState>) -> Result<bool, String> {
|
|||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
.manage(ProxyState::default())
|
.manage(ProxyState::default())
|
||||||
.invoke_handler(tauri::generate_handler![proxy_metadata, proxy_start, proxy_stop])
|
.invoke_handler(tauri::generate_handler![proxy_metadata, proxy_start, proxy_stop])
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -224,7 +224,9 @@
|
|||||||
"name": "@yaakapp/yaak-proxy",
|
"name": "@yaakapp/yaak-proxy",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^5.90.5",
|
||||||
"@tauri-apps/api": "^2.9.1",
|
"@tauri-apps/api": "^2.9.1",
|
||||||
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
"@yaakapp-internal/theme": "^1.0.0",
|
"@yaakapp-internal/theme": "^1.0.0",
|
||||||
"@yaakapp-internal/ui": "^1.0.0",
|
"@yaakapp-internal/ui": "^1.0.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
@@ -16143,6 +16145,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/theme": {
|
"packages/theme": {
|
||||||
|
"name": "@yaakapp-internal/theme",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.9.1",
|
"@tauri-apps/api": "^2.9.1",
|
||||||
@@ -16154,8 +16157,13 @@
|
|||||||
"name": "@yaakapp-internal/ui",
|
"name": "@yaakapp-internal/ui",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^5.90.5",
|
||||||
|
"@tauri-apps/api": "^2.9.1",
|
||||||
|
"@yaakapp-internal/lib": "^1.0.0",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0"
|
"react-dom": "^19.1.0",
|
||||||
|
"react-use": "^17.6.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
|
|||||||
@@ -6,8 +6,13 @@
|
|||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^5.90.5",
|
||||||
|
"@tauri-apps/api": "^2.9.1",
|
||||||
|
"@yaakapp-internal/lib": "^1.0.0",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0"
|
"react-dom": "^19.1.0",
|
||||||
|
"react-use": "^17.6.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import { type } from '@tauri-apps/plugin-os';
|
|
||||||
import { settingsAtom } from '@yaakapp-internal/models';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useAtomValue } from 'jotai';
|
|
||||||
import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';
|
import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useIsFullscreen } from '../hooks/useIsFullscreen';
|
import { useIsFullscreen } from '../hooks/useIsFullscreen';
|
||||||
@@ -14,6 +11,10 @@ interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
|
|||||||
ignoreControlsSpacing?: boolean;
|
ignoreControlsSpacing?: boolean;
|
||||||
onlyXWindowControl?: boolean;
|
onlyXWindowControl?: boolean;
|
||||||
hideControls?: boolean;
|
hideControls?: boolean;
|
||||||
|
osType: string;
|
||||||
|
hideWindowControls: boolean;
|
||||||
|
useNativeTitlebar: boolean;
|
||||||
|
interfaceScale: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeaderSize({
|
export function HeaderSize({
|
||||||
@@ -24,10 +25,12 @@ export function HeaderSize({
|
|||||||
onlyXWindowControl,
|
onlyXWindowControl,
|
||||||
children,
|
children,
|
||||||
hideControls,
|
hideControls,
|
||||||
|
osType,
|
||||||
|
hideWindowControls,
|
||||||
|
useNativeTitlebar,
|
||||||
|
interfaceScale,
|
||||||
}: HeaderSizeProps) {
|
}: HeaderSizeProps) {
|
||||||
const settings = useAtomValue(settingsAtom);
|
|
||||||
const isFullscreen = useIsFullscreen();
|
const isFullscreen = useIsFullscreen();
|
||||||
const nativeTitlebar = settings.useNativeTitlebar;
|
|
||||||
const finalStyle = useMemo<CSSProperties>(() => {
|
const finalStyle = useMemo<CSSProperties>(() => {
|
||||||
const s = { ...style };
|
const s = { ...style };
|
||||||
|
|
||||||
@@ -35,14 +38,14 @@ export function HeaderSize({
|
|||||||
if (size === 'md') s.minHeight = HEADER_SIZE_MD;
|
if (size === 'md') s.minHeight = HEADER_SIZE_MD;
|
||||||
if (size === 'lg') s.minHeight = HEADER_SIZE_LG;
|
if (size === 'lg') s.minHeight = HEADER_SIZE_LG;
|
||||||
|
|
||||||
if (nativeTitlebar) {
|
if (useNativeTitlebar) {
|
||||||
// No style updates when using native titlebar
|
// No style updates when using native titlebar
|
||||||
} else if (type() === 'macos') {
|
} else if (osType === 'macos') {
|
||||||
if (!isFullscreen) {
|
if (!isFullscreen) {
|
||||||
// Add large padding for window controls
|
// Add large padding for window controls
|
||||||
s.paddingLeft = 72 / settings.interfaceScale;
|
s.paddingLeft = 72 / interfaceScale;
|
||||||
}
|
}
|
||||||
} else if (!ignoreControlsSpacing && !settings.hideWindowControls) {
|
} else if (!ignoreControlsSpacing && !hideWindowControls) {
|
||||||
s.paddingRight = WINDOW_CONTROLS_WIDTH;
|
s.paddingRight = WINDOW_CONTROLS_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,11 +53,12 @@ export function HeaderSize({
|
|||||||
}, [
|
}, [
|
||||||
ignoreControlsSpacing,
|
ignoreControlsSpacing,
|
||||||
isFullscreen,
|
isFullscreen,
|
||||||
settings.hideWindowControls,
|
hideWindowControls,
|
||||||
settings.interfaceScale,
|
interfaceScale,
|
||||||
size,
|
size,
|
||||||
style,
|
style,
|
||||||
nativeTitlebar,
|
useNativeTitlebar,
|
||||||
|
osType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -70,6 +74,7 @@ export function HeaderSize({
|
|||||||
>
|
>
|
||||||
{/* NOTE: This needs display:grid or else the element shrinks (even though scrollable) */}
|
{/* NOTE: This needs display:grid or else the element shrinks (even though scrollable) */}
|
||||||
<div
|
<div
|
||||||
|
data-tauri-drag-region
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'pointer-events-none h-full w-full overflow-x-auto hide-scrollbars grid',
|
'pointer-events-none h-full w-full overflow-x-auto hide-scrollbars grid',
|
||||||
'px-1', // Give it some space on either end for focus outlines
|
'px-1', // Give it some space on either end for focus outlines
|
||||||
@@ -77,7 +82,14 @@ export function HeaderSize({
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
{!hideControls && !nativeTitlebar && <WindowControls onlyX={onlyXWindowControl} />}
|
{!hideControls && !useNativeTitlebar && (
|
||||||
|
<WindowControls
|
||||||
|
onlyX={onlyXWindowControl}
|
||||||
|
osType={osType}
|
||||||
|
hideWindowControls={hideWindowControls}
|
||||||
|
useNativeTitlebar={useNativeTitlebar}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,28 @@
|
|||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||||
import { type } from '@tauri-apps/plugin-os';
|
|
||||||
import { settingsAtom } from '@yaakapp-internal/models';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useAtomValue } from 'jotai';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { WINDOW_CONTROLS_WIDTH } from '../lib/constants';
|
import { WINDOW_CONTROLS_WIDTH } from '../lib/constants';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './Button';
|
||||||
import { HStack } from './core/Stacks';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
onlyX?: boolean;
|
onlyX?: boolean;
|
||||||
macos?: boolean;
|
osType: string;
|
||||||
|
hideWindowControls: boolean;
|
||||||
|
useNativeTitlebar: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WindowControls({ className, onlyX }: Props) {
|
export function WindowControls({ className, onlyX, osType, hideWindowControls, useNativeTitlebar }: Props) {
|
||||||
const [maximized, setMaximized] = useState<boolean>(false);
|
const [maximized, setMaximized] = useState<boolean>(false);
|
||||||
const settings = useAtomValue(settingsAtom);
|
|
||||||
// Never show controls on macOS or if hideWindowControls is true
|
// Never show controls on macOS or if hideWindowControls is true
|
||||||
if (type() === 'macos' || settings.hideWindowControls || settings.useNativeTitlebar) {
|
if (osType === 'macos' || hideWindowControls || useNativeTitlebar) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HStack
|
<div
|
||||||
className={classNames(className, 'ml-4 absolute right-0 top-0 bottom-0')}
|
className={classNames(className, 'ml-4 absolute right-0 top-0 bottom-0 flex items-center justify-end')}
|
||||||
justifyContent="end"
|
|
||||||
style={{ width: WINDOW_CONTROLS_WIDTH }}
|
style={{ width: WINDOW_CONTROLS_WIDTH }}
|
||||||
data-tauri-drag-region
|
data-tauri-drag-region
|
||||||
>
|
>
|
||||||
@@ -88,6 +85,6 @@ export function WindowControls({ className, onlyX }: Props) {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
12
packages/ui/src/hooks/useDebouncedState.ts
Normal file
12
packages/ui/src/hooks/useDebouncedState.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { debounce } from '@yaakapp-internal/lib';
|
||||||
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
export function useDebouncedState<T>(
|
||||||
|
defaultValue: T,
|
||||||
|
delay = 500,
|
||||||
|
): [T, Dispatch<SetStateAction<T>>, Dispatch<SetStateAction<T>>] {
|
||||||
|
const [state, setState] = useState<T>(defaultValue);
|
||||||
|
const debouncedSetState = useMemo(() => debounce(setState, delay), [delay]);
|
||||||
|
return [state, debouncedSetState, setState];
|
||||||
|
}
|
||||||
8
packages/ui/src/hooks/useDebouncedValue.ts
Normal file
8
packages/ui/src/hooks/useDebouncedValue.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useDebouncedState } from './useDebouncedState';
|
||||||
|
|
||||||
|
export function useDebouncedValue<T>(value: T, delay = 500) {
|
||||||
|
const [state, setState] = useDebouncedState<T>(value, delay);
|
||||||
|
useEffect(() => setState(value), [setState, value]);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
@@ -1,2 +1,8 @@
|
|||||||
export { Button } from "./components/Button";
|
export { Button } from "./components/Button";
|
||||||
export type { ButtonProps } from "./components/Button";
|
export type { ButtonProps } from "./components/Button";
|
||||||
|
export { HeaderSize } from "./components/HeaderSize";
|
||||||
|
export { WindowControls } from "./components/WindowControls";
|
||||||
|
export { useIsFullscreen } from "./hooks/useIsFullscreen";
|
||||||
|
export { useDebouncedValue } from "./hooks/useDebouncedValue";
|
||||||
|
export { useDebouncedState } from "./hooks/useDebouncedState";
|
||||||
|
export { HEADER_SIZE_MD, HEADER_SIZE_LG, WINDOW_CONTROLS_WIDTH } from "./lib/constants";
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
"target": "es2021",
|
"target": "es2021",
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|||||||
Reference in New Issue
Block a user