Run oxfmt across repo, add format script and docs

Add .oxfmtignore to skip generated bindings and wasm-pack output.
Add npm format script, update DEVELOPMENT.md for Vite+ toolchain,
and format all non-generated files with oxfmt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-03-13 10:15:49 -07:00
parent 45262edfbd
commit b4a1c418bb
664 changed files with 13638 additions and 13492 deletions

View File

@@ -1,39 +1,39 @@
import { useSearch } from '@tanstack/react-router';
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
import { type } from '@tauri-apps/plugin-os';
import { useLicense } from '@yaakapp-internal/license';
import { pluginsAtom, settingsAtom } from '@yaakapp-internal/models';
import classNames from 'classnames';
import { useAtomValue } from 'jotai';
import { useKeyPressEvent } from 'react-use';
import { appInfo } from '../../lib/appInfo';
import { capitalize } from '../../lib/capitalize';
import { CountBadge } from '../core/CountBadge';
import { Icon } from '../core/Icon';
import { HStack } from '../core/Stacks';
import { TabContent, type TabItem, Tabs } from '../core/Tabs/Tabs';
import { HeaderSize } from '../HeaderSize';
import { SettingsCertificates } from './SettingsCertificates';
import { SettingsGeneral } from './SettingsGeneral';
import { SettingsHotkeys } from './SettingsHotkeys';
import { SettingsInterface } from './SettingsInterface';
import { SettingsLicense } from './SettingsLicense';
import { SettingsPlugins } from './SettingsPlugins';
import { SettingsProxy } from './SettingsProxy';
import { SettingsTheme } from './SettingsTheme';
import { useSearch } from "@tanstack/react-router";
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
import { type } from "@tauri-apps/plugin-os";
import { useLicense } from "@yaakapp-internal/license";
import { pluginsAtom, settingsAtom } from "@yaakapp-internal/models";
import classNames from "classnames";
import { useAtomValue } from "jotai";
import { useKeyPressEvent } from "react-use";
import { appInfo } from "../../lib/appInfo";
import { capitalize } from "../../lib/capitalize";
import { CountBadge } from "../core/CountBadge";
import { Icon } from "../core/Icon";
import { HStack } from "../core/Stacks";
import { TabContent, type TabItem, Tabs } from "../core/Tabs/Tabs";
import { HeaderSize } from "../HeaderSize";
import { SettingsCertificates } from "./SettingsCertificates";
import { SettingsGeneral } from "./SettingsGeneral";
import { SettingsHotkeys } from "./SettingsHotkeys";
import { SettingsInterface } from "./SettingsInterface";
import { SettingsLicense } from "./SettingsLicense";
import { SettingsPlugins } from "./SettingsPlugins";
import { SettingsProxy } from "./SettingsProxy";
import { SettingsTheme } from "./SettingsTheme";
interface Props {
hide?: () => void;
}
const TAB_GENERAL = 'general';
const TAB_INTERFACE = 'interface';
const TAB_THEME = 'theme';
const TAB_SHORTCUTS = 'shortcuts';
const TAB_PROXY = 'proxy';
const TAB_CERTIFICATES = 'certificates';
const TAB_PLUGINS = 'plugins';
const TAB_LICENSE = 'license';
const TAB_GENERAL = "general";
const TAB_INTERFACE = "interface";
const TAB_THEME = "theme";
const TAB_SHORTCUTS = "shortcuts";
const TAB_PROXY = "proxy";
const TAB_CERTIFICATES = "certificates";
const TAB_PLUGINS = "plugins";
const TAB_LICENSE = "license";
const tabs = [
TAB_GENERAL,
TAB_THEME,
@@ -47,16 +47,16 @@ const tabs = [
export type SettingsTab = (typeof tabs)[number];
export default function Settings({ hide }: Props) {
const { tab: tabFromQuery } = useSearch({ from: '/workspaces/$workspaceId/settings' });
const { tab: tabFromQuery } = useSearch({ from: "/workspaces/$workspaceId/settings" });
// Parse tab and subtab (e.g., "plugins:installed")
const [mainTab, subtab] = tabFromQuery?.split(':') ?? [];
const [mainTab, subtab] = tabFromQuery?.split(":") ?? [];
const settings = useAtomValue(settingsAtom);
const plugins = useAtomValue(pluginsAtom);
const licenseCheck = useLicense();
// 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', async () => {
useKeyPressEvent("Escape", async () => {
if (hide != null) {
// It's being shown in a dialog, so close the dialog
hide();
@@ -67,7 +67,7 @@ export default function Settings({ hide }: Props) {
});
return (
<div className={classNames('grid grid-rows-[auto_minmax(0,1fr)] h-full')}>
<div className={classNames("grid grid-rows-[auto_minmax(0,1fr)] h-full")}>
{hide ? (
<span />
) : (
@@ -83,7 +83,7 @@ export default function Settings({ hide }: Props) {
justifyContent="center"
className="w-full h-full grid grid-cols-[1fr_auto] pointer-events-none"
>
<div className={classNames(type() === 'macos' ? 'text-center' : 'pl-2')}>Settings</div>
<div className={classNames(type() === "macos" ? "text-center" : "pl-2")}>Settings</div>
</HStack>
</HeaderSize>
)}
@@ -120,10 +120,10 @@ export default function Settings({ hide }: Props) {
value === TAB_CERTIFICATES ? (
<CountBadge count={settings.clientCertificates.length} />
) : value === TAB_PLUGINS ? (
<CountBadge count={plugins.filter((p) => p.source !== 'bundled').length} />
) : value === TAB_PROXY && settings.proxy?.type === 'enabled' ? (
<CountBadge count={plugins.filter((p) => p.source !== "bundled").length} />
) : value === TAB_PROXY && settings.proxy?.type === "enabled" ? (
<CountBadge count />
) : value === TAB_LICENSE && licenseCheck.check.data?.status === 'personal_use' ? (
) : value === TAB_LICENSE && licenseCheck.check.data?.status === "personal_use" ? (
<CountBadge count color="notice" />
) : null,
}),

View File

@@ -1,22 +1,22 @@
import type { ClientCertificate } from '@yaakapp-internal/models';
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import { useAtomValue } from 'jotai';
import { useRef } from 'react';
import { showConfirmDelete } from '../../lib/confirm';
import { Button } from '../core/Button';
import { Checkbox } from '../core/Checkbox';
import { DetailsBanner } from '../core/DetailsBanner';
import { Heading } from '../core/Heading';
import { IconButton } from '../core/IconButton';
import { InlineCode } from '../core/InlineCode';
import { PlainInput } from '../core/PlainInput';
import { Separator } from '../core/Separator';
import { HStack, VStack } from '../core/Stacks';
import { SelectFile } from '../SelectFile';
import type { ClientCertificate } from "@yaakapp-internal/models";
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import { useAtomValue } from "jotai";
import { useRef } from "react";
import { showConfirmDelete } from "../../lib/confirm";
import { Button } from "../core/Button";
import { Checkbox } from "../core/Checkbox";
import { DetailsBanner } from "../core/DetailsBanner";
import { Heading } from "../core/Heading";
import { IconButton } from "../core/IconButton";
import { InlineCode } from "../core/InlineCode";
import { PlainInput } from "../core/PlainInput";
import { Separator } from "../core/Separator";
import { HStack, VStack } from "../core/Stacks";
import { SelectFile } from "../SelectFile";
function createEmptyCertificate(): ClientCertificate {
return {
host: '',
host: "",
port: null,
crtFile: null,
keyFile: null,
@@ -44,11 +44,11 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
const hasPfx = Boolean(certificate.pfxFile && certificate.pfxFile.length > 0);
const hasCrtKey = Boolean(
(certificate.crtFile && certificate.crtFile.length > 0) ||
(certificate.keyFile && certificate.keyFile.length > 0),
(certificate.keyFile && certificate.keyFile.length > 0),
);
// Determine certificate type for display
const certType = hasPfx ? 'PFX' : hasCrtKey ? 'CERT' : null;
const certType = hasPfx ? "PFX" : hasCrtKey ? "CERT" : null;
const defaultOpen = useRef<boolean>(!certificate.host);
return (
@@ -60,9 +60,9 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
<Checkbox
className="ml-1"
checked={certificate.enabled ?? true}
title={certificate.enabled ? 'Disable certificate' : 'Enable certificate'}
title={certificate.enabled ? "Disable certificate" : "Enable certificate"}
hideLabel
onChange={(enabled) => updateField('enabled', enabled)}
onChange={(enabled) => updateField("enabled", enabled)}
/>
{certificate.host ? (
@@ -103,7 +103,7 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
size="sm"
required
defaultValue={certificate.host}
onChange={(host) => updateField('host', host)}
onChange={(host) => updateField("host", host)}
/>
<PlainInput
label="Port"
@@ -121,8 +121,8 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
}
size="sm"
className="w-24"
defaultValue={certificate.port?.toString() ?? ''}
onChange={(port) => updateField('port', port ? parseInt(port, 10) : null)}
defaultValue={certificate.port?.toString() ?? ""}
onChange={(port) => updateField("port", port ? parseInt(port, 10) : null)}
/>
</HStack>
@@ -135,7 +135,7 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
filePath={certificate.crtFile ?? null}
size="sm"
disabled={hasPfx}
onChange={({ filePath }) => updateField('crtFile', filePath)}
onChange={({ filePath }) => updateField("crtFile", filePath)}
/>
<SelectFile
label="KEY File"
@@ -143,7 +143,7 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
filePath={certificate.keyFile ?? null}
size="sm"
disabled={hasPfx}
onChange={({ filePath }) => updateField('keyFile', filePath)}
onChange={({ filePath }) => updateField("keyFile", filePath)}
/>
</VStack>
@@ -155,15 +155,15 @@ function CertificateEditor({ certificate, index, onUpdate, onRemove }: Certifica
filePath={certificate.pfxFile ?? null}
size="sm"
disabled={hasCrtKey}
onChange={({ filePath }) => updateField('pfxFile', filePath)}
onChange={({ filePath }) => updateField("pfxFile", filePath)}
/>
<PlainInput
label="Passphrase"
size="sm"
type="password"
defaultValue={certificate.passphrase ?? ''}
onChange={(passphrase) => updateField('passphrase', passphrase || null)}
defaultValue={certificate.passphrase ?? ""}
onChange={(passphrase) => updateField("passphrase", passphrase || null)}
/>
</VStack>
</DetailsBanner>
@@ -193,15 +193,15 @@ export function SettingsCertificates() {
const cert = certificates[index];
if (cert == null) return;
const host = cert.host || 'this certificate';
const port = cert.port != null ? `:${cert.port}` : '';
const host = cert.host || "this certificate";
const port = cert.port != null ? `:${cert.port}` : "";
const confirmed = await showConfirmDelete({
id: 'confirm-remove-certificate',
title: 'Delete Certificate',
id: "confirm-remove-certificate",
title: "Delete Certificate",
description: (
<>
Permanently delete certificate for{' '}
Permanently delete certificate for{" "}
<InlineCode>
{host}
{port}

View File

@@ -1,19 +1,19 @@
import { revealItemInDir } from '@tauri-apps/plugin-opener';
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import { useAtomValue } from 'jotai';
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
import { useCheckForUpdates } from '../../hooks/useCheckForUpdates';
import { appInfo } from '../../lib/appInfo';
import { revealInFinderText } from '../../lib/reveal';
import { CargoFeature } from '../CargoFeature';
import { Checkbox } from '../core/Checkbox';
import { Heading } from '../core/Heading';
import { IconButton } from '../core/IconButton';
import { KeyValueRow, KeyValueRows } from '../core/KeyValueRow';
import { PlainInput } from '../core/PlainInput';
import { Select } from '../core/Select';
import { Separator } from '../core/Separator';
import { VStack } from '../core/Stacks';
import { revealItemInDir } from "@tauri-apps/plugin-opener";
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import { useAtomValue } from "jotai";
import { activeWorkspaceAtom } from "../../hooks/useActiveWorkspace";
import { useCheckForUpdates } from "../../hooks/useCheckForUpdates";
import { appInfo } from "../../lib/appInfo";
import { revealInFinderText } from "../../lib/reveal";
import { CargoFeature } from "../CargoFeature";
import { Checkbox } from "../core/Checkbox";
import { Heading } from "../core/Heading";
import { IconButton } from "../core/IconButton";
import { KeyValueRow, KeyValueRows } from "../core/KeyValueRow";
import { PlainInput } from "../core/PlainInput";
import { Select } from "../core/Select";
import { Separator } from "../core/Separator";
import { VStack } from "../core/Stacks";
export function SettingsGeneral() {
const workspace = useAtomValue(activeWorkspaceAtom);
@@ -41,8 +41,8 @@ export function SettingsGeneral() {
value={settings.updateChannel}
onChange={(updateChannel) => patchModel(settings, { updateChannel })}
options={[
{ label: 'Stable', value: 'stable' },
{ label: 'Beta (more frequent)', value: 'beta' },
{ label: "Stable", value: "stable" },
{ label: "Beta (more frequent)", value: "beta" },
]}
/>
<IconButton
@@ -57,15 +57,15 @@ export function SettingsGeneral() {
<Select
name="autoupdate"
value={settings.autoupdate ? 'auto' : 'manual'}
value={settings.autoupdate ? "auto" : "manual"}
label="Update Behavior"
labelPosition="left"
size="sm"
labelClassName="w-[14rem]"
onChange={(v) => patchModel(settings, { autoupdate: v === 'auto' })}
onChange={(v) => patchModel(settings, { autoupdate: v === "auto" })}
options={[
{ label: 'Automatic', value: 'auto' },
{ label: 'Manual', value: 'manual' },
{ label: "Automatic", value: "auto" },
{ label: "Manual", value: "manual" },
]}
/>
<Checkbox
@@ -97,7 +97,7 @@ export function SettingsGeneral() {
<Separator className="my-4" />
<Heading level={2}>
Workspace{' '}
Workspace{" "}
<div className="inline-block ml-1 bg-surface-highlight px-2 py-0.5 rounded text text-shrink">
{workspace.name}
</div>

View File

@@ -1,8 +1,8 @@
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import classNames from 'classnames';
import { fuzzyMatch } from 'fuzzbunny';
import { useAtomValue } from 'jotai';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import classNames from "classnames";
import { fuzzyMatch } from "fuzzbunny";
import { useAtomValue } from "jotai";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
defaultHotkeys,
formatHotkeyString,
@@ -11,27 +11,27 @@ import {
hotkeyActions,
hotkeysAtom,
useHotkeyLabel,
} from '../../hooks/useHotKey';
import { capitalize } from '../../lib/capitalize';
import { showDialog } from '../../lib/dialog';
import { Button } from '../core/Button';
import { Dropdown, type DropdownItem } from '../core/Dropdown';
import { Heading } from '../core/Heading';
import { HotkeyRaw } from '../core/Hotkey';
import { Icon } from '../core/Icon';
import { IconButton } from '../core/IconButton';
import { PlainInput } from '../core/PlainInput';
import { HStack, VStack } from '../core/Stacks';
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '../core/Table';
} from "../../hooks/useHotKey";
import { capitalize } from "../../lib/capitalize";
import { showDialog } from "../../lib/dialog";
import { Button } from "../core/Button";
import { Dropdown, type DropdownItem } from "../core/Dropdown";
import { Heading } from "../core/Heading";
import { HotkeyRaw } from "../core/Hotkey";
import { Icon } from "../core/Icon";
import { IconButton } from "../core/IconButton";
import { PlainInput } from "../core/PlainInput";
import { HStack, VStack } from "../core/Stacks";
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "../core/Table";
const HOLD_KEYS = ['Shift', 'Control', 'Alt', 'Meta'];
const HOLD_KEYS = ["Shift", "Control", "Alt", "Meta"];
const LAYOUT_INSENSITIVE_KEYS = [
'Equal',
'Minus',
'BracketLeft',
'BracketRight',
'Backquote',
'Space',
"Equal",
"Minus",
"BracketLeft",
"BracketRight",
"Backquote",
"Space",
];
/** Convert a KeyboardEvent to a hotkey string like "Meta+Shift+k" or "Control+Shift+k" */
@@ -45,37 +45,37 @@ function eventToHotkeyString(e: KeyboardEvent): string | null {
// Add modifiers in consistent order (Meta, Control, Alt, Shift)
if (e.metaKey) {
parts.push('Meta');
parts.push("Meta");
}
if (e.ctrlKey) {
parts.push('Control');
parts.push("Control");
}
if (e.altKey) {
parts.push('Alt');
parts.push("Alt");
}
if (e.shiftKey) {
parts.push('Shift');
parts.push("Shift");
}
// Get the main key - use the same logic as useHotKey.ts
const key = LAYOUT_INSENSITIVE_KEYS.includes(e.code) ? e.code : e.key;
parts.push(key);
return parts.join('+');
return parts.join("+");
}
export function SettingsHotkeys() {
const settings = useAtomValue(settingsAtom);
const hotkeys = useAtomValue(hotkeysAtom);
const [filter, setFilter] = useState('');
const [filter, setFilter] = useState("");
const filteredActions = useMemo(() => {
if (!filter.trim()) {
return hotkeyActions;
}
return hotkeyActions.filter((action) => {
const scope = getHotkeyScope(action).replace(/_/g, ' ');
const label = action.replace(/[_.]/g, ' ');
const scope = getHotkeyScope(action).replace(/_/g, " ");
const label = action.replace(/[_.]/g, " ");
const searchText = `${scope} ${label}`;
return fuzzyMatch(searchText, filter) != null;
});
@@ -152,7 +152,7 @@ interface HotkeyRowProps {
function HotkeyRow({ action, currentKeys, defaultKeys, onSave, onReset }: HotkeyRowProps) {
const label = useHotkeyLabel(action);
const scope = capitalize(getHotkeyScope(action).replace(/_/g, ' '));
const scope = capitalize(getHotkeyScope(action).replace(/_/g, " "));
const isCustomized = !arraysEqual(currentKeys, defaultKeys);
const isDisabled = currentKeys.length === 0;
@@ -160,7 +160,7 @@ function HotkeyRow({ action, currentKeys, defaultKeys, onSave, onReset }: Hotkey
showDialog({
id: `record-hotkey-${action}`,
title: label,
size: 'sm',
size: "sm",
render: ({ hide }) => (
<RecordHotkeyDialog
label={label}
@@ -189,7 +189,7 @@ function HotkeyRow({ action, currentKeys, defaultKeys, onSave, onReset }: Hotkey
// Build dropdown items dynamically
const dropdownItems: DropdownItem[] = [
{
label: 'Add Keyboard Shortcut',
label: "Add Keyboard Shortcut",
leftSlot: <Icon icon="plus" />,
onSelect: handleStartRecording,
},
@@ -213,10 +213,10 @@ function HotkeyRow({ action, currentKeys, defaultKeys, onSave, onReset }: Hotkey
if (currentKeys.length > 1) {
dropdownItems.push(
{
type: 'separator',
type: "separator",
},
{
label: 'Remove All Shortcuts',
label: "Remove All Shortcuts",
leftSlot: <Icon icon="trash" />,
onSelect: handleClearAll,
},
@@ -226,10 +226,10 @@ function HotkeyRow({ action, currentKeys, defaultKeys, onSave, onReset }: Hotkey
if (isCustomized) {
dropdownItems.push({
type: 'separator',
type: "separator",
});
dropdownItems.push({
label: 'Reset to Default',
label: "Reset to Default",
leftSlot: <Icon icon="refresh" />,
onSelect: onReset,
});
@@ -292,7 +292,7 @@ function RecordHotkeyDialog({ label, onSave, onCancel }: RecordHotkeyDialogProps
e.preventDefault();
e.stopPropagation();
if (e.key === 'Escape') {
if (e.key === "Escape") {
onCancel();
return;
}
@@ -303,9 +303,9 @@ function RecordHotkeyDialog({ label, onSave, onCancel }: RecordHotkeyDialogProps
}
};
window.addEventListener('keydown', handleKeyDown, { capture: true });
window.addEventListener("keydown", handleKeyDown, { capture: true });
return () => {
window.removeEventListener('keydown', handleKeyDown, { capture: true });
window.removeEventListener("keydown", handleKeyDown, { capture: true });
};
}, [isFocused, onCancel]);
@@ -332,9 +332,9 @@ function RecordHotkeyDialog({ label, onSave, onCancel }: RecordHotkeyDialogProps
e.currentTarget.focus();
}}
className={classNames(
'flex items-center justify-center',
'px-4 py-2 rounded-lg bg-surface-highlight border outline-none cursor-default w-full',
'border-border-subtle focus:border-border-focus',
"flex items-center justify-center",
"px-4 py-2 rounded-lg bg-surface-highlight border outline-none cursor-default w-full",
"border-border-subtle focus:border-border-focus",
)}
>
{recordedKey ? (

View File

@@ -1,35 +1,35 @@
import { type } from '@tauri-apps/plugin-os';
import { useFonts } from '@yaakapp-internal/fonts';
import { useLicense } from '@yaakapp-internal/license';
import type { EditorKeymap, Settings } from '@yaakapp-internal/models';
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import { useAtomValue } from 'jotai';
import { useState } from 'react';
import { type } from "@tauri-apps/plugin-os";
import { useFonts } from "@yaakapp-internal/fonts";
import { useLicense } from "@yaakapp-internal/license";
import type { EditorKeymap, Settings } from "@yaakapp-internal/models";
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import { useAtomValue } from "jotai";
import { useState } from "react";
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
import { clamp } from '../../lib/clamp';
import { showConfirm } from '../../lib/confirm';
import { invokeCmd } from '../../lib/tauri';
import { CargoFeature } from '../CargoFeature';
import { Button } from '../core/Button';
import { Checkbox } from '../core/Checkbox';
import { Heading } from '../core/Heading';
import { Icon } from '../core/Icon';
import { Link } from '../core/Link';
import { Select } from '../core/Select';
import { HStack, VStack } from '../core/Stacks';
import { activeWorkspaceAtom } from "../../hooks/useActiveWorkspace";
import { clamp } from "../../lib/clamp";
import { showConfirm } from "../../lib/confirm";
import { invokeCmd } from "../../lib/tauri";
import { CargoFeature } from "../CargoFeature";
import { Button } from "../core/Button";
import { Checkbox } from "../core/Checkbox";
import { Heading } from "../core/Heading";
import { Icon } from "../core/Icon";
import { Link } from "../core/Link";
import { Select } from "../core/Select";
import { HStack, VStack } from "../core/Stacks";
const NULL_FONT_VALUE = '__NULL_FONT__';
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' },
{ value: "default", label: "Default" },
{ value: "vim", label: "Vim" },
{ value: "vscode", label: "VSCode" },
{ value: "emacs", label: "Emacs" },
];
export function SettingsInterface() {
@@ -54,20 +54,20 @@ export function SettingsInterface() {
help="When opening a workspace, should it open in the current window or a new window?"
value={
settings.openWorkspaceNewWindow === true
? 'new'
? "new"
: settings.openWorkspaceNewWindow === false
? 'current'
: 'ask'
? "current"
: "ask"
}
onChange={async (v) => {
if (v === 'current') await patchModel(settings, { openWorkspaceNewWindow: false });
else if (v === 'new') await patchModel(settings, { openWorkspaceNewWindow: true });
if (v === "current") await patchModel(settings, { openWorkspaceNewWindow: false });
else if (v === "new") await patchModel(settings, { openWorkspaceNewWindow: true });
else await patchModel(settings, { openWorkspaceNewWindow: null });
}}
options={[
{ label: 'Always ask', value: 'ask' },
{ label: 'Open in current window', value: 'current' },
{ label: 'Open in new window', value: 'new' },
{ label: "Always ask", value: "ask" },
{ label: "Open in current window", value: "current" },
{ label: "Open in new window", value: "new" },
]}
/>
<HStack space={2} alignItems="end">
@@ -78,7 +78,7 @@ export function SettingsInterface() {
label="Interface font"
value={settings.interfaceFont ?? NULL_FONT_VALUE}
options={[
{ label: 'System default', value: NULL_FONT_VALUE },
{ label: "System default", value: NULL_FONT_VALUE },
...(fonts.data.uiFonts.map((f) => ({
label: f,
value: f,
@@ -114,7 +114,7 @@ export function SettingsInterface() {
label="Editor font"
value={settings.editorFont ?? NULL_FONT_VALUE}
options={[
{ label: 'System default', value: NULL_FONT_VALUE },
{ label: "System default", value: NULL_FONT_VALUE },
...(fonts.data.editorFonts.map((f) => ({
label: f,
value: f,
@@ -164,7 +164,7 @@ export function SettingsInterface() {
<NativeTitlebarSetting settings={settings} />
{type() !== 'macos' && (
{type() !== "macos" && (
<Checkbox
checked={settings.hideWindowControls}
title="Hide window controls"
@@ -192,7 +192,7 @@ function NativeTitlebarSetting({ settings }: { settings: Settings }) {
size="2xs"
onClick={async () => {
await patchModel(settings, { useNativeTitlebar: nativeTitlebar });
await invokeCmd('cmd_restart');
await invokeCmd("cmd_restart");
}}
>
Apply and Restart
@@ -204,7 +204,7 @@ function NativeTitlebarSetting({ settings }: { settings: Settings }) {
function LicenseSettings({ settings }: { settings: Settings }) {
const license = useLicense();
if (license.check.data?.status !== 'personal_use') {
if (license.check.data?.status !== "personal_use") {
return null;
}
@@ -215,24 +215,24 @@ function LicenseSettings({ settings }: { settings: Settings }) {
onChange={async (hideLicenseBadge) => {
if (hideLicenseBadge) {
const confirmed = await showConfirm({
id: 'hide-license-badge',
title: 'Confirm Personal Use',
confirmText: 'Confirm',
id: "hide-license-badge",
title: "Confirm Personal Use",
confirmText: "Confirm",
description: (
<VStack space={3}>
<p>Hey there 👋🏼</p>
<p>
Yaak is free for personal projects and learning.{' '}
Yaak is free for personal projects and learning.{" "}
<strong>If youre using Yaak at work, a license is required.</strong>
</p>
<p>
Licenses help keep Yaak independent and sustainable.{' '}
Licenses help keep Yaak independent and sustainable.{" "}
<Link href="https://yaak.app/pricing?s=badge">Purchase a License </Link>
</p>
</VStack>
),
requireTyping: 'Personal Use',
color: 'info',
requireTyping: "Personal Use",
color: "info",
});
if (!confirmed) {
return; // Cancel

View File

@@ -1,18 +1,18 @@
import { openUrl } from '@tauri-apps/plugin-opener';
import { useLicense } from '@yaakapp-internal/license';
import { differenceInDays } from 'date-fns';
import { formatDate } from 'date-fns/format';
import { useState } from 'react';
import { useToggle } from '../../hooks/useToggle';
import { pluralizeCount } from '../../lib/pluralize';
import { CargoFeature } from '../CargoFeature';
import { Banner } from '../core/Banner';
import { Button } from '../core/Button';
import { Icon } from '../core/Icon';
import { Link } from '../core/Link';
import { PlainInput } from '../core/PlainInput';
import { Separator } from '../core/Separator';
import { HStack, VStack } from '../core/Stacks';
import { openUrl } from "@tauri-apps/plugin-opener";
import { useLicense } from "@yaakapp-internal/license";
import { differenceInDays } from "date-fns";
import { formatDate } from "date-fns/format";
import { useState } from "react";
import { useToggle } from "../../hooks/useToggle";
import { pluralizeCount } from "../../lib/pluralize";
import { CargoFeature } from "../CargoFeature";
import { Banner } from "../core/Banner";
import { Button } from "../core/Button";
import { Icon } from "../core/Icon";
import { Link } from "../core/Link";
import { PlainInput } from "../core/PlainInput";
import { Separator } from "../core/Separator";
import { HStack, VStack } from "../core/Stacks";
export function SettingsLicense() {
return (
@@ -24,7 +24,7 @@ export function SettingsLicense() {
function SettingsLicenseCmp() {
const { check, activate, deactivate } = useLicense();
const [key, setKey] = useState<string>('');
const [key, setKey] = useState<string>("");
const [activateFormVisible, toggleActivateFormVisible] = useToggle(false);
if (check.isPending) {
@@ -35,16 +35,16 @@ function SettingsLicenseCmp() {
if (!check.data) return null;
switch (check.data.status) {
case 'active':
case "active":
return <Banner color="success">Your license is active 🥳</Banner>;
case 'trialing':
case "trialing":
return (
<Banner color="info" className="max-w-lg">
<p className="w-full">
<strong>
{pluralizeCount('day', differenceInDays(check.data.data.end, new Date()))}
</strong>{' '}
{pluralizeCount("day", differenceInDays(check.data.data.end, new Date()))}
</strong>{" "}
left to evaluate Yaak for commercial use.
<br />
<span className="opacity-50">Personal use is always free, forever.</span>
@@ -58,7 +58,7 @@ function SettingsLicenseCmp() {
</Banner>
);
case 'personal_use':
case "personal_use":
return (
<Banner color="notice" className="max-w-lg">
<p className="w-full">
@@ -78,19 +78,19 @@ function SettingsLicenseCmp() {
</Banner>
);
case 'inactive':
case "inactive":
return (
<Banner color="danger">
Your license is invalid. Please <Link href="https://yaak.app/dashboard">Sign In</Link>{' '}
Your license is invalid. Please <Link href="https://yaak.app/dashboard">Sign In</Link>{" "}
for more details
</Banner>
);
case 'expired':
case "expired":
return (
<Banner color="notice">
Your license expired{' '}
<strong>{formatDate(check.data.data.periodEnd, 'MMMM dd, yyyy')}</strong>. Please{' '}
Your license expired{" "}
<strong>{formatDate(check.data.data.periodEnd, "MMMM dd, yyyy")}</strong>. Please{" "}
<Link href="https://yaak.app/dashboard">Resubscribe</Link> to continue receiving
updates.
{check.data.data.changesUrl && (
@@ -102,17 +102,17 @@ function SettingsLicenseCmp() {
</Banner>
);
case 'past_due':
case "past_due":
return (
<Banner color="danger">
<strong>Your payment method needs attention.</strong>
<br />
To re-activate your license, please{' '}
To re-activate your license, please{" "}
<Link href={check.data.data.billingUrl}>update your billing info</Link>.
</Banner>
);
case 'error':
case "error":
return (
<Banner color="danger">
License check failed: {check.data.data.message} (Code: {check.data.data.code})
@@ -128,7 +128,7 @@ function SettingsLicenseCmp() {
{check.error && <Banner color="danger">{check.error}</Banner>}
{activate.error && <Banner color="danger">{activate.error}</Banner>}
{check.data?.status === 'active' ? (
{check.data?.status === "active" ? (
<HStack space={2}>
<Button variant="border" color="secondary" size="sm" onClick={() => deactivate.mutate()}>
Deactivate License
@@ -136,7 +136,7 @@ function SettingsLicenseCmp() {
<Button
color="secondary"
size="sm"
onClick={() => openUrl('https://yaak.app/dashboard?s=support&ref=app.yaak.desktop')}
onClick={() => openUrl("https://yaak.app/dashboard?s=support&ref=app.yaak.desktop")}
rightSlot={<Icon icon="external_link" />}
>
Direct Support
@@ -153,7 +153,7 @@ function SettingsLicenseCmp() {
rightSlot={<Icon icon="external_link" />}
onClick={() =>
openUrl(
`https://yaak.app/pricing?s=purchase&ref=app.yaak.desktop&t=${check.data?.status ?? ''}`,
`https://yaak.app/pricing?s=purchase&ref=app.yaak.desktop&t=${check.data?.status ?? ""}`,
)
}
>

View File

@@ -1,37 +1,37 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import { openUrl } from '@tauri-apps/plugin-opener';
import type { Plugin } from '@yaakapp-internal/models';
import { patchModel, pluginsAtom } from '@yaakapp-internal/models';
import type { PluginVersion } from '@yaakapp-internal/plugins';
import { useMutation, useQuery } from "@tanstack/react-query";
import { openUrl } from "@tauri-apps/plugin-opener";
import type { Plugin } from "@yaakapp-internal/models";
import { patchModel, pluginsAtom } from "@yaakapp-internal/models";
import type { PluginVersion } from "@yaakapp-internal/plugins";
import {
checkPluginUpdates,
installPlugin,
searchPlugins,
uninstallPlugin,
} from '@yaakapp-internal/plugins';
import classNames from 'classnames';
import { useAtomValue } from 'jotai';
import { useState } from 'react';
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
import { useInstallPlugin } from '../../hooks/useInstallPlugin';
import { usePluginInfo } from '../../hooks/usePluginInfo';
import { usePluginsKey, useRefreshPlugins } from '../../hooks/usePlugins';
import { showConfirmDelete } from '../../lib/confirm';
import { minPromiseMillis } from '../../lib/minPromiseMillis';
import { Button } from '../core/Button';
import { Checkbox } from '../core/Checkbox';
import { CountBadge } from '../core/CountBadge';
import { Icon } from '../core/Icon';
import { IconButton } from '../core/IconButton';
import { InlineCode } from '../core/InlineCode';
import { Link } from '../core/Link';
import { LoadingIcon } from '../core/LoadingIcon';
import { PlainInput } from '../core/PlainInput';
import { HStack } from '../core/Stacks';
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '../core/Table';
import { TabContent, Tabs } from '../core/Tabs/Tabs';
import { EmptyStateText } from '../EmptyStateText';
import { SelectFile } from '../SelectFile';
} from "@yaakapp-internal/plugins";
import classNames from "classnames";
import { useAtomValue } from "jotai";
import { useState } from "react";
import { useDebouncedValue } from "../../hooks/useDebouncedValue";
import { useInstallPlugin } from "../../hooks/useInstallPlugin";
import { usePluginInfo } from "../../hooks/usePluginInfo";
import { usePluginsKey, useRefreshPlugins } from "../../hooks/usePlugins";
import { showConfirmDelete } from "../../lib/confirm";
import { minPromiseMillis } from "../../lib/minPromiseMillis";
import { Button } from "../core/Button";
import { Checkbox } from "../core/Checkbox";
import { CountBadge } from "../core/CountBadge";
import { Icon } from "../core/Icon";
import { IconButton } from "../core/IconButton";
import { InlineCode } from "../core/InlineCode";
import { Link } from "../core/Link";
import { LoadingIcon } from "../core/LoadingIcon";
import { PlainInput } from "../core/PlainInput";
import { HStack } from "../core/Stacks";
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "../core/Table";
import { TabContent, Tabs } from "../core/Tabs/Tabs";
import { EmptyStateText } from "../EmptyStateText";
import { SelectFile } from "../SelectFile";
interface SettingsPluginsProps {
defaultSubtab?: string;
@@ -40,8 +40,8 @@ interface SettingsPluginsProps {
export function SettingsPlugins({ defaultSubtab }: SettingsPluginsProps) {
const [directory, setDirectory] = useState<string | null>(null);
const plugins = useAtomValue(pluginsAtom);
const bundledPlugins = plugins.filter((p) => p.source === 'bundled');
const installedPlugins = plugins.filter((p) => p.source !== 'bundled');
const bundledPlugins = plugins.filter((p) => p.source === "bundled");
const installedPlugins = plugins.filter((p) => p.source !== "bundled");
const createPlugin = useInstallPlugin();
const refreshPlugins = useRefreshPlugins();
return (
@@ -52,15 +52,15 @@ export function SettingsPlugins({ defaultSubtab }: SettingsPluginsProps) {
addBorders
tabListClassName="px-6 pt-2"
tabs={[
{ label: 'Discover', value: 'search' },
{ label: "Discover", value: "search" },
{
label: 'Installed',
value: 'installed',
label: "Installed",
value: "installed",
rightSlot: <CountBadge count={installedPlugins.length} />,
},
{
label: 'Bundled',
value: 'bundled',
label: "Bundled",
value: "bundled",
rightSlot: <CountBadge count={bundledPlugins.length} />,
},
]}
@@ -106,7 +106,7 @@ export function SettingsPlugins({ defaultSubtab }: SettingsPluginsProps) {
icon="help"
title="View documentation"
onClick={() =>
openUrl('https://yaak.app/docs/plugin-development/plugins-quick-start')
openUrl("https://yaak.app/docs/plugin-development/plugins-quick-start")
}
/>
</HStack>
@@ -195,7 +195,7 @@ function PluginTableRow({
const updates = usePluginUpdates();
const latestVersion = updates.data?.plugins.find((u) => u.name === name)?.version;
const installPluginMutation = useMutation({
mutationKey: ['install_plugin', name],
mutationKey: ["install_plugin", name],
mutationFn: (name: string) => installPlugin(name, null),
});
const uninstall = usePromptUninstall(plugin?.id ?? null, displayName);
@@ -207,7 +207,7 @@ function PluginTableRow({
<TableCell className="!py-0">
<Checkbox
hideLabel
title={plugin?.enabled ? 'Disable plugin' : 'Enable plugin'}
title={plugin?.enabled ? "Disable plugin" : "Enable plugin"}
checked={plugin?.enabled ?? false}
disabled={plugin == null}
onChange={async (enabled) => {
@@ -285,10 +285,10 @@ function PluginTableRow({
}
function PluginSearch() {
const [query, setQuery] = useState<string>('');
const [query, setQuery] = useState<string>("");
const debouncedQuery = useDebouncedValue(query);
const results = useQuery({
queryKey: ['plugins', debouncedQuery],
queryKey: ["plugins", debouncedQuery],
queryFn: () => searchPlugins(query),
});
@@ -334,7 +334,7 @@ function PluginSearch() {
function InstalledPlugins({ plugins, className }: { plugins: Plugin[]; className?: string }) {
return plugins.length === 0 ? (
<div className={classNames(className, 'pb-4')}>
<div className={classNames(className, "pb-4")}>
<EmptyStateText className="text-center">
Plugins extend the functionality of Yaak.
<br />
@@ -388,14 +388,14 @@ function BundledPlugins({ plugins }: { plugins: Plugin[] }) {
function usePromptUninstall(pluginId: string | null, name: string) {
const mut = useMutation({
mutationKey: ['uninstall_plugin', pluginId],
mutationKey: ["uninstall_plugin", pluginId],
mutationFn: async () => {
if (pluginId == null) return;
const confirmed = await showConfirmDelete({
id: `uninstall-plugin-${pluginId}`,
title: 'Uninstall Plugin',
confirmText: 'Uninstall',
title: "Uninstall Plugin",
confirmText: "Uninstall",
description: (
<>
Permanently uninstall <InlineCode>{name}</InlineCode>?
@@ -413,7 +413,7 @@ function usePromptUninstall(pluginId: string | null, name: string) {
function usePluginUpdates() {
return useQuery({
queryKey: ['plugin_updates', usePluginsKey()],
queryKey: ["plugin_updates", usePluginsKey()],
queryFn: () => checkPluginUpdates(),
});
}

View File

@@ -1,13 +1,13 @@
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import { useAtomValue } from 'jotai';
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import { useAtomValue } from "jotai";
import { Checkbox } from '../core/Checkbox';
import { Heading } from '../core/Heading';
import { InlineCode } from '../core/InlineCode';
import { PlainInput } from '../core/PlainInput';
import { Select } from '../core/Select';
import { Separator } from '../core/Separator';
import { HStack, VStack } from '../core/Stacks';
import { Checkbox } from "../core/Checkbox";
import { Heading } from "../core/Heading";
import { InlineCode } from "../core/InlineCode";
import { PlainInput } from "../core/PlainInput";
import { Select } from "../core/Select";
import { Separator } from "../core/Separator";
import { HStack, VStack } from "../core/Stacks";
export function SettingsProxy() {
const settings = useAtomValue(settingsAtom);
@@ -26,32 +26,32 @@ export function SettingsProxy() {
label="Proxy"
hideLabel
size="sm"
value={settings.proxy?.type ?? 'automatic'}
value={settings.proxy?.type ?? "automatic"}
onChange={async (v) => {
if (v === 'automatic') {
if (v === "automatic") {
await patchModel(settings, { proxy: undefined });
} else if (v === 'enabled') {
} else if (v === "enabled") {
await patchModel(settings, {
proxy: {
disabled: false,
type: 'enabled',
http: '',
https: '',
auth: { user: '', password: '' },
bypass: '',
type: "enabled",
http: "",
https: "",
auth: { user: "", password: "" },
bypass: "",
},
});
} else {
await patchModel(settings, { proxy: { type: 'disabled' } });
await patchModel(settings, { proxy: { type: "disabled" } });
}
}}
options={[
{ label: 'Automatic proxy detection', value: 'automatic' },
{ label: 'Custom proxy configuration', value: 'enabled' },
{ label: 'No proxy', value: 'disabled' },
{ label: "Automatic proxy detection", value: "automatic" },
{ label: "Custom proxy configuration", value: "enabled" },
{ label: "No proxy", value: "disabled" },
]}
/>
{settings.proxy?.type === 'enabled' && (
{settings.proxy?.type === "enabled" && (
<VStack space={1.5}>
<Checkbox
className="my-3"
@@ -60,13 +60,13 @@ export function SettingsProxy() {
help="Use this to temporarily disable the proxy without losing the configuration"
onChange={async (enabled) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const http = proxy?.type === "enabled" ? proxy.http : "";
const https = proxy?.type === "enabled" ? proxy.https : "";
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const auth = proxy?.type === "enabled" ? proxy.auth : null;
const disabled = !enabled;
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>
@@ -82,13 +82,13 @@ export function SettingsProxy() {
defaultValue={settings.proxy?.http}
onChange={async (http) => {
const { proxy } = settings;
const https = proxy?.type === 'enabled' ? proxy.https : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const https = proxy?.type === "enabled" ? proxy.https : "";
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const auth = proxy?.type === "enabled" ? proxy.auth : null;
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
await patchModel(settings, {
proxy: {
type: 'enabled',
type: "enabled",
http,
https,
auth,
@@ -109,12 +109,12 @@ export function SettingsProxy() {
defaultValue={settings.proxy?.https}
onChange={async (https) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const http = proxy?.type === "enabled" ? proxy.http : "";
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const auth = proxy?.type === "enabled" ? proxy.auth : null;
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>
@@ -125,13 +125,13 @@ export function SettingsProxy() {
title="Enable authentication"
onChange={async (enabled) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = enabled ? { user: '', password: '' } : null;
const http = proxy?.type === "enabled" ? proxy.http : "";
const https = proxy?.type === "enabled" ? proxy.https : "";
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const auth = enabled ? { user: "", password: "" } : null;
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>
@@ -146,14 +146,14 @@ export function SettingsProxy() {
defaultValue={settings.proxy.auth.user}
onChange={async (user) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
const http = proxy?.type === "enabled" ? proxy.http : "";
const https = proxy?.type === "enabled" ? proxy.https : "";
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const password = proxy?.type === "enabled" ? (proxy.auth?.password ?? "") : "";
const auth = { user, password };
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>
@@ -165,20 +165,20 @@ export function SettingsProxy() {
defaultValue={settings.proxy.auth.password}
onChange={async (password) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
const http = proxy?.type === "enabled" ? proxy.http : "";
const https = proxy?.type === "enabled" ? proxy.https : "";
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
const bypass = proxy?.type === "enabled" ? proxy.bypass : "";
const user = proxy?.type === "enabled" ? (proxy.auth?.user ?? "") : "";
const auth = { user, password };
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>
</HStack>
)}
{settings.proxy.type === 'enabled' && (
{settings.proxy.type === "enabled" && (
<>
<Separator className="my-6" />
<PlainInput
@@ -188,14 +188,14 @@ export function SettingsProxy() {
placeholder="127.0.0.1, *.example.com, localhost:3000"
onChange={async (bypass) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
const http = proxy?.type === "enabled" ? proxy.http : "";
const https = proxy?.type === "enabled" ? proxy.https : "";
const disabled = proxy?.type === "enabled" ? proxy.disabled : false;
const user = proxy?.type === "enabled" ? (proxy.auth?.user ?? "") : "";
const password = proxy?.type === "enabled" ? (proxy.auth?.password ?? "") : "";
const auth = { user, password };
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
proxy: { type: "enabled", http, https, auth, disabled, bypass },
});
}}
/>

View File

@@ -1,48 +1,48 @@
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
import { useAtomValue } from 'jotai';
import { lazy, Suspense } from 'react';
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
import { useResolvedAppearance } from '../../hooks/useResolvedAppearance';
import { useResolvedTheme } from '../../hooks/useResolvedTheme';
import type { ButtonProps } from '../core/Button';
import { Heading } from '../core/Heading';
import type { IconProps } from '../core/Icon';
import { Icon } from '../core/Icon';
import { IconButton } from '../core/IconButton';
import { Link } from '../core/Link';
import type { SelectProps } from '../core/Select';
import { Select } from '../core/Select';
import { HStack, VStack } from '../core/Stacks';
import { patchModel, settingsAtom } from "@yaakapp-internal/models";
import { useAtomValue } from "jotai";
import { lazy, Suspense } from "react";
import { activeWorkspaceAtom } from "../../hooks/useActiveWorkspace";
import { useResolvedAppearance } from "../../hooks/useResolvedAppearance";
import { useResolvedTheme } from "../../hooks/useResolvedTheme";
import type { ButtonProps } from "../core/Button";
import { Heading } from "../core/Heading";
import type { IconProps } from "../core/Icon";
import { Icon } from "../core/Icon";
import { IconButton } from "../core/IconButton";
import { Link } from "../core/Link";
import type { SelectProps } from "../core/Select";
import { Select } from "../core/Select";
import { HStack, VStack } from "../core/Stacks";
const Editor = lazy(() => import('../core/Editor/Editor').then((m) => ({ default: m.Editor })));
const Editor = lazy(() => import("../core/Editor/Editor").then((m) => ({ default: m.Editor })));
const buttonColors: ButtonProps['color'][] = [
'primary',
'info',
'success',
'notice',
'warning',
'danger',
'secondary',
'default',
const buttonColors: ButtonProps["color"][] = [
"primary",
"info",
"success",
"notice",
"warning",
"danger",
"secondary",
"default",
];
const icons: IconProps['icon'][] = [
'info',
'box',
'update',
'alert_triangle',
'arrow_big_right_dash',
'download',
'copy',
'magic_wand',
'settings',
'trash',
'sparkles',
'pencil',
'paste',
'search',
'send_horizontal',
const icons: IconProps["icon"][] = [
"info",
"box",
"update",
"alert_triangle",
"arrow_big_right_dash",
"download",
"copy",
"magic_wand",
"settings",
"trash",
"sparkles",
"pencil",
"paste",
"search",
"send_horizontal",
];
export function SettingsTheme() {
@@ -55,14 +55,14 @@ export function SettingsTheme() {
return null;
}
const lightThemes: SelectProps<string>['options'] = activeTheme.data.themes
const lightThemes: SelectProps<string>["options"] = activeTheme.data.themes
.filter((theme) => !theme.dark)
.map((theme) => ({
label: theme.label,
value: theme.id,
}));
const darkThemes: SelectProps<string>['options'] = activeTheme.data.themes
const darkThemes: SelectProps<string>["options"] = activeTheme.data.themes
.filter((theme) => theme.dark)
.map((theme) => ({
label: theme.label,
@@ -74,7 +74,7 @@ export function SettingsTheme() {
<div className="mb-3">
<Heading>Theme</Heading>
<p className="text-text-subtle">
Make Yaak your own by selecting a theme, or{' '}
Make Yaak your own by selecting a theme, or{" "}
<Link href="https://yaak.app/docs/plugin-development/plugins-quick-start">
Create Your Own
</Link>
@@ -88,13 +88,13 @@ export function SettingsTheme() {
value={settings.appearance}
onChange={(appearance) => patchModel(settings, { appearance })}
options={[
{ label: 'Automatic', value: 'system' },
{ label: 'Light', value: 'light' },
{ label: 'Dark', value: 'dark' },
{ label: "Automatic", value: "system" },
{ label: "Light", value: "light" },
{ label: "Dark", value: "dark" },
]}
/>
<HStack space={2}>
{(settings.appearance === 'system' || settings.appearance === 'light') && (
{(settings.appearance === "system" || settings.appearance === "light") && (
<Select
hideLabel
leftSlot={<Icon icon="sun" color="secondary" />}
@@ -107,7 +107,7 @@ export function SettingsTheme() {
onChange={(themeLight) => patchModel(settings, { themeLight })}
/>
)}
{(settings.appearance === 'system' || settings.appearance === 'dark') && (
{(settings.appearance === "system" || settings.appearance === "dark") && (
<Select
hideLabel
name="darkTheme"
@@ -127,7 +127,7 @@ export function SettingsTheme() {
className="mt-3 w-full bg-surface p-3 border border-dashed border-border-subtle rounded overflow-x-auto"
>
<HStack className="text" space={1.5}>
<Icon icon={appearance === 'dark' ? 'moon' : 'sun'} />
<Icon icon={appearance === "dark" ? "moon" : "sun"} />
<strong>{activeTheme.data.active.label}</strong>
<em>(preview)</em>
</HStack>
@@ -138,7 +138,7 @@ export function SettingsTheme() {
color={c}
size="2xs"
iconSize="xs"
icon={icons[i % icons.length] ?? 'info'}
icon={icons[i % icons.length] ?? "info"}
iconClassName="text"
title={`${c}`}
/>
@@ -150,7 +150,7 @@ export function SettingsTheme() {
variant="border"
size="2xs"
iconSize="xs"
icon={icons[i % icons.length] ?? 'info'}
icon={icons[i % icons.length] ?? "info"}
iconClassName="text"
title={`${c}`}
/>
@@ -159,11 +159,11 @@ export function SettingsTheme() {
<Suspense>
<Editor
defaultValue={[
'let foo = { // Demo code editor',
"let foo = { // Demo code editor",
' foo: ("bar" || "baz" ?? \'qux\'),',
' baz: [1, 10.2, null, false, true],',
'};',
].join('\n')}
" baz: [1, 10.2, null, false, true],",
"};",
].join("\n")}
heightMode="auto"
language="javascript"
stateKey={null}