Tweak appearance settings

This commit is contained in:
Gregory Schier
2024-05-30 12:32:12 -07:00
parent 16739d9a37
commit e2e026e1ff
22 changed files with 170 additions and 144 deletions

View File

@@ -45,7 +45,7 @@ export function BinaryFileEditor({
return ( return (
<VStack space={2}> <VStack space={2}>
<HStack space={2} alignItems="center"> <HStack space={2}>
<Button variant="border" color="secondary" size="sm" onClick={handleClick}> <Button variant="border" color="secondary" size="sm" onClick={handleClick}>
Choose File Choose File
</Button> </Button>

View File

@@ -36,7 +36,7 @@ export const CookieDialog = function ({ cookieJarId }: Props) {
<th className="py-2 pl-4"></th> <th className="py-2 pl-4"></th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y"> <tbody className="divide-y divide-background-highlight-secondary">
{cookieJar?.cookies.map((c) => ( {cookieJar?.cookies.map((c) => (
<tr key={c.domain + c.raw_cookie}> <tr key={c.domain + c.raw_cookie}>
<td className="py-2 select-text cursor-text font-mono font-semibold max-w-0"> <td className="py-2 select-text cursor-text font-mono font-semibold max-w-0">

View File

@@ -61,8 +61,8 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
firstSlot={() => firstSlot={() =>
activeConnection && ( activeConnection && (
<div className="w-full grid grid-rows-[auto_minmax(0,1fr)] items-center"> <div className="w-full grid grid-rows-[auto_minmax(0,1fr)] items-center">
<HStack className="pl-3 mb-1 font-mono" alignItems="center"> <HStack className="pl-3 mb-1 font-mono">
<HStack alignItems="center" space={2}> <HStack space={2}>
<span>{events.length} messages</span> <span>{events.length} messages</span>
{activeConnection.elapsed === 0 && ( {activeConnection.elapsed === 0 && (
<Icon icon="refresh" size="sm" spin className="text-fg-subtler" /> <Icon icon="refresh" size="sm" spin className="text-fg-subtler" />

View File

@@ -0,0 +1,31 @@
import classNames from 'classnames';
import type { HTMLAttributes, ReactNode } from 'react';
import { useIsFullscreen } from '../hooks/useIsFullscreen';
import { useOsInfo } from '../hooks/useOsInfo';
interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
size: 'md' | 'lg';
}
export function HeaderSize({ className, style, size, ...props }: HeaderSizeProps) {
const platform = useOsInfo();
const fullscreen = useIsFullscreen();
const stoplightsVisible = platform?.osType === 'macos' && !fullscreen;
return (
<div
data-tauri-drag-region
style={style}
className={classNames(
className,
'pt-[1px] w-full border-b border-background-highlight min-w-0',
stoplightsVisible ? 'pl-20 pr-1' : 'pl-1',
size === 'md' && 'h-[27px]',
size === 'lg' && 'h-[38px]',
)}
>
{/* NOTE: This needs display:grid or else the element shrinks (even though scrollable) */}
<div className="h-full w-full overflow-x-auto hide-scrollbars grid" {...props} />
</div>
);
}

View File

@@ -43,7 +43,7 @@ export function RecentConnectionsDropdown({
...connections.slice(0, 20).map((c) => ({ ...connections.slice(0, 20).map((c) => ({
key: c.id, key: c.id,
label: ( label: (
<HStack space={2} alignItems="center"> <HStack space={2}>
{formatDistanceToNowStrict(c.createdAt + 'Z')} ago &bull;{' '} {formatDistanceToNowStrict(c.createdAt + 'Z')} ago &bull;{' '}
<span className="font-mono text-sm">{c.elapsed}ms</span> <span className="font-mono text-sm">{c.elapsed}ms</span>
</HStack> </HStack>

View File

@@ -46,7 +46,7 @@ export const RecentResponsesDropdown = function ResponsePane({
...responses.slice(0, 20).map((r: HttpResponse) => ({ ...responses.slice(0, 20).map((r: HttpResponse) => ({
key: r.id, key: r.id,
label: ( label: (
<HStack space={2} alignItems="center"> <HStack space={2}>
<StatusTag className="text-sm" response={r} /> <StatusTag className="text-sm" response={r} />
<span>&rarr;</span>{' '} <span>&rarr;</span>{' '}
<span className="font-mono text-sm">{r.elapsed >= 0 ? `${r.elapsed}ms` : 'n/a'}</span> <span className="font-mono text-sm">{r.elapsed >= 0 ? `${r.elapsed}ms` : 'n/a'}</span>

View File

@@ -92,7 +92,6 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
) : ( ) : (
<div className="h-full w-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1"> <div className="h-full w-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1">
<HStack <HStack
alignItems="center"
className={classNames( className={classNames(
'text-fg-subtle w-full flex-shrink-0', 'text-fg-subtle w-full flex-shrink-0',
// Remove a bit of space because the tabs have lots too // Remove a bit of space because the tabs have lots too
@@ -102,7 +101,6 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
{activeResponse && ( {activeResponse && (
<HStack <HStack
space={2} space={2}
alignItems="center"
className="whitespace-nowrap w-full pl-3 overflow-x-auto font-mono text-sm" className="whitespace-nowrap w-full pl-3 overflow-x-auto font-mono text-sm"
> >
<StatusTag showReason response={activeResponse} /> <StatusTag showReason response={activeResponse} />

View File

@@ -1,7 +1,11 @@
import { getCurrent } from '@tauri-apps/api/webviewWindow'; import { getCurrent } from '@tauri-apps/api/webviewWindow';
import React from 'react';
import { createGlobalState, useKeyPressEvent } from 'react-use'; import { createGlobalState, useKeyPressEvent } from 'react-use';
import { capitalize } from '../../lib/capitalize'; import { capitalize } from '../../lib/capitalize';
import { HStack } from '../core/Stacks';
import { TabContent, Tabs } from '../core/Tabs/Tabs'; import { TabContent, Tabs } from '../core/Tabs/Tabs';
import { HeaderSize } from '../HeaderSize';
import { WindowControls } from '../WindowControls';
import { SettingsAppearance } from './SettingsAppearance'; import { SettingsAppearance } from './SettingsAppearance';
import { SettingsGeneral } from './SettingsGeneral'; import { SettingsGeneral } from './SettingsGeneral';
@@ -22,12 +26,20 @@ export const Settings = () => {
return ( return (
<> <>
<div <HeaderSize
data-tauri-drag-region data-tauri-drag-region
className="x-theme-appHeader h-[27px] bg-background text-fg-subtle flex items-center justify-center border-b border-background-highlight text-sm font-semibold" size="md"
className="x-theme-appHeader bg-background text-fg-subtle flex items-center justify-center border-b border-background-highlight text-sm font-semibold"
> >
Settings <HStack
</div> space={2}
justifyContent="center"
className="w-full h-full grid grid-cols-[1fr_auto]"
>
<div className="text-center">Settings</div>
<WindowControls className="ml-auto" />
</HStack>
</HeaderSize>
<Tabs <Tabs
value={tab} value={tab}
addBorders addBorders

View File

@@ -123,6 +123,7 @@ export function SettingsAppearance() {
]} ]}
/> />
<HStack space={2}> <HStack space={2}>
<div>Theme</div>
{(settings.appearance === 'system' || settings.appearance === 'light') && ( {(settings.appearance === 'system' || settings.appearance === 'light') && (
<Select <Select
hideLabel hideLabel
@@ -131,7 +132,7 @@ export function SettingsAppearance() {
label="Light Theme" label="Light Theme"
size="sm" size="sm"
value={activeTheme.light.id} value={activeTheme.light.id}
options={lightThemes} options={[{ label: 'Light Mode Themes', options: lightThemes }]}
onChange={(themeLight) => { onChange={(themeLight) => {
trackEvent('theme', 'update', { theme: themeLight, appearance: 'light' }); trackEvent('theme', 'update', { theme: themeLight, appearance: 'light' });
updateSettings.mutateAsync({ ...settings, themeLight }); updateSettings.mutateAsync({ ...settings, themeLight });
@@ -146,7 +147,7 @@ export function SettingsAppearance() {
leftSlot={<Icon icon="moon" />} leftSlot={<Icon icon="moon" />}
size="sm" size="sm"
value={activeTheme.dark.id} value={activeTheme.dark.id}
options={darkThemes} options={[{ label: 'Dark Mode Themes', options: darkThemes }]}
onChange={(themeDark) => { onChange={(themeDark) => {
trackEvent('theme', 'update', { theme: themeDark, appearance: 'dark' }); trackEvent('theme', 'update', { theme: themeDark, appearance: 'dark' });
updateSettings.mutateAsync({ ...settings, themeDark }); updateSettings.mutateAsync({ ...settings, themeDark });
@@ -159,11 +160,11 @@ export function SettingsAppearance() {
space={3} space={3}
className="mt-3 w-full bg-background p-3 border border-dashed border-background-highlight rounded overflow-x-auto" className="mt-3 w-full bg-background p-3 border border-dashed border-background-highlight rounded overflow-x-auto"
> >
<HStack className="text-fg font-bold" alignItems="center" space={2}> <HStack className="text-fg font-bold" space={2}>
Theme Preview{' '} Theme Preview{' '}
<Icon icon={appearance === 'dark' ? 'moon' : 'sun'} className="text-fg-subtle" /> <Icon icon={appearance === 'dark' ? 'moon' : 'sun'} className="text-fg-subtle" />
</HStack> </HStack>
<HStack space={1.5} alignItems="center" className="w-full"> <HStack space={1.5} className="w-full">
{buttonColors.map((c, i) => ( {buttonColors.map((c, i) => (
<IconButton <IconButton
key={c} key={c}

View File

@@ -19,7 +19,7 @@ export function SidebarActions() {
); );
return ( return (
<HStack className="h-full" alignItems="center"> <HStack className="h-full">
<IconButton <IconButton
onClick={async () => { onClick={async () => {
trackEvent('sidebar', 'toggle'); trackEvent('sidebar', 'toggle');

View File

@@ -0,0 +1,69 @@
import { getCurrent } from '@tauri-apps/api/webviewWindow';
import classNames from 'classnames';
import React, { useState } from 'react';
import { useOsInfo } from '../hooks/useOsInfo';
import { Button } from './core/Button';
import { HStack } from './core/Stacks';
interface Props {
className?: string;
}
export function WindowControls({ className }: Props) {
const [maximized, setMaximized] = useState<boolean>(false);
const osInfo = useOsInfo();
const shouldShow = osInfo?.osType === 'linux' || osInfo?.osType === 'windows';
if (!shouldShow) {
return null;
}
return (
<HStack className={classNames(className, 'ml-4 h-full')}>
<Button
className="!h-full px-4 text-fg-subtle hocus:text-fg hocus:bg-background-highlight-secondary rounded-none"
color="custom"
onClick={() => getCurrent().minimize()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M14 8v1H3V8z" />
</svg>
</Button>
<Button
className="!h-full px-4 text-fg-subtle hocus:text-fg hocus:bg-background-highlight rounded-none"
color="custom"
onClick={async () => {
const w = getCurrent();
await w.toggleMaximize();
setMaximized(await w.isMaximized());
}}
>
{maximized ? (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="currentColor">
<path d="M3 5v9h9V5zm8 8H4V6h7z" />
<path fillRule="evenodd" d="M5 5h1V4h7v7h-1v1h2V3H5z" clipRule="evenodd" />
</g>
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M3 3v10h10V3zm9 9H4V4h8z" />
</svg>
)}
</Button>
<Button
color="custom"
className="!h-full px-4 text-fg-subtle rounded-none hocus:bg-fg-danger hocus:text-fg"
onClick={() => getCurrent().close()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path
fill="currentColor"
fillRule="evenodd"
d="m7.116 8l-4.558 4.558l.884.884L8 8.884l4.558 4.558l.884-.884L8.884 8l4.558-4.558l-.884-.884L8 7.116L3.442 2.558l-.884.884z"
clipRule="evenodd"
/>
</svg>
</Button>
</HStack>
);
}

View File

@@ -1,11 +1,6 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import type { import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
CSSProperties,
HTMLAttributes,
MouseEvent as ReactMouseEvent,
ReactNode,
} from 'react';
import { useCallback, useMemo, useRef, useState } from 'react'; import { useCallback, useMemo, useRef, useState } from 'react';
import { useWindowSize } from 'react-use'; import { useWindowSize } from 'react-use';
import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveRequest } from '../hooks/useActiveRequest';
@@ -13,8 +8,6 @@ import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId'; import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden'; import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
import { useImportData } from '../hooks/useImportData'; import { useImportData } from '../hooks/useImportData';
import { useIsFullscreen } from '../hooks/useIsFullscreen';
import { useOsInfo } from '../hooks/useOsInfo';
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar'; import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
import { useSidebarHidden } from '../hooks/useSidebarHidden'; import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useSidebarWidth } from '../hooks/useSidebarWidth'; import { useSidebarWidth } from '../hooks/useSidebarWidth';
@@ -28,6 +21,7 @@ import { FeedbackLink } from './core/Link';
import { HStack } from './core/Stacks'; import { HStack } from './core/Stacks';
import { CreateDropdown } from './CreateDropdown'; import { CreateDropdown } from './CreateDropdown';
import { GrpcConnectionLayout } from './GrpcConnectionLayout'; import { GrpcConnectionLayout } from './GrpcConnectionLayout';
import { HeaderSize } from './HeaderSize';
import { HttpRequestLayout } from './HttpRequestLayout'; import { HttpRequestLayout } from './HttpRequestLayout';
import { Overlay } from './Overlay'; import { Overlay } from './Overlay';
import { ResizeHandle } from './ResizeHandle'; import { ResizeHandle } from './ResizeHandle';
@@ -150,7 +144,7 @@ export default function Workspace() {
'grid grid-rows-[auto_1fr]', 'grid grid-rows-[auto_1fr]',
)} )}
> >
<HeaderSize className="border-transparent"> <HeaderSize size="lg" className="border-transparent">
<SidebarActions /> <SidebarActions />
</HeaderSize> </HeaderSize>
<Sidebar /> <Sidebar />
@@ -174,7 +168,12 @@ export default function Workspace() {
/> />
</> </>
)} )}
<HeaderSize data-tauri-drag-region className="x-theme-appHeader bg-background" style={head}> <HeaderSize
data-tauri-drag-region
size="lg"
className="x-theme-appHeader bg-background"
style={head}
>
<WorkspaceHeader className="pointer-events-none" /> <WorkspaceHeader className="pointer-events-none" />
</HeaderSize> </HeaderSize>
{activeWorkspace == null ? ( {activeWorkspace == null ? (
@@ -209,27 +208,3 @@ export default function Workspace() {
</div> </div>
); );
} }
interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
}
export function HeaderSize({ className, style, ...props }: HeaderSizeProps) {
const platform = useOsInfo();
const fullscreen = useIsFullscreen();
const stoplightsVisible = platform?.osType === 'macos' && !fullscreen;
return (
<div
data-tauri-drag-region
style={style}
className={classNames(
className,
'h-md pt-[1px] w-full border-b border-background-highlight min-w-0',
stoplightsVisible ? 'pl-20 pr-1' : 'pl-1',
)}
>
{/* NOTE: This needs display:grid or else the element shrinks (even though scrollable) */}
<div className="h-full w-full overflow-x-auto hide-scrollbars grid" {...props} />
</div>
);
}

View File

@@ -52,12 +52,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
), ),
render: ({ hide }) => { render: ({ hide }) => {
return ( return (
<HStack <HStack space={2} justifyContent="start" className="mt-4 mb-6 flex-row-reverse">
space={2}
justifyContent="start"
alignItems="center"
className="mt-4 mb-6 flex-row-reverse"
>
<Button <Button
className="focus" className="focus"
color="primary" color="primary"

View File

@@ -1,9 +1,6 @@
import { getCurrent } from '@tauri-apps/api/webviewWindow';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { memo, useState } from 'react'; import React, { memo } from 'react';
import { useOsInfo } from '../hooks/useOsInfo';
import { CookieDropdown } from './CookieDropdown'; import { CookieDropdown } from './CookieDropdown';
import { Button } from './core/Button';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
import { HStack } from './core/Stacks'; import { HStack } from './core/Stacks';
import { EnvironmentActionsDropdown } from './EnvironmentActionsDropdown'; import { EnvironmentActionsDropdown } from './EnvironmentActionsDropdown';
@@ -11,6 +8,7 @@ import { ImportCurlButton } from './ImportCurlButton';
import { RecentRequestsDropdown } from './RecentRequestsDropdown'; import { RecentRequestsDropdown } from './RecentRequestsDropdown';
import { SettingsDropdown } from './SettingsDropdown'; import { SettingsDropdown } from './SettingsDropdown';
import { SidebarActions } from './SidebarActions'; import { SidebarActions } from './SidebarActions';
import { WindowControls } from './WindowControls';
import { WorkspaceActionsDropdown } from './WorkspaceActionsDropdown'; import { WorkspaceActionsDropdown } from './WorkspaceActionsDropdown';
interface Props { interface Props {
@@ -18,20 +16,12 @@ interface Props {
} }
export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Props) { export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Props) {
const osInfo = useOsInfo();
const [maximized, setMaximized] = useState<boolean>(false);
return ( return (
<HStack <HStack space={2} justifyContent="center" className={classNames(className, 'w-full h-full')}>
space={2} <HStack space={0.5} className="flex-1 pointer-events-none">
justifyContent="center"
alignItems="center"
className={classNames(className, 'w-full h-full')}
>
<HStack space={0.5} className="flex-1 pointer-events-none" alignItems="center">
<SidebarActions /> <SidebarActions />
<CookieDropdown /> <CookieDropdown />
<HStack alignItems="center"> <HStack>
<WorkspaceActionsDropdown /> <WorkspaceActionsDropdown />
<Icon icon="chevronRight" className="text-fg-subtle" /> <Icon icon="chevronRight" className="text-fg-subtle" />
<EnvironmentActionsDropdown className="w-auto pointer-events-auto" /> <EnvironmentActionsDropdown className="w-auto pointer-events-auto" />
@@ -43,55 +33,7 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
<div className="flex-1 flex gap-1 items-center h-full justify-end pointer-events-none pr-0.5"> <div className="flex-1 flex gap-1 items-center h-full justify-end pointer-events-none pr-0.5">
<ImportCurlButton /> <ImportCurlButton />
<SettingsDropdown /> <SettingsDropdown />
{(osInfo?.osType === 'linux' || osInfo?.osType === 'windows') && ( <WindowControls />
<HStack className="ml-4" alignItems="center">
<Button
className="px-4 text-fg-subtle hocus:text-fg hocus:bg-background-highlight-secondary rounded-none"
color="custom"
onClick={() => getCurrent().minimize()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M14 8v1H3V8z" />
</svg>
</Button>
<Button
className="px-4 text-fg-subtle hocus:text-fg hocus:bg-background-highlight rounded-none"
color="custom"
onClick={async () => {
const w = getCurrent();
await w.toggleMaximize();
setMaximized(await w.isMaximized());
}}
>
{maximized ? (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="currentColor">
<path d="M3 5v9h9V5zm8 8H4V6h7z" />
<path fillRule="evenodd" d="M5 5h1V4h7v7h-1v1h2V3H5z" clipRule="evenodd" />
</g>
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M3 3v10h10V3zm9 9H4V4h8z" />
</svg>
)}
</Button>
<Button
color="custom"
className="px-4 text-fg-subtle rounded-none hocus:bg-fg-danger hocus:text-fg"
onClick={() => getCurrent().close()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path
fill="currentColor"
fillRule="evenodd"
d="m7.116 8l-4.558 4.558l.884.884L8 8.884l4.558 4.558l.884-.884L8.884 8l4.558-4.558l-.884-.884L8 7.116L3.442 2.558l-.884.884z"
clipRule="evenodd"
/>
</svg>
</Button>
</HStack>
)}
</div> </div>
</HStack> </HStack>
); );

View File

@@ -27,7 +27,6 @@ export function Checkbox({
<HStack <HStack
as="label" as="label"
space={2} space={2}
alignItems="center"
className={classNames(className, 'text-fg', disabled && 'opacity-disabled')} className={classNames(className, 'text-fg', disabled && 'opacity-disabled')}
> >
<div className={classNames(inputWrapperClassName, 'x-theme-input', 'relative flex')}> <div className={classNames(inputWrapperClassName, 'x-theme-input', 'relative flex')}>

View File

@@ -224,7 +224,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
); );
const [menuStyles, setMenuStyles] = useState<CSSProperties>({}); const [menuStyles, setMenuStyles] = useState<CSSProperties>({});
const [filter, setFilter] = useState<string>(''); const [filter, setFilter] = useState<string>('');
const [containerWidth, setContainerWidth] = useState<number | null>(null);
// Calculate the max height so we can scroll // Calculate the max height so we can scroll
const initMenu = useCallback((el: HTMLDivElement | null) => { const initMenu = useCallback((el: HTMLDivElement | null) => {
@@ -349,11 +348,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
[handleClose, handleNext, handlePrev, handleSelect, items, selectedIndex], [handleClose, handleNext, handlePrev, handleSelect, items, selectedIndex],
); );
const initContainerRef = (n: HTMLDivElement | null) => {
if (n == null) return null;
setContainerWidth(n.offsetWidth);
};
const { containerStyles, triangleStyles } = useMemo<{ const { containerStyles, triangleStyles } = useMemo<{
containerStyles: CSSProperties; containerStyles: CSSProperties;
triangleStyles: CSSProperties | null; triangleStyles: CSSProperties | null;
@@ -379,7 +373,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
? { right: width / 2, marginRight: '-0.2rem', ...size } ? { right: width / 2, marginRight: '-0.2rem', ...size }
: { left: width / 2, marginLeft: '-0.2rem', ...size }; : { left: width / 2, marginLeft: '-0.2rem', ...size };
return { containerStyles, triangleStyles }; return { containerStyles, triangleStyles };
}, [triggerShape, containerWidth]); }, [triggerShape]);
const filteredItems = useMemo( const filteredItems = useMemo(
() => items.filter((i) => getNodeText(i.label).toLowerCase().includes(filter.toLowerCase())), () => items.filter((i) => getNodeText(i.label).toLowerCase().includes(filter.toLowerCase())),
@@ -422,7 +416,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
role="menu" role="menu"
aria-orientation="vertical" aria-orientation="vertical"
dir="ltr" dir="ltr"
ref={initContainerRef}
style={containerStyles} style={containerStyles}
className={classNames(className, 'outline-none my-1 pointer-events-auto fixed z-50')} className={classNames(className, 'outline-none my-1 pointer-events-auto fixed z-50')}
> >
@@ -446,7 +439,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
{filter && ( {filter && (
<HStack <HStack
space={2} space={2}
alignItems="center"
className="pb-0.5 px-1.5 mb-2 text-sm border border-background-highlight-secondary mx-2 rounded font-mono h-xs" className="pb-0.5 px-1.5 mb-2 text-sm border border-background-highlight-secondary mx-2 rounded font-mono h-xs"
> >
<Icon icon="search" size="xs" className="text-fg-subtle" /> <Icon icon="search" size="xs" className="text-fg-subtle" />

View File

@@ -294,7 +294,6 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
{decoratedActions && ( {decoratedActions && (
<HStack <HStack
space={1} space={1}
alignItems="center"
justifyContent="end" justifyContent="end"
className={classNames( className={classNames(
'absolute bottom-2 left-0 right-0', 'absolute bottom-2 left-0 right-0',

View File

@@ -153,7 +153,6 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
> >
{leftSlot} {leftSlot}
<HStack <HStack
alignItems="center"
className={classNames( className={classNames(
'w-full min-w-0', 'w-full min-w-0',
leftSlot && 'pl-0.5 -ml-2', leftSlot && 'pl-0.5 -ml-2',

View File

@@ -105,7 +105,6 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
> >
{leftSlot} {leftSlot}
<HStack <HStack
alignItems="center"
className={classNames( className={classNames(
'w-full min-w-0', 'w-full min-w-0',
leftSlot && 'pl-0.5 -ml-2', leftSlot && 'pl-0.5 -ml-2',

View File

@@ -11,7 +11,7 @@ interface Props<T extends string> {
hideLabel?: boolean; hideLabel?: boolean;
value: T; value: T;
leftSlot?: ReactNode; leftSlot?: ReactNode;
options: SelectOption<T>[]; options: SelectOption<T>[] | SelectOptionGroup<T>[];
onChange: (value: T) => void; onChange: (value: T) => void;
size?: 'xs' | 'sm' | 'md' | 'lg'; size?: 'xs' | 'sm' | 'md' | 'lg';
className?: string; className?: string;
@@ -22,6 +22,11 @@ export interface SelectOption<T extends string> {
value: T; value: T;
} }
export interface SelectOptionGroup<T extends string> {
label: string;
options: SelectOption<T>[];
}
export function Select<T extends string>({ export function Select<T extends string>({
labelPosition = 'top', labelPosition = 'top',
name, name,
@@ -56,7 +61,6 @@ export function Select<T extends string>({
</label> </label>
<HStack <HStack
space={2} space={2}
alignItems="center"
className={classNames( className={classNames(
'w-full rounded-md text-fg text-sm font-mono', 'w-full rounded-md text-fg text-sm font-mono',
'pl-2', 'pl-2',
@@ -77,11 +81,21 @@ export function Select<T extends string>({
onBlur={() => setFocused(false)} onBlur={() => setFocused(false)}
className={classNames('pr-7 w-full outline-none bg-transparent')} className={classNames('pr-7 w-full outline-none bg-transparent')}
> >
{options.map(({ label, value }) => ( {options.map((o) =>
<option key={label} value={value}> 'options' in o ? (
{label} <optgroup key={o.label} label={o.label}>
</option> {o.options.map(({ label, value }) => (
))} <option key={label} value={value}>
{label}
</option>
))}
</optgroup>
) : (
<option key={o.label} value={o.value}>
{o.label}
</option>
),
)}
</select> </select>
</HStack> </HStack>
</div> </div>

View File

@@ -19,7 +19,7 @@ interface HStackProps extends BaseStackProps {
} }
export const HStack = forwardRef(function HStack( export const HStack = forwardRef(function HStack(
{ className, space, children, ...props }: HStackProps, { className, space, children, alignItems = 'center', ...props }: HStackProps,
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
ref: ForwardedRef<any>, ref: ForwardedRef<any>,
) { ) {
@@ -27,6 +27,7 @@ export const HStack = forwardRef(function HStack(
<BaseStack <BaseStack
ref={ref} ref={ref}
className={classNames(className, 'flex-row', space != null && gapClasses[space])} className={classNames(className, 'flex-row', space != null && gapClasses[space])}
alignItems={alignItems}
{...props} {...props}
> >
{children} {children}

View File

@@ -34,9 +34,9 @@ export const yaakDark: YaakTheme = {
background: new Color('hsl(244,23%,14%)', 'dark'), background: new Color('hsl(244,23%,14%)', 'dark'),
backgroundHighlight: new Color('hsl(244,23%,23%)', 'dark'), backgroundHighlight: new Color('hsl(244,23%,23%)', 'dark'),
backgroundHighlightSecondary: new Color('hsl(244,23%,20%)', 'dark'), backgroundHighlightSecondary: new Color('hsl(244,23%,20%)', 'dark'),
foreground: new Color('hsl(245,23%,80%)', 'dark'), foreground: new Color('hsl(245,23%,83%)', 'dark'),
foregroundSubtle: new Color('hsl(245,20%,65%)', 'dark'), foregroundSubtle: new Color('hsl(245,20%,65%)', 'dark'),
foregroundSubtler: new Color('hsl(245,18%,50%)', 'dark'), foregroundSubtler: new Color('hsl(245,18%,51%)', 'dark'),
colors: { colors: {
primary: new Color('hsl(266,100%,79%)', 'dark'), primary: new Color('hsl(266,100%,79%)', 'dark'),