From 2caa735a2ec5ae985e034714b1e5dfac2f97c5e5 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Thu, 30 May 2024 10:28:59 -0700 Subject: [PATCH] Tweak settings for release --- src-tauri/src/lib.rs | 61 +++------- src-tauri/src/window_menu.rs | 6 +- src-web/components/AppRouter.tsx | 4 +- src-web/components/GlobalHooks.tsx | 2 - src-web/components/Settings/Settings.tsx | 47 ++++++++ .../Settings/SettingsAppearance.tsx | 111 ++++++++---------- .../components/Settings/SettingsDialog.tsx | 61 ---------- .../components/Settings/SettingsGeneral.tsx | 22 +--- src-web/components/Sidebar.tsx | 19 ++- src-web/components/Workspace.tsx | 2 + src-web/components/core/Dropdown.tsx | 3 +- src-web/components/core/Editor/Editor.tsx | 6 + src-web/components/core/Icon.tsx | 2 + src-web/components/core/Select.tsx | 42 +++++-- src-web/hooks/useSettings.ts | 1 - ...tle.ts => useSyncWorkspaceRequestTitle.ts} | 2 +- src-web/hooks/useUpdateSettings.ts | 17 ++- src-web/hooks/useZoom.ts | 3 - src-web/lib/models.ts | 2 +- tailwind.config.cjs | 5 +- 20 files changed, 191 insertions(+), 227 deletions(-) create mode 100644 src-web/components/Settings/Settings.tsx delete mode 100644 src-web/components/Settings/SettingsDialog.tsx rename src-web/hooks/{useSyncWindowTitle.ts => useSyncWorkspaceRequestTitle.ts} (96%) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b1f6daf9..e8b1a14a 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -23,7 +23,7 @@ use sqlx::{Pool, Sqlite, SqlitePool}; use sqlx::migrate::Migrator; use sqlx::sqlite::SqliteConnectOptions; use sqlx::types::Json; -use tauri::{AppHandle, RunEvent, State, WebviewUrl, WebviewWindow}; +use tauri::{AppHandle, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow}; use tauri::{Manager, WindowEvent}; use tauri::path::BaseDirectory; #[cfg(target_os = "macos")] @@ -74,6 +74,9 @@ mod tauri_plugin_mac_window; #[cfg(target_os = "windows")] mod tauri_plugin_windows_window; +const DEFAULT_WINDOW_WIDTH: i32 = 1100; +const DEFAULT_WINDOW_HEIGHT: i32 = 600; + async fn migrate_db(app_handle: &AppHandle, db: &Mutex>) -> Result<(), String> { let pool = &*db.lock().await; let p = app_handle @@ -1784,41 +1787,6 @@ fn create_nested_window(window: &WebviewWindow, label: &str, url: &str, title: & let win = win_builder.build().expect("failed to build window"); - // Tauri doesn't support shadows when hiding decorations, so we add our own - // #[cfg(any(windows, target_os = "macos"))] - // set_shadow(&win, true).unwrap(); - - let win2 = win.clone(); - win.on_menu_event(move |w, event| { - if !w.is_focused().unwrap() { - return; - } - - match event.id().0.as_str() { - "quit" => exit(0), - "close" => _ = w.close(), - "zoom_reset" => w.emit("zoom_reset", true).unwrap(), - "zoom_in" => w.emit("zoom_in", true).unwrap(), - "zoom_out" => w.emit("zoom_out", true).unwrap(), - "settings" => w.emit("settings", true).unwrap(), - "refresh" => win2.eval("location.reload()").unwrap(), - "open_feedback" => { - _ = win2 - .app_handle() - .shell() - .open("https://yaak.canny.io", None) - } - "toggle_devtools" => { - if win2.is_devtools_open() { - win2.close_devtools(); - } else { - win2.open_devtools(); - } - } - _ => {} - } - }); - win } @@ -1840,7 +1808,7 @@ fn create_window(handle: &AppHandle, url: &str) -> WebviewWindow { .resizable(true) .fullscreen(false) .disable_drag_drop_handler() // Required for frontend Dnd on windows - .inner_size(1100.0, 600.0) + .inner_size(DEFAULT_WINDOW_WIDTH as f64, DEFAULT_WINDOW_HEIGHT as f64) .position( // Randomly offset so windows don't stack exactly 100.0 + random::() * 30.0, @@ -1866,7 +1834,7 @@ fn create_window(handle: &AppHandle, url: &str) -> WebviewWindow { let win = win_builder.build().expect("failed to build window"); - let win2 = win.clone(); + let webview_window = win.clone(); win.on_menu_event(move |w, event| { if !w.is_focused().unwrap() { return; @@ -1874,23 +1842,26 @@ fn create_window(handle: &AppHandle, url: &str) -> WebviewWindow { match event.id().0.as_str() { "quit" => exit(0), - "close" => _ = w.close(), + "close" => w.close().unwrap(), "zoom_reset" => w.emit("zoom_reset", true).unwrap(), "zoom_in" => w.emit("zoom_in", true).unwrap(), "zoom_out" => w.emit("zoom_out", true).unwrap(), "settings" => w.emit("settings", true).unwrap(), - "refresh" => win2.eval("location.reload()").unwrap(), "open_feedback" => { - _ = win2 + _ = webview_window .app_handle() .shell() .open("https://yaak.canny.io", None) } - "toggle_devtools" => { - if win2.is_devtools_open() { - win2.close_devtools(); + + // Commands for development + "dev.reset_size" => webview_window.set_size(LogicalSize::new(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT)).unwrap(), + "dev.refresh" => webview_window.eval("location.reload()").unwrap(), + "dev.toggle_devtools" => { + if webview_window.is_devtools_open() { + webview_window.close_devtools(); } else { - win2.open_devtools(); + webview_window.open_devtools(); } } _ => {} diff --git a/src-tauri/src/window_menu.rs b/src-tauri/src/window_menu.rs index 4c74a764..d9a0b42a 100644 --- a/src-tauri/src/window_menu.rs +++ b/src-tauri/src/window_menu.rs @@ -126,12 +126,14 @@ pub fn app_menu(app_handle: &AppHandle) -> tauri::Result> { "Develop", true, &[ - &MenuItemBuilder::with_id("refresh".to_string(), "Refresh") + &MenuItemBuilder::with_id("dev.refresh".to_string(), "Refresh") .accelerator("CmdOrCtrl+Shift+r") .build(app_handle)?, - &MenuItemBuilder::with_id("toggle_devtools".to_string(), "Open Devtools") + &MenuItemBuilder::with_id("dev.toggle_devtools".to_string(), "Open Devtools") .accelerator("CmdOrCtrl+Option+i") .build(app_handle)?, + &MenuItemBuilder::with_id("dev.reset_size".to_string(), "Reset Size") + .build(app_handle)?, ], )?, ], diff --git a/src-web/components/AppRouter.tsx b/src-web/components/AppRouter.tsx index 66adfed8..70f96a4b 100644 --- a/src-web/components/AppRouter.tsx +++ b/src-web/components/AppRouter.tsx @@ -3,7 +3,7 @@ import { routePaths, useAppRoutes } from '../hooks/useAppRoutes'; import { DefaultLayout } from './DefaultLayout'; import { RedirectToLatestWorkspace } from './RedirectToLatestWorkspace'; import RouteError from './RouteError'; -import { SettingsDialog } from './Settings/SettingsDialog'; +import { Settings } from './Settings/Settings'; import Workspace from './Workspace'; const router = createBrowserRouter([ @@ -41,7 +41,7 @@ const router = createBrowserRouter([ path: routePaths.workspaceSettings({ workspaceId: ':workspaceId', }), - element: , + element: , }, ], }, diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx index d3a7b502..19c937f6 100644 --- a/src-web/components/GlobalHooks.tsx +++ b/src-web/components/GlobalHooks.tsx @@ -20,7 +20,6 @@ import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { settingsQueryKey, useSettings } from '../hooks/useSettings'; import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument'; -import { useSyncWindowTitle } from '../hooks/useSyncWindowTitle'; import { workspacesQueryKey } from '../hooks/useWorkspaces'; import { useZoom } from '../hooks/useZoom'; import type { Model } from '../lib/models'; @@ -34,7 +33,6 @@ export function GlobalHooks() { // Other useful things useSyncThemeToDocument(); - useSyncWindowTitle(); useGlobalCommands(); useCommandPalette(); useNotificationToast(); diff --git a/src-web/components/Settings/Settings.tsx b/src-web/components/Settings/Settings.tsx new file mode 100644 index 00000000..794672ba --- /dev/null +++ b/src-web/components/Settings/Settings.tsx @@ -0,0 +1,47 @@ +import { getCurrent } from '@tauri-apps/api/webviewWindow'; +import { createGlobalState, useKeyPressEvent } from 'react-use'; +import { capitalize } from '../../lib/capitalize'; +import { TabContent, Tabs } from '../core/Tabs/Tabs'; +import { SettingsAppearance } from './SettingsAppearance'; +import { SettingsGeneral } from './SettingsGeneral'; + +enum Tab { + General = 'general', + Appearance = 'appearance', +} + +const tabs = [Tab.General, Tab.Appearance]; +const useTabState = createGlobalState(tabs[0]!); + +export const Settings = () => { + const [tab, setTab] = useTabState(); + + // Close settings window on escape + // TODO: Could this be put in a better place? Eg. in Rust key listener when creating the window + useKeyPressEvent('Escape', () => getCurrent().close()); + + return ( + <> +
+ Settings +
+ ({ value, label: capitalize(value) }))} + > + + + + + + + + + ); +}; diff --git a/src-web/components/Settings/SettingsAppearance.tsx b/src-web/components/Settings/SettingsAppearance.tsx index 7a06f2d3..67a376d9 100644 --- a/src-web/components/Settings/SettingsAppearance.tsx +++ b/src-web/components/Settings/SettingsAppearance.tsx @@ -5,19 +5,23 @@ import { useResolvedTheme } from '../../hooks/useResolvedTheme'; import { useSettings } from '../../hooks/useSettings'; import { useThemes } from '../../hooks/useThemes'; import { useUpdateSettings } from '../../hooks/useUpdateSettings'; -import { trackEvent } from '../../lib/analytics'; import { clamp } from '../../lib/clamp'; import { isThemeDark } from '../../lib/theme/window'; import type { ButtonProps } from '../core/Button'; +import { Checkbox } from '../core/Checkbox'; import { Editor } from '../core/Editor'; import type { IconProps } from '../core/Icon'; +import { Icon } from '../core/Icon'; import { IconButton } from '../core/IconButton'; -import { PlainInput } from '../core/PlainInput'; import type { SelectOption } from '../core/Select'; import { Select } from '../core/Select'; import { Separator } from '../core/Separator'; import { HStack, VStack } from '../core/Stacks'; +const fontSizes = [ + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, +].map((n) => ({ label: `${n}`, value: `${n}` })); + const buttonColors: ButtonProps['color'][] = [ 'primary', 'info', @@ -75,39 +79,28 @@ export function SettingsAppearance() { return ( - parseInt(value) >= 8 && parseInt(value) <= 30} - onChange={(v) => - updateSettings.mutate({ - ...settings, - interfaceFontSize: clamp(parseInt(v) || 16, 8, 30), - }) - } + value={`${settings.interfaceFontSize}`} + options={fontSizes} + onChange={(v) => updateSettings.mutate({ interfaceFontSize: parseInt(v) })} /> - parseInt(value) >= 8 && parseInt(value) <= 30} - onChange={(v) => - updateSettings.mutate({ - ...settings, - editorFontSize: clamp(parseInt(v) || 14, 8, 30), - }) - } + value={`${settings.editorFontSize}`} + options={fontSizes} + onChange={(v) => updateSettings.mutate({ editorFontSize: clamp(parseInt(v) || 14, 8, 30) })} + /> + updateSettings.mutate({ editorSoftWrap })} /> @@ -118,9 +111,8 @@ export function SettingsAppearance() { labelPosition="left" size="sm" value={settings.appearance} - onChange={async (appearance) => { - await updateSettings.mutateAsync({ ...settings, appearance }); - trackEvent('setting', 'update', { appearance }); + onChange={(appearance) => { + updateSettings.mutateAsync({ appearance }); }} options={[ { label: 'Automatic', value: 'system' }, @@ -128,42 +120,41 @@ export function SettingsAppearance() { { label: 'Dark', value: 'dark' }, ]} /> - {(settings.appearance === 'system' || settings.appearance === 'light') && ( - { - await updateSettings.mutateAsync({ ...settings, themeDark }); - trackEvent('setting', 'update', { themeDark }); - }} - /> - )} + + {(settings.appearance === 'system' || settings.appearance === 'light') && ( + } + size="sm" + value={activeTheme.dark.id} + options={darkThemes} + onChange={(themeDark) => updateSettings.mutateAsync({ ...settings, themeDark })} + /> + )} + -
- Theme Preview ({appearance}) -
+ + Theme Preview{' '} + + {buttonColors.map((c, i) => ( (tabs[0]!); - -interface Props { - fullscreen?: true; -} - -export const SettingsDialog = ({ fullscreen }: Props) => { - const [tab, setTab] = useTabState(); - const appInfo = useAppInfo(); - const isDev = appInfo?.isDev ?? false; - - return ( -
- {fullscreen && ( -
- Settings -
- )} - t !== Tab.Design || isDev) - .map((value) => ({ value, label: capitalize(value) }))} - > - - - - - - - - - - -
- ); -}; diff --git a/src-web/components/Settings/SettingsGeneral.tsx b/src-web/components/Settings/SettingsGeneral.tsx index d1bd230f..aef01dd0 100644 --- a/src-web/components/Settings/SettingsGeneral.tsx +++ b/src-web/components/Settings/SettingsGeneral.tsx @@ -5,7 +5,6 @@ import { useCheckForUpdates } from '../../hooks/useCheckForUpdates'; import { useSettings } from '../../hooks/useSettings'; import { useUpdateSettings } from '../../hooks/useUpdateSettings'; import { useUpdateWorkspace } from '../../hooks/useUpdateWorkspace'; -import { trackEvent } from '../../lib/analytics'; import { Checkbox } from '../core/Checkbox'; import { Heading } from '../core/Heading'; import { IconButton } from '../core/IconButton'; @@ -36,10 +35,7 @@ export function SettingsGeneral() { labelPosition="left" size="sm" value={settings.updateChannel} - onChange={(updateChannel) => { - trackEvent('setting', 'update', { update_channel: updateChannel }); - updateSettings.mutate({ ...settings, updateChannel }); - }} + onChange={(updateChannel) => updateSettings.mutate({ updateChannel })} options={[ { label: 'Release', value: 'stable' }, { label: 'Early Bird (Beta)', value: 'beta' }, @@ -77,23 +73,15 @@ export function SettingsGeneral() { { - trackEvent('workspace', 'update', { - validate_certificates: JSON.stringify(settingValidateCertificates), - }); - updateWorkspace.mutate({ settingValidateCertificates }); - }} + onChange={(settingValidateCertificates) => + updateWorkspace.mutate({ settingValidateCertificates }) + } /> { - trackEvent('workspace', 'update', { - follow_redirects: JSON.stringify(settingFollowRedirects), - }); - updateWorkspace.mutate({ settingFollowRedirects }); - }} + onChange={(settingFollowRedirects) => updateWorkspace.mutate({ settingFollowRedirects })} />
diff --git a/src-web/components/Sidebar.tsx b/src-web/components/Sidebar.tsx index 6b0857c6..840165a7 100644 --- a/src-web/components/Sidebar.tsx +++ b/src-web/components/Sidebar.tsx @@ -133,27 +133,31 @@ export function Sidebar({ className }: Props) { ) { selectedRequest = node.item; } - const childItems = [...requests, ...folders].filter((f) => node.item.model === 'workspace' ? f.folderId == null : f.folderId === node.item.id, ); - childItems.sort((a, b) => a.sortPriority - b.sortPriority); + // Recurse to children + const isCollapsed = collapsed.value?.[node.item.id]; const depth = node.depth + 1; + childItems.sort((a, b) => a.sortPriority - b.sortPriority); for (const item of childItems) { treeParentMap[item.id] = node; + // Add to children node.children.push(next({ item, children: [], depth })); - if (item.model !== 'folder') { + // Add to selectable requests + if (item.model !== 'folder' && !isCollapsed) { selectableRequests.push({ id: item.id, index: selectableRequestIndex++, tree: node }); } } + return node; }; const tree = next({ item: activeWorkspace, children: [], depth: 0 }); return { tree, treeParentMap, selectableRequests, selectedRequest }; - }, [activeWorkspace, selectedId, requests, folders]); + }, [activeWorkspace, selectedId, requests, folders, collapsed.value]); const deleteSelectedRequest = useDeleteRequest(selectedRequest); @@ -455,6 +459,7 @@ export function Sidebar({ className }: Props) { /> ; @@ -491,6 +497,7 @@ interface SidebarItemsProps { function SidebarItems({ tree, focused, + activeId, selectedId, selectedTree, draggingId, @@ -517,6 +524,7 @@ function SidebarItems({ > {tree.children.map((child, i) => { const selected = selectedId === child.item.id; + const active = activeId === child.item.id; return ( {hoveredIndex === i && hoveredTree?.item.id === tree.item.id && } @@ -535,7 +543,7 @@ function SidebarItems({ (child.item.model === 'http_request' || child.item.model === 'grpc_request') && ( ) } @@ -558,6 +566,7 @@ function SidebarItems({ hoveredTree={hoveredTree} hoveredIndex={hoveredIndex} focused={focused} + activeId={activeId} selectedId={selectedId} selectedTree={selectedTree} onSelect={onSelect} diff --git a/src-web/components/Workspace.tsx b/src-web/components/Workspace.tsx index 9635a695..c439b27f 100644 --- a/src-web/components/Workspace.tsx +++ b/src-web/components/Workspace.tsx @@ -18,6 +18,7 @@ import { useOsInfo } from '../hooks/useOsInfo'; import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar'; import { useSidebarHidden } from '../hooks/useSidebarHidden'; import { useSidebarWidth } from '../hooks/useSidebarWidth'; +import { useSyncWorkspaceRequestTitle } from '../hooks/useSyncWorkspaceRequestTitle'; import { useWorkspaces } from '../hooks/useWorkspaces'; import { Banner } from './core/Banner'; import { Button } from './core/Button'; @@ -40,6 +41,7 @@ const body = { gridArea: 'body' }; const drag = { gridArea: 'drag' }; export default function Workspace() { + useSyncWorkspaceRequestTitle(); const workspaces = useWorkspaces(); const activeWorkspace = useActiveWorkspace(); const activeWorkspaceId = useActiveWorkspaceId(); diff --git a/src-web/components/core/Dropdown.tsx b/src-web/components/core/Dropdown.tsx index 6d487953..c2f9acd4 100644 --- a/src-web/components/core/Dropdown.tsx +++ b/src-web/components/core/Dropdown.tsx @@ -373,7 +373,6 @@ const Menu = forwardRef, MenuPro bottom: upsideDown ? docRect.height - top : undefined, right: onRight ? docRect.width - triggerShape?.right : undefined, left: !onRight ? triggerShape?.left : undefined, - width: containerWidth ?? 'auto', }; const size = { top: '-0.2rem', width: '0.4rem', height: '0.4rem' }; const triangleStyles = onRight @@ -448,7 +447,7 @@ const Menu = forwardRef, MenuPro
{filter}
diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index 410de507..a0eda94c 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -17,6 +17,7 @@ import { } from 'react'; import { useActiveEnvironment } from '../../../hooks/useActiveEnvironment'; import { useActiveWorkspace } from '../../../hooks/useActiveWorkspace'; +import { useSettings } from '../../../hooks/useSettings'; import { IconButton } from '../IconButton'; import { HStack } from '../Stacks'; import './Editor.css'; @@ -85,11 +86,16 @@ export const Editor = forwardRef(function E }: EditorProps, ref, ) { + const s = useSettings(); const e = useActiveEnvironment(); const w = useActiveWorkspace(); const environment = autocompleteVariables ? e : null; const workspace = autocompleteVariables ? w : null; + if (s && wrapLines === undefined) { + wrapLines = s.editorSoftWrap; + } + const cm = useRef<{ view: EditorView; languageCompartment: Compartment } | null>(null); useImperativeHandle(ref, () => cm.current?.view); diff --git a/src-web/components/core/Icon.tsx b/src-web/components/core/Icon.tsx index d82f79e4..c299d4ab 100644 --- a/src-web/components/core/Icon.tsx +++ b/src-web/components/core/Icon.tsx @@ -42,6 +42,7 @@ const icons = { magicWand: lucide.Wand2Icon, minus: lucide.MinusIcon, moreVertical: lucide.MoreVerticalIcon, + moon: lucide.MoonIcon, paste: lucide.ClipboardPasteIcon, pencil: lucide.PencilIcon, pin: lucide.PinIcon, @@ -55,6 +56,7 @@ const icons = { settings2: lucide.Settings2Icon, settings: lucide.SettingsIcon, sparkles: lucide.SparklesIcon, + sun: lucide.SunIcon, trash: lucide.TrashIcon, update: lucide.RefreshCcwIcon, upload: lucide.UploadIcon, diff --git a/src-web/components/core/Select.tsx b/src-web/components/core/Select.tsx index 766ca7c7..50432f87 100644 --- a/src-web/components/core/Select.tsx +++ b/src-web/components/core/Select.tsx @@ -1,5 +1,7 @@ import classNames from 'classnames'; -import type { CSSProperties } from 'react'; +import type { CSSProperties, ReactNode } from 'react'; +import { useState } from 'react'; +import { HStack } from './Stacks'; interface Props { name: string; @@ -8,6 +10,7 @@ interface Props { labelClassName?: string; hideLabel?: boolean; value: T; + leftSlot?: ReactNode; options: SelectOption[]; onChange: (value: T) => void; size?: 'xs' | 'sm' | 'md' | 'lg'; @@ -27,10 +30,12 @@ export function Select({ label, value, options, + leftSlot, onChange, className, size = 'md', }: Props) { + const [focused, setFocused] = useState(false); const id = `input-${name}`; return (
({ > {label} - + {leftSlot &&
{leftSlot}
} + +
); } diff --git a/src-web/hooks/useSettings.ts b/src-web/hooks/useSettings.ts index 68b99bdb..47ba7b85 100644 --- a/src-web/hooks/useSettings.ts +++ b/src-web/hooks/useSettings.ts @@ -12,7 +12,6 @@ export function useSettings() { queryKey: settingsQueryKey(), queryFn: async () => { const settings = (await invoke('cmd_get_settings')) as Settings; - console.log('SETTINGS', settings); return [settings]; }, }).data?.[0] ?? undefined diff --git a/src-web/hooks/useSyncWindowTitle.ts b/src-web/hooks/useSyncWorkspaceRequestTitle.ts similarity index 96% rename from src-web/hooks/useSyncWindowTitle.ts rename to src-web/hooks/useSyncWorkspaceRequestTitle.ts index 51a5c712..6b4a62e0 100644 --- a/src-web/hooks/useSyncWindowTitle.ts +++ b/src-web/hooks/useSyncWorkspaceRequestTitle.ts @@ -7,7 +7,7 @@ import { useActiveWorkspace } from './useActiveWorkspace'; import { useOsInfo } from './useOsInfo'; import { emit } from '@tauri-apps/api/event'; -export function useSyncWindowTitle() { +export function useSyncWorkspaceRequestTitle() { const activeRequest = useActiveRequest(); const activeWorkspace = useActiveWorkspace(); const activeEnvironment = useActiveEnvironment(); diff --git a/src-web/hooks/useUpdateSettings.ts b/src-web/hooks/useUpdateSettings.ts index b4e3eeb0..f4063055 100644 --- a/src-web/hooks/useUpdateSettings.ts +++ b/src-web/hooks/useUpdateSettings.ts @@ -1,17 +1,16 @@ -import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; import { invoke } from '@tauri-apps/api/core'; import type { Settings } from '../lib/models'; -import { settingsQueryKey } from './useSettings'; +import { useSettings } from './useSettings'; export function useUpdateSettings() { - const queryClient = useQueryClient(); + const settings = useSettings(); - return useMutation({ - mutationFn: async (settings) => { - await invoke('cmd_update_settings', { settings }); - }, - onMutate: async (settings) => { - queryClient.setQueryData(settingsQueryKey(), [settings]); + return useMutation>({ + mutationFn: async (patch) => { + if (settings == null) return; + const newSettings: Settings = { ...settings, ...patch }; + await invoke('cmd_update_settings', { settings: newSettings }); }, }); } diff --git a/src-web/hooks/useZoom.ts b/src-web/hooks/useZoom.ts index fe303904..2625f882 100644 --- a/src-web/hooks/useZoom.ts +++ b/src-web/hooks/useZoom.ts @@ -9,7 +9,6 @@ export function useZoom() { const zoomIn = useCallback(() => { if (!settings) return; updateSettings.mutate({ - ...settings, interfaceScale: Math.min(1.8, settings.interfaceScale * 1.1), }); }, [settings, updateSettings]); @@ -17,13 +16,11 @@ export function useZoom() { const zoomOut = useCallback(() => { if (!settings) return; updateSettings.mutate({ - ...settings, interfaceScale: Math.max(0.4, settings.interfaceScale * 0.9), }); }, [settings, updateSettings]); const zoomReset = useCallback(() => { - if (!settings) return; updateSettings.mutate({ ...settings, interfaceScale: 1 }); }, [settings, updateSettings]); diff --git a/src-web/lib/models.ts b/src-web/lib/models.ts index 0b2f6c87..c36d7c2b 100644 --- a/src-web/lib/models.ts +++ b/src-web/lib/models.ts @@ -40,7 +40,7 @@ export interface Settings extends BaseModel { interfaceFontSize: number; interfaceScale: number; editorFontSize: number; - editorSoftWrap: number; + editorSoftWrap: boolean; } export interface Workspace extends BaseModel { diff --git a/tailwind.config.cjs b/tailwind.config.cjs index 372c37b2..7b196091 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -1,10 +1,9 @@ const plugin = require('tailwindcss/plugin'); const height = { - '2xs': '1.6rem', xs: '1.8rem', - sm: '2.2rem', - md: '2.7rem', + sm: '2.0rem', + md: '2.5rem', }; /** @type {import("tailwindcss").Config} */