mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-07-10 23:02:46 +02:00
Split appearance settings into theme/interface
This commit is contained in:
@@ -8,22 +8,24 @@ import { capitalize } from '../../lib/capitalize';
|
|||||||
import { HStack } from '../core/Stacks';
|
import { HStack } from '../core/Stacks';
|
||||||
import { TabContent, Tabs } from '../core/Tabs/Tabs';
|
import { TabContent, Tabs } from '../core/Tabs/Tabs';
|
||||||
import { HeaderSize } from '../HeaderSize';
|
import { HeaderSize } from '../HeaderSize';
|
||||||
import { SettingsAppearance } from './SettingsAppearance';
|
import { SettingsInterface } from './SettingsInterface';
|
||||||
import { SettingsGeneral } from './SettingsGeneral';
|
import { SettingsGeneral } from './SettingsGeneral';
|
||||||
import { SettingsLicense } from './SettingsLicense';
|
import { SettingsLicense } from './SettingsLicense';
|
||||||
import { SettingsPlugins } from './SettingsPlugins';
|
import { SettingsPlugins } from './SettingsPlugins';
|
||||||
import { SettingsProxy } from './SettingsProxy';
|
import { SettingsProxy } from './SettingsProxy';
|
||||||
|
import { SettingsTheme } from './SettingsTheme';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
hide?: () => void;
|
hide?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TAB_GENERAL = 'general';
|
const TAB_GENERAL = 'general';
|
||||||
const TAB_APPEARANCE = 'appearance';
|
const TAB_INTERFACE = 'interface';
|
||||||
|
const TAB_THEME = 'theme';
|
||||||
const TAB_PROXY = 'proxy';
|
const TAB_PROXY = 'proxy';
|
||||||
const TAB_PLUGINS = 'plugins';
|
const TAB_PLUGINS = 'plugins';
|
||||||
const TAB_LICENSE = 'license';
|
const TAB_LICENSE = 'license';
|
||||||
const tabs = [TAB_GENERAL, TAB_APPEARANCE, TAB_PROXY, TAB_PLUGINS, TAB_LICENSE] as const;
|
const tabs = [TAB_GENERAL, TAB_THEME, TAB_INTERFACE, TAB_PROXY, TAB_PLUGINS, TAB_LICENSE] as const;
|
||||||
export type SettingsTab = (typeof tabs)[number];
|
export type SettingsTab = (typeof tabs)[number];
|
||||||
|
|
||||||
export default function Settings({ hide }: Props) {
|
export default function Settings({ hide }: Props) {
|
||||||
@@ -73,8 +75,11 @@ export default function Settings({ hide }: Props) {
|
|||||||
<TabContent value={TAB_GENERAL} className="pt-3 overflow-y-auto h-full px-4">
|
<TabContent value={TAB_GENERAL} className="pt-3 overflow-y-auto h-full px-4">
|
||||||
<SettingsGeneral />
|
<SettingsGeneral />
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value={TAB_APPEARANCE} className="pt-3 overflow-y-auto h-full px-4">
|
<TabContent value={TAB_INTERFACE} className="pt-3 overflow-y-auto h-full px-4">
|
||||||
<SettingsAppearance />
|
<SettingsInterface />
|
||||||
|
</TabContent>
|
||||||
|
<TabContent value={TAB_THEME} className="pt-3 overflow-y-auto h-full px-4">
|
||||||
|
<SettingsTheme />
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value={TAB_PLUGINS} className="pt-3 overflow-y-auto h-full px-4">
|
<TabContent value={TAB_PLUGINS} className="pt-3 overflow-y-auto h-full px-4">
|
||||||
<SettingsPlugins />
|
<SettingsPlugins />
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import { type } from '@tauri-apps/plugin-os';
|
||||||
|
import { useFonts } from '@yaakapp-internal/fonts';
|
||||||
|
import type { EditorKeymap } from '@yaakapp-internal/models';
|
||||||
|
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
||||||
|
import { useAtomValue } from 'jotai';
|
||||||
|
import React from 'react';
|
||||||
|
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
||||||
|
import { clamp } from '../../lib/clamp';
|
||||||
|
import { Checkbox } from '../core/Checkbox';
|
||||||
|
import { Icon } from '../core/Icon';
|
||||||
|
import { Select } from '../core/Select';
|
||||||
|
import { HStack, VStack } from '../core/Stacks';
|
||||||
|
|
||||||
|
const NULL_FONT_VALUE = '__NULL_FONT__';
|
||||||
|
|
||||||
|
const fontSizeOptions = [
|
||||||
|
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 keymaps: { value: EditorKeymap; label: string }[] = [
|
||||||
|
{ value: 'default', label: 'Default' },
|
||||||
|
{ value: 'vim', label: 'Vim' },
|
||||||
|
{ value: 'vscode', label: 'VSCode' },
|
||||||
|
{ value: 'emacs', label: 'Emacs' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function SettingsInterface() {
|
||||||
|
const workspace = useAtomValue(activeWorkspaceAtom);
|
||||||
|
const settings = useAtomValue(settingsAtom);
|
||||||
|
const fonts = useFonts();
|
||||||
|
|
||||||
|
if (settings == null || workspace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VStack space={3} className="mb-4">
|
||||||
|
<HStack space={2} alignItems="end">
|
||||||
|
{fonts.data && (
|
||||||
|
<Select
|
||||||
|
size="sm"
|
||||||
|
name="uiFont"
|
||||||
|
label="Interface Font"
|
||||||
|
value={settings.interfaceFont ?? NULL_FONT_VALUE}
|
||||||
|
options={[
|
||||||
|
{ label: 'System Default', value: NULL_FONT_VALUE },
|
||||||
|
...(fonts.data.uiFonts.map((f) => ({
|
||||||
|
label: f,
|
||||||
|
value: f,
|
||||||
|
})) ?? []),
|
||||||
|
// Some people like monospace fonts for the UI
|
||||||
|
...(fonts.data.editorFonts.map((f) => ({
|
||||||
|
label: f,
|
||||||
|
value: f,
|
||||||
|
})) ?? []),
|
||||||
|
]}
|
||||||
|
onChange={async (v) => {
|
||||||
|
const interfaceFont = v === NULL_FONT_VALUE ? null : v;
|
||||||
|
await patchModel(settings, { interfaceFont });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Select
|
||||||
|
hideLabel
|
||||||
|
size="sm"
|
||||||
|
name="interfaceFontSize"
|
||||||
|
label="Interface Font Size"
|
||||||
|
defaultValue="15"
|
||||||
|
value={`${settings.interfaceFontSize}`}
|
||||||
|
options={fontSizeOptions}
|
||||||
|
onChange={(v) => patchModel(settings, { interfaceFontSize: parseInt(v) })}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
|
<HStack space={2} alignItems="end">
|
||||||
|
{fonts.data && (
|
||||||
|
<Select
|
||||||
|
size="sm"
|
||||||
|
name="editorFont"
|
||||||
|
label="Editor Font"
|
||||||
|
value={settings.editorFont ?? NULL_FONT_VALUE}
|
||||||
|
options={[
|
||||||
|
{ label: 'System Default', value: NULL_FONT_VALUE },
|
||||||
|
...(fonts.data.editorFonts.map((f) => ({
|
||||||
|
label: f,
|
||||||
|
value: f,
|
||||||
|
})) ?? []),
|
||||||
|
]}
|
||||||
|
onChange={async (v) => {
|
||||||
|
const editorFont = v === NULL_FONT_VALUE ? null : v;
|
||||||
|
await patchModel(settings, { editorFont });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Select
|
||||||
|
hideLabel
|
||||||
|
size="sm"
|
||||||
|
name="editorFontSize"
|
||||||
|
label="Editor Font Size"
|
||||||
|
defaultValue="13"
|
||||||
|
value={`${settings.editorFontSize}`}
|
||||||
|
options={fontSizeOptions}
|
||||||
|
onChange={(v) =>
|
||||||
|
patchModel(settings, { editorFontSize: clamp(parseInt(v) || 14, 8, 30) })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
|
<Select
|
||||||
|
leftSlot={<Icon icon="keyboard" color="secondary" />}
|
||||||
|
size="sm"
|
||||||
|
name="editorKeymap"
|
||||||
|
label="Editor Keymap"
|
||||||
|
value={`${settings.editorKeymap}`}
|
||||||
|
options={keymaps}
|
||||||
|
onChange={(v) => patchModel(settings, { editorKeymap: v })}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
checked={settings.editorSoftWrap}
|
||||||
|
title="Wrap Editor Lines"
|
||||||
|
onChange={(editorSoftWrap) => patchModel(settings, { editorSoftWrap })}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
checked={settings.coloredMethods}
|
||||||
|
title="Colorize Request Methods"
|
||||||
|
onChange={(coloredMethods) => patchModel(settings, { coloredMethods })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{type() !== 'macos' && (
|
||||||
|
<Checkbox
|
||||||
|
checked={settings.hideWindowControls}
|
||||||
|
title="Hide Window Controls"
|
||||||
|
help="Hide the close/maximize/minimize controls on Windows or Linux"
|
||||||
|
onChange={(hideWindowControls) => patchModel(settings, { hideWindowControls })}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
);
|
||||||
|
}
|
||||||
+1
-123
@@ -1,38 +1,19 @@
|
|||||||
import { type } from '@tauri-apps/plugin-os';
|
|
||||||
import { useFonts } from '@yaakapp-internal/fonts';
|
|
||||||
import type { EditorKeymap } from '@yaakapp-internal/models';
|
|
||||||
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
||||||
import { useResolvedAppearance } from '../../hooks/useResolvedAppearance';
|
import { useResolvedAppearance } from '../../hooks/useResolvedAppearance';
|
||||||
import { useResolvedTheme } from '../../hooks/useResolvedTheme';
|
import { useResolvedTheme } from '../../hooks/useResolvedTheme';
|
||||||
import { clamp } from '../../lib/clamp';
|
|
||||||
import { getThemes } from '../../lib/theme/themes';
|
import { getThemes } from '../../lib/theme/themes';
|
||||||
import { isThemeDark } from '../../lib/theme/window';
|
import { isThemeDark } from '../../lib/theme/window';
|
||||||
import type { ButtonProps } from '../core/Button';
|
import type { ButtonProps } from '../core/Button';
|
||||||
import { Checkbox } from '../core/Checkbox';
|
|
||||||
import { Editor } from '../core/Editor/Editor';
|
import { Editor } from '../core/Editor/Editor';
|
||||||
import type { IconProps } from '../core/Icon';
|
import type { IconProps } from '../core/Icon';
|
||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { IconButton } from '../core/IconButton';
|
import { IconButton } from '../core/IconButton';
|
||||||
import { Select, SelectProps } from '../core/Select';
|
import { Select, SelectProps } from '../core/Select';
|
||||||
import { Separator } from '../core/Separator';
|
|
||||||
import { HStack, VStack } from '../core/Stacks';
|
import { HStack, VStack } from '../core/Stacks';
|
||||||
|
|
||||||
const NULL_FONT_VALUE = '__NULL_FONT__';
|
|
||||||
|
|
||||||
const fontSizeOptions = [
|
|
||||||
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 keymaps: { value: EditorKeymap; label: string }[] = [
|
|
||||||
{ value: 'default', label: 'Default' },
|
|
||||||
{ value: 'vim', label: 'Vim' },
|
|
||||||
{ value: 'vscode', label: 'VSCode' },
|
|
||||||
{ value: 'emacs', label: 'Emacs' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const buttonColors: ButtonProps['color'][] = [
|
const buttonColors: ButtonProps['color'][] = [
|
||||||
'primary',
|
'primary',
|
||||||
'info',
|
'info',
|
||||||
@@ -64,12 +45,11 @@ const icons: IconProps['icon'][] = [
|
|||||||
|
|
||||||
const { themes } = getThemes();
|
const { themes } = getThemes();
|
||||||
|
|
||||||
export function SettingsAppearance() {
|
export function SettingsTheme() {
|
||||||
const workspace = useAtomValue(activeWorkspaceAtom);
|
const workspace = useAtomValue(activeWorkspaceAtom);
|
||||||
const settings = useAtomValue(settingsAtom);
|
const settings = useAtomValue(settingsAtom);
|
||||||
const appearance = useResolvedAppearance();
|
const appearance = useResolvedAppearance();
|
||||||
const activeTheme = useResolvedTheme();
|
const activeTheme = useResolvedTheme();
|
||||||
const fonts = useFonts();
|
|
||||||
|
|
||||||
if (settings == null || workspace == null) {
|
if (settings == null || workspace == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -91,108 +71,6 @@ export function SettingsAppearance() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack space={3} className="mb-4">
|
<VStack space={3} className="mb-4">
|
||||||
<HStack space={2} alignItems="end">
|
|
||||||
{fonts.data && (
|
|
||||||
<Select
|
|
||||||
size="sm"
|
|
||||||
name="uiFont"
|
|
||||||
label="Interface Font"
|
|
||||||
value={settings.interfaceFont ?? NULL_FONT_VALUE}
|
|
||||||
options={[
|
|
||||||
{ label: 'System Default', value: NULL_FONT_VALUE },
|
|
||||||
...(fonts.data.uiFonts.map((f) => ({
|
|
||||||
label: f,
|
|
||||||
value: f,
|
|
||||||
})) ?? []),
|
|
||||||
// Some people like monospace fonts for the UI
|
|
||||||
...(fonts.data.editorFonts.map((f) => ({
|
|
||||||
label: f,
|
|
||||||
value: f,
|
|
||||||
})) ?? []),
|
|
||||||
]}
|
|
||||||
onChange={async (v) => {
|
|
||||||
const interfaceFont = v === NULL_FONT_VALUE ? null : v;
|
|
||||||
await patchModel(settings, { interfaceFont });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Select
|
|
||||||
hideLabel
|
|
||||||
size="sm"
|
|
||||||
name="interfaceFontSize"
|
|
||||||
label="Interface Font Size"
|
|
||||||
defaultValue="15"
|
|
||||||
value={`${settings.interfaceFontSize}`}
|
|
||||||
options={fontSizeOptions}
|
|
||||||
onChange={(v) => patchModel(settings, { interfaceFontSize: parseInt(v) })}
|
|
||||||
/>
|
|
||||||
</HStack>
|
|
||||||
<HStack space={2} alignItems="end">
|
|
||||||
{fonts.data && (
|
|
||||||
<Select
|
|
||||||
size="sm"
|
|
||||||
name="editorFont"
|
|
||||||
label="Editor Font"
|
|
||||||
value={settings.editorFont ?? NULL_FONT_VALUE}
|
|
||||||
options={[
|
|
||||||
{ label: 'System Default', value: NULL_FONT_VALUE },
|
|
||||||
...(fonts.data.editorFonts.map((f) => ({
|
|
||||||
label: f,
|
|
||||||
value: f,
|
|
||||||
})) ?? []),
|
|
||||||
]}
|
|
||||||
onChange={async (v) => {
|
|
||||||
const editorFont = v === NULL_FONT_VALUE ? null : v;
|
|
||||||
await patchModel(settings, { editorFont });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Select
|
|
||||||
hideLabel
|
|
||||||
size="sm"
|
|
||||||
name="editorFontSize"
|
|
||||||
label="Editor Font Size"
|
|
||||||
defaultValue="13"
|
|
||||||
value={`${settings.editorFontSize}`}
|
|
||||||
options={fontSizeOptions}
|
|
||||||
onChange={(v) =>
|
|
||||||
patchModel(settings, { editorFontSize: clamp(parseInt(v) || 14, 8, 30) })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</HStack>
|
|
||||||
<Select
|
|
||||||
leftSlot={<Icon icon="keyboard" color="secondary" />}
|
|
||||||
size="sm"
|
|
||||||
name="editorKeymap"
|
|
||||||
label="Editor Keymap"
|
|
||||||
value={`${settings.editorKeymap}`}
|
|
||||||
options={keymaps}
|
|
||||||
onChange={(v) => patchModel(settings, { editorKeymap: v })}
|
|
||||||
/>
|
|
||||||
<div className="grid grid-cols-2">
|
|
||||||
<Checkbox
|
|
||||||
checked={settings.editorSoftWrap}
|
|
||||||
title="Wrap Editor Lines"
|
|
||||||
onChange={(editorSoftWrap) => patchModel(settings, { editorSoftWrap })}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
checked={settings.coloredMethods}
|
|
||||||
title="Colorize Request Methods"
|
|
||||||
onChange={(coloredMethods) => patchModel(settings, { coloredMethods })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{type() !== 'macos' && (
|
|
||||||
<Checkbox
|
|
||||||
checked={settings.hideWindowControls}
|
|
||||||
title="Hide Window Controls"
|
|
||||||
help="Hide the close/maximize/minimize controls on Windows or Linux"
|
|
||||||
onChange={(hideWindowControls) => patchModel(settings, { hideWindowControls })}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Separator className="my-4" />
|
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
name="appearance"
|
name="appearance"
|
||||||
label="Appearance"
|
label="Appearance"
|
||||||
Reference in New Issue
Block a user