diff --git a/src-web/components/GrpcConnectionLayout.tsx b/src-web/components/GrpcConnectionLayout.tsx index 7004640c..851ef6b9 100644 --- a/src-web/components/GrpcConnectionLayout.tsx +++ b/src-web/components/GrpcConnectionLayout.tsx @@ -7,6 +7,7 @@ import { useActiveRequest } from '../hooks/useActiveRequest'; import { useGrpc } from '../hooks/useGrpc'; import { useGrpcProtoFiles } from '../hooks/useGrpcProtoFiles'; import { activeGrpcConnectionAtom, useGrpcEvents } from '../hooks/usePinnedGrpcConnection'; +import { workspaceLayoutAtom } from '../lib/atoms'; import { Banner } from './core/Banner'; import { HotKeyList } from './core/HotKeyList'; import { SplitLayout } from './core/SplitLayout'; @@ -20,6 +21,7 @@ interface Props { const emptyArray: string[] = []; export function GrpcConnectionLayout({ style }: Props) { + const workspaceLayout = useAtomValue(workspaceLayoutAtom); const activeRequest = useActiveRequest('grpc_request'); const activeConnection = useAtomValue(activeGrpcConnectionAtom); const grpcEvents = useGrpcEvents(activeConnection?.id ?? null); @@ -80,6 +82,7 @@ export function GrpcConnectionLayout({ style }: Props) { name="grpc_layout" className="p-3 gap-1.5" style={style} + layout={workspaceLayout} firstSlot={({ style }) => ( ) => ( ( openSettings.mutate('license')}> - License Error - - ); + // Failed to check for license. Probably a network or server error so just don't + // show anything. + return null; } // Hasn't loaded yet diff --git a/src-web/components/WebsocketRequestLayout.tsx b/src-web/components/WebsocketRequestLayout.tsx index 3356e359..eb38e30d 100644 --- a/src-web/components/WebsocketRequestLayout.tsx +++ b/src-web/components/WebsocketRequestLayout.tsx @@ -1,7 +1,9 @@ import type { WebsocketRequest } from '@yaakapp-internal/models'; import classNames from 'classnames'; +import { useAtomValue } from 'jotai'; import type { CSSProperties } from 'react'; import React from 'react'; +import { workspaceLayoutAtom } from '../lib/atoms'; import { SplitLayout } from './core/SplitLayout'; import { WebsocketRequestPane } from './WebsocketRequestPane'; import { WebsocketResponsePane } from './WebsocketResponsePane'; @@ -12,10 +14,12 @@ interface Props { } export function WebsocketRequestLayout({ activeRequest, style }: Props) { + const workspaceLayout = useAtomValue(workspaceLayoutAtom); return ( ( {!disableLabel && ( - workspace encryption key{' '} + Workspace encryption key{' '} )} diff --git a/src-web/components/WorkspaceHeader.tsx b/src-web/components/WorkspaceHeader.tsx index 61d38964..49815095 100644 --- a/src-web/components/WorkspaceHeader.tsx +++ b/src-web/components/WorkspaceHeader.tsx @@ -1,9 +1,8 @@ -import { type } from '@tauri-apps/plugin-os'; import classNames from 'classnames'; -import { useAtomValue } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import React, { memo } from 'react'; import { activeWorkspaceAtom, activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace'; -import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette'; +import { workspaceLayoutAtom } from '../lib/atoms'; import { setupOrConfigureEncryption } from '../lib/setupOrConfigureEncryption'; import { CookieDropdown } from './CookieDropdown'; import { BadgeButton } from './core/BadgeButton'; @@ -23,7 +22,7 @@ interface Props { } export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Props) { - const togglePalette = useToggleCommandPalette(); + const [workspaceLayout, setWorkspaceLayout] = useAtom(workspaceLayoutAtom); const workspace = useAtomValue(activeWorkspaceAtom); const workspaceMeta = useAtomValue(activeWorkspaceMetaAtom); const showEncryptionSetup = @@ -57,14 +56,22 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop ) : ( )} + + setWorkspaceLayout((prev) => (prev === 'horizontal' ? 'vertical' : 'horizontal')) + } /> - ); diff --git a/src-web/components/core/SplitLayout.tsx b/src-web/components/core/SplitLayout.tsx index bf75c7de..ec121672 100644 --- a/src-web/components/core/SplitLayout.tsx +++ b/src-web/components/core/SplitLayout.tsx @@ -8,6 +8,8 @@ import { useContainerSize } from '../../hooks/useContainerQuery'; import { clamp } from '../../lib/clamp'; import { ResizeHandle } from '../ResizeHandle'; +export type SplitLayoutLayout = 'responsive' | 'horizontal' | 'vertical'; + export interface SlotProps { orientation: 'horizontal' | 'vertical'; style: CSSProperties; @@ -22,7 +24,7 @@ interface Props { defaultRatio?: number; minHeightPx?: number; minWidthPx?: number; - layout?: 'responsive' | 'vertical' | 'horizontal'; + layout?: SplitLayoutLayout; } const baseProperties = { minWidth: 0 }; diff --git a/src-web/lib/atoms.ts b/src-web/lib/atoms.ts index b2665a17..44050f81 100644 --- a/src-web/lib/atoms.ts +++ b/src-web/lib/atoms.ts @@ -1,6 +1,8 @@ import deepEqual from '@gilbarbara/deep-equal'; import type { Atom } from 'jotai'; import { selectAtom } from 'jotai/utils'; +import type { SplitLayoutLayout } from '../components/core/SplitLayout'; +import { atomWithKVStorage } from './atoms/atomWithKVStorage'; export function deepEqualAtom(a: Atom) { return selectAtom( @@ -9,3 +11,8 @@ export function deepEqualAtom(a: Atom) { (a, b) => deepEqual(a, b), ); } + +export const workspaceLayoutAtom = atomWithKVStorage( + 'workspace_layout', + 'horizontal', +);