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