mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-19 15:21:23 +02:00
Store appearance in k/v
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
|
import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
|
||||||
|
import { useKeyValues } from '../hooks/useKeyValues';
|
||||||
import { useSendRequest } from '../hooks/useSendRequest';
|
import { useSendRequest } from '../hooks/useSendRequest';
|
||||||
import { useUpdateRequest } from '../hooks/useUpdateRequest';
|
import { useUpdateRequest } from '../hooks/useUpdateRequest';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
@@ -20,6 +21,10 @@ export function RequestPane({ fullHeight, className }: Props) {
|
|||||||
const updateRequest = useUpdateRequest(activeRequest);
|
const updateRequest = useUpdateRequest(activeRequest);
|
||||||
const sendRequest = useSendRequest(activeRequest);
|
const sendRequest = useSendRequest(activeRequest);
|
||||||
const responseLoading = useIsResponseLoading();
|
const responseLoading = useIsResponseLoading();
|
||||||
|
const activeTab = useKeyValues({
|
||||||
|
key: ['active_request_body_tab', activeRequest?.id ?? 'n/a'],
|
||||||
|
initialValue: 'body',
|
||||||
|
});
|
||||||
|
|
||||||
if (activeRequest === null) return null;
|
if (activeRequest === null) return null;
|
||||||
|
|
||||||
@@ -35,6 +40,8 @@ export function RequestPane({ fullHeight, className }: Props) {
|
|||||||
loading={responseLoading}
|
loading={responseLoading}
|
||||||
/>
|
/>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
value={activeTab.value}
|
||||||
|
onChangeValue={activeTab.set}
|
||||||
tabs={[
|
tabs={[
|
||||||
{
|
{
|
||||||
value: 'body',
|
value: 'body',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as T from '@radix-ui/react-tabs';
|
import * as T from '@radix-ui/react-tabs';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { useState } from 'react';
|
|
||||||
import { Button } from '../Button';
|
import { Button } from '../Button';
|
||||||
import type { DropdownMenuRadioItem, DropdownMenuRadioProps } from '../Dropdown';
|
import type { DropdownMenuRadioItem, DropdownMenuRadioProps } from '../Dropdown';
|
||||||
import { DropdownMenuRadio, DropdownMenuTrigger } from '../Dropdown';
|
import { DropdownMenuRadio, DropdownMenuTrigger } from '../Dropdown';
|
||||||
@@ -13,6 +12,8 @@ import './Tabs.css';
|
|||||||
interface Props {
|
interface Props {
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
onChangeValue: (value: string) => void;
|
||||||
|
value: string;
|
||||||
tabs: {
|
tabs: {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
@@ -27,12 +28,20 @@ interface Props {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Tabs({ defaultValue, label, children, tabs, className, tabListClassName }: Props) {
|
export function Tabs({
|
||||||
const [value, setValue] = useState(defaultValue);
|
value,
|
||||||
|
onChangeValue,
|
||||||
|
defaultValue,
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
tabs,
|
||||||
|
className,
|
||||||
|
tabListClassName,
|
||||||
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<T.Root
|
<T.Root
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
onValueChange={setValue}
|
onValueChange={onChangeValue}
|
||||||
className={classnames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
|
className={classnames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
|
||||||
>
|
>
|
||||||
<T.List
|
<T.List
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function keyValueQueryKey({
|
|||||||
namespace = DEFAULT_NAMESPACE,
|
namespace = DEFAULT_NAMESPACE,
|
||||||
key,
|
key,
|
||||||
}: {
|
}: {
|
||||||
namespace: string;
|
namespace?: string;
|
||||||
key: string | string[];
|
key: string | string[];
|
||||||
}) {
|
}) {
|
||||||
return ['key_value', { namespace, key: buildKey(key) }];
|
return ['key_value', { namespace, key: buildKey(key) }];
|
||||||
@@ -19,7 +19,7 @@ export function useKeyValues({
|
|||||||
key,
|
key,
|
||||||
initialValue,
|
initialValue,
|
||||||
}: {
|
}: {
|
||||||
namespace: string;
|
namespace?: string;
|
||||||
key: string | string[];
|
key: string | string[];
|
||||||
initialValue: string;
|
initialValue: string;
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -1,38 +1,31 @@
|
|||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import type { Appearance } from '../lib/theme/window';
|
import type { Appearance } from '../lib/theme/window';
|
||||||
import {
|
import {
|
||||||
getAppearance,
|
getAppearance,
|
||||||
setAppearance,
|
setAppearance,
|
||||||
subscribeToPreferredAppearanceChange,
|
subscribeToPreferredAppearanceChange,
|
||||||
toggleAppearance,
|
|
||||||
} from '../lib/theme/window';
|
} from '../lib/theme/window';
|
||||||
|
import { useKeyValues } from './useKeyValues';
|
||||||
export function appearanceQueryKey() {
|
|
||||||
return ['theme', 'appearance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTheme() {
|
export function useTheme() {
|
||||||
const queryClient = useQueryClient();
|
const appearanceKv = useKeyValues({ key: 'appearance', initialValue: getAppearance() });
|
||||||
const appearance = useQuery({
|
|
||||||
queryKey: appearanceQueryKey(),
|
|
||||||
queryFn: getAppearance,
|
|
||||||
initialData: getAppearance(),
|
|
||||||
}).data;
|
|
||||||
|
|
||||||
const themeChange = (appearance: Appearance) => {
|
const themeChange = (appearance: Appearance) => {
|
||||||
setAppearance(appearance);
|
appearanceKv.set(appearance);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleAppearance = async () => {
|
const handleToggleAppearance = async () => {
|
||||||
const newAppearance = toggleAppearance();
|
appearanceKv.set(appearanceKv.value === 'dark' ? 'light' : 'dark');
|
||||||
await queryClient.setQueryData(appearanceQueryKey(), newAppearance);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set appearance when preferred theme changes
|
||||||
useEffect(() => subscribeToPreferredAppearanceChange(themeChange), []);
|
useEffect(() => subscribeToPreferredAppearanceChange(themeChange), []);
|
||||||
|
|
||||||
|
// Sync appearance when k/v changes
|
||||||
|
useEffect(() => setAppearance(appearanceKv.value as Appearance), [appearanceKv.value]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appearance,
|
appearance: appearanceKv.value,
|
||||||
toggleAppearance: handleToggleAppearance,
|
toggleAppearance: handleToggleAppearance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { App } from './components/App';
|
import { App } from './components/App';
|
||||||
import { setAppearance } from './lib/theme/window';
|
import type { KeyValue } from './lib/models';
|
||||||
|
import type { Appearance } from './lib/theme/window';
|
||||||
|
import { getPreferredAppearance, setAppearance } from './lib/theme/window';
|
||||||
import './main.css';
|
import './main.css';
|
||||||
|
|
||||||
setAppearance();
|
const appearance: KeyValue = await invoke('get_key_value', {
|
||||||
|
namespace: 'app',
|
||||||
|
key: 'appearance',
|
||||||
|
});
|
||||||
|
setAppearance((appearance?.value ?? getPreferredAppearance()) as Appearance);
|
||||||
|
|
||||||
// root holds our app's root DOM Element:
|
// root holds our app's root DOM Element:
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
|
|||||||
Reference in New Issue
Block a user