mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-17 23:13:51 +01:00
Tweak appearance settings
This commit is contained in:
@@ -45,7 +45,7 @@ export function BinaryFileEditor({
|
||||
|
||||
return (
|
||||
<VStack space={2}>
|
||||
<HStack space={2} alignItems="center">
|
||||
<HStack space={2}>
|
||||
<Button variant="border" color="secondary" size="sm" onClick={handleClick}>
|
||||
Choose File
|
||||
</Button>
|
||||
|
||||
@@ -36,7 +36,7 @@ export const CookieDialog = function ({ cookieJarId }: Props) {
|
||||
<th className="py-2 pl-4"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y">
|
||||
<tbody className="divide-y divide-background-highlight-secondary">
|
||||
{cookieJar?.cookies.map((c) => (
|
||||
<tr key={c.domain + c.raw_cookie}>
|
||||
<td className="py-2 select-text cursor-text font-mono font-semibold max-w-0">
|
||||
|
||||
@@ -61,8 +61,8 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
||||
firstSlot={() =>
|
||||
activeConnection && (
|
||||
<div className="w-full grid grid-rows-[auto_minmax(0,1fr)] items-center">
|
||||
<HStack className="pl-3 mb-1 font-mono" alignItems="center">
|
||||
<HStack alignItems="center" space={2}>
|
||||
<HStack className="pl-3 mb-1 font-mono">
|
||||
<HStack space={2}>
|
||||
<span>{events.length} messages</span>
|
||||
{activeConnection.elapsed === 0 && (
|
||||
<Icon icon="refresh" size="sm" spin className="text-fg-subtler" />
|
||||
|
||||
31
src-web/components/HeaderSize.tsx
Normal file
31
src-web/components/HeaderSize.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export function RecentConnectionsDropdown({
|
||||
...connections.slice(0, 20).map((c) => ({
|
||||
key: c.id,
|
||||
label: (
|
||||
<HStack space={2} alignItems="center">
|
||||
<HStack space={2}>
|
||||
{formatDistanceToNowStrict(c.createdAt + 'Z')} ago •{' '}
|
||||
<span className="font-mono text-sm">{c.elapsed}ms</span>
|
||||
</HStack>
|
||||
|
||||
@@ -46,7 +46,7 @@ export const RecentResponsesDropdown = function ResponsePane({
|
||||
...responses.slice(0, 20).map((r: HttpResponse) => ({
|
||||
key: r.id,
|
||||
label: (
|
||||
<HStack space={2} alignItems="center">
|
||||
<HStack space={2}>
|
||||
<StatusTag className="text-sm" response={r} />
|
||||
<span>→</span>{' '}
|
||||
<span className="font-mono text-sm">{r.elapsed >= 0 ? `${r.elapsed}ms` : 'n/a'}</span>
|
||||
|
||||
@@ -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">
|
||||
<HStack
|
||||
alignItems="center"
|
||||
className={classNames(
|
||||
'text-fg-subtle w-full flex-shrink-0',
|
||||
// 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 && (
|
||||
<HStack
|
||||
space={2}
|
||||
alignItems="center"
|
||||
className="whitespace-nowrap w-full pl-3 overflow-x-auto font-mono text-sm"
|
||||
>
|
||||
<StatusTag showReason response={activeResponse} />
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { getCurrent } from '@tauri-apps/api/webviewWindow';
|
||||
import React from 'react';
|
||||
import { createGlobalState, useKeyPressEvent } from 'react-use';
|
||||
import { capitalize } from '../../lib/capitalize';
|
||||
import { HStack } from '../core/Stacks';
|
||||
import { TabContent, Tabs } from '../core/Tabs/Tabs';
|
||||
import { HeaderSize } from '../HeaderSize';
|
||||
import { WindowControls } from '../WindowControls';
|
||||
import { SettingsAppearance } from './SettingsAppearance';
|
||||
import { SettingsGeneral } from './SettingsGeneral';
|
||||
|
||||
@@ -22,12 +26,20 @@ export const Settings = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
<HeaderSize
|
||||
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
|
||||
</div>
|
||||
<HStack
|
||||
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
|
||||
value={tab}
|
||||
addBorders
|
||||
|
||||
@@ -123,6 +123,7 @@ export function SettingsAppearance() {
|
||||
]}
|
||||
/>
|
||||
<HStack space={2}>
|
||||
<div>Theme</div>
|
||||
{(settings.appearance === 'system' || settings.appearance === 'light') && (
|
||||
<Select
|
||||
hideLabel
|
||||
@@ -131,7 +132,7 @@ export function SettingsAppearance() {
|
||||
label="Light Theme"
|
||||
size="sm"
|
||||
value={activeTheme.light.id}
|
||||
options={lightThemes}
|
||||
options={[{ label: 'Light Mode Themes', options: lightThemes }]}
|
||||
onChange={(themeLight) => {
|
||||
trackEvent('theme', 'update', { theme: themeLight, appearance: 'light' });
|
||||
updateSettings.mutateAsync({ ...settings, themeLight });
|
||||
@@ -146,7 +147,7 @@ export function SettingsAppearance() {
|
||||
leftSlot={<Icon icon="moon" />}
|
||||
size="sm"
|
||||
value={activeTheme.dark.id}
|
||||
options={darkThemes}
|
||||
options={[{ label: 'Dark Mode Themes', options: darkThemes }]}
|
||||
onChange={(themeDark) => {
|
||||
trackEvent('theme', 'update', { theme: themeDark, appearance: 'dark' });
|
||||
updateSettings.mutateAsync({ ...settings, themeDark });
|
||||
@@ -159,11 +160,11 @@ export function SettingsAppearance() {
|
||||
space={3}
|
||||
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{' '}
|
||||
<Icon icon={appearance === 'dark' ? 'moon' : 'sun'} className="text-fg-subtle" />
|
||||
</HStack>
|
||||
<HStack space={1.5} alignItems="center" className="w-full">
|
||||
<HStack space={1.5} className="w-full">
|
||||
{buttonColors.map((c, i) => (
|
||||
<IconButton
|
||||
key={c}
|
||||
|
||||
@@ -19,7 +19,7 @@ export function SidebarActions() {
|
||||
);
|
||||
|
||||
return (
|
||||
<HStack className="h-full" alignItems="center">
|
||||
<HStack className="h-full">
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
trackEvent('sidebar', 'toggle');
|
||||
|
||||
69
src-web/components/WindowControls.tsx
Normal file
69
src-web/components/WindowControls.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import { motion } from 'framer-motion';
|
||||
import type {
|
||||
CSSProperties,
|
||||
HTMLAttributes,
|
||||
MouseEvent as ReactMouseEvent,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
@@ -13,8 +8,6 @@ import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||
import { useImportData } from '../hooks/useImportData';
|
||||
import { useIsFullscreen } from '../hooks/useIsFullscreen';
|
||||
import { useOsInfo } from '../hooks/useOsInfo';
|
||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||
import { useSidebarWidth } from '../hooks/useSidebarWidth';
|
||||
@@ -28,6 +21,7 @@ import { FeedbackLink } from './core/Link';
|
||||
import { HStack } from './core/Stacks';
|
||||
import { CreateDropdown } from './CreateDropdown';
|
||||
import { GrpcConnectionLayout } from './GrpcConnectionLayout';
|
||||
import { HeaderSize } from './HeaderSize';
|
||||
import { HttpRequestLayout } from './HttpRequestLayout';
|
||||
import { Overlay } from './Overlay';
|
||||
import { ResizeHandle } from './ResizeHandle';
|
||||
@@ -150,7 +144,7 @@ export default function Workspace() {
|
||||
'grid grid-rows-[auto_1fr]',
|
||||
)}
|
||||
>
|
||||
<HeaderSize className="border-transparent">
|
||||
<HeaderSize size="lg" className="border-transparent">
|
||||
<SidebarActions />
|
||||
</HeaderSize>
|
||||
<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" />
|
||||
</HeaderSize>
|
||||
{activeWorkspace == null ? (
|
||||
@@ -209,27 +208,3 @@ export default function Workspace() {
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,12 +52,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
),
|
||||
render: ({ hide }) => {
|
||||
return (
|
||||
<HStack
|
||||
space={2}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
className="mt-4 mb-6 flex-row-reverse"
|
||||
>
|
||||
<HStack space={2} justifyContent="start" className="mt-4 mb-6 flex-row-reverse">
|
||||
<Button
|
||||
className="focus"
|
||||
color="primary"
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { getCurrent } from '@tauri-apps/api/webviewWindow';
|
||||
import classNames from 'classnames';
|
||||
import React, { memo, useState } from 'react';
|
||||
import { useOsInfo } from '../hooks/useOsInfo';
|
||||
import React, { memo } from 'react';
|
||||
import { CookieDropdown } from './CookieDropdown';
|
||||
import { Button } from './core/Button';
|
||||
import { Icon } from './core/Icon';
|
||||
import { HStack } from './core/Stacks';
|
||||
import { EnvironmentActionsDropdown } from './EnvironmentActionsDropdown';
|
||||
@@ -11,6 +8,7 @@ import { ImportCurlButton } from './ImportCurlButton';
|
||||
import { RecentRequestsDropdown } from './RecentRequestsDropdown';
|
||||
import { SettingsDropdown } from './SettingsDropdown';
|
||||
import { SidebarActions } from './SidebarActions';
|
||||
import { WindowControls } from './WindowControls';
|
||||
import { WorkspaceActionsDropdown } from './WorkspaceActionsDropdown';
|
||||
|
||||
interface Props {
|
||||
@@ -18,20 +16,12 @@ interface Props {
|
||||
}
|
||||
|
||||
export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Props) {
|
||||
const osInfo = useOsInfo();
|
||||
const [maximized, setMaximized] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<HStack
|
||||
space={2}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
className={classNames(className, 'w-full h-full')}
|
||||
>
|
||||
<HStack space={0.5} className="flex-1 pointer-events-none" alignItems="center">
|
||||
<HStack space={2} justifyContent="center" className={classNames(className, 'w-full h-full')}>
|
||||
<HStack space={0.5} className="flex-1 pointer-events-none">
|
||||
<SidebarActions />
|
||||
<CookieDropdown />
|
||||
<HStack alignItems="center">
|
||||
<HStack>
|
||||
<WorkspaceActionsDropdown />
|
||||
<Icon icon="chevronRight" className="text-fg-subtle" />
|
||||
<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">
|
||||
<ImportCurlButton />
|
||||
<SettingsDropdown />
|
||||
{(osInfo?.osType === 'linux' || osInfo?.osType === 'windows') && (
|
||||
<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>
|
||||
)}
|
||||
<WindowControls />
|
||||
</div>
|
||||
</HStack>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,6 @@ export function Checkbox({
|
||||
<HStack
|
||||
as="label"
|
||||
space={2}
|
||||
alignItems="center"
|
||||
className={classNames(className, 'text-fg', disabled && 'opacity-disabled')}
|
||||
>
|
||||
<div className={classNames(inputWrapperClassName, 'x-theme-input', 'relative flex')}>
|
||||
|
||||
@@ -224,7 +224,6 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
);
|
||||
const [menuStyles, setMenuStyles] = useState<CSSProperties>({});
|
||||
const [filter, setFilter] = useState<string>('');
|
||||
const [containerWidth, setContainerWidth] = useState<number | null>(null);
|
||||
|
||||
// Calculate the max height so we can scroll
|
||||
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],
|
||||
);
|
||||
|
||||
const initContainerRef = (n: HTMLDivElement | null) => {
|
||||
if (n == null) return null;
|
||||
setContainerWidth(n.offsetWidth);
|
||||
};
|
||||
|
||||
const { containerStyles, triangleStyles } = useMemo<{
|
||||
containerStyles: CSSProperties;
|
||||
triangleStyles: CSSProperties | null;
|
||||
@@ -379,7 +373,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
? { right: width / 2, marginRight: '-0.2rem', ...size }
|
||||
: { left: width / 2, marginLeft: '-0.2rem', ...size };
|
||||
return { containerStyles, triangleStyles };
|
||||
}, [triggerShape, containerWidth]);
|
||||
}, [triggerShape]);
|
||||
|
||||
const filteredItems = useMemo(
|
||||
() => 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"
|
||||
aria-orientation="vertical"
|
||||
dir="ltr"
|
||||
ref={initContainerRef}
|
||||
style={containerStyles}
|
||||
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 && (
|
||||
<HStack
|
||||
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"
|
||||
>
|
||||
<Icon icon="search" size="xs" className="text-fg-subtle" />
|
||||
|
||||
@@ -294,7 +294,6 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
{decoratedActions && (
|
||||
<HStack
|
||||
space={1}
|
||||
alignItems="center"
|
||||
justifyContent="end"
|
||||
className={classNames(
|
||||
'absolute bottom-2 left-0 right-0',
|
||||
|
||||
@@ -153,7 +153,6 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
|
||||
>
|
||||
{leftSlot}
|
||||
<HStack
|
||||
alignItems="center"
|
||||
className={classNames(
|
||||
'w-full min-w-0',
|
||||
leftSlot && 'pl-0.5 -ml-2',
|
||||
|
||||
@@ -105,7 +105,6 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
|
||||
>
|
||||
{leftSlot}
|
||||
<HStack
|
||||
alignItems="center"
|
||||
className={classNames(
|
||||
'w-full min-w-0',
|
||||
leftSlot && 'pl-0.5 -ml-2',
|
||||
|
||||
@@ -11,7 +11,7 @@ interface Props<T extends string> {
|
||||
hideLabel?: boolean;
|
||||
value: T;
|
||||
leftSlot?: ReactNode;
|
||||
options: SelectOption<T>[];
|
||||
options: SelectOption<T>[] | SelectOptionGroup<T>[];
|
||||
onChange: (value: T) => void;
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg';
|
||||
className?: string;
|
||||
@@ -22,6 +22,11 @@ export interface SelectOption<T extends string> {
|
||||
value: T;
|
||||
}
|
||||
|
||||
export interface SelectOptionGroup<T extends string> {
|
||||
label: string;
|
||||
options: SelectOption<T>[];
|
||||
}
|
||||
|
||||
export function Select<T extends string>({
|
||||
labelPosition = 'top',
|
||||
name,
|
||||
@@ -56,7 +61,6 @@ export function Select<T extends string>({
|
||||
</label>
|
||||
<HStack
|
||||
space={2}
|
||||
alignItems="center"
|
||||
className={classNames(
|
||||
'w-full rounded-md text-fg text-sm font-mono',
|
||||
'pl-2',
|
||||
@@ -77,11 +81,21 @@ export function Select<T extends string>({
|
||||
onBlur={() => setFocused(false)}
|
||||
className={classNames('pr-7 w-full outline-none bg-transparent')}
|
||||
>
|
||||
{options.map(({ label, value }) => (
|
||||
<option key={label} value={value}>
|
||||
{label}
|
||||
</option>
|
||||
))}
|
||||
{options.map((o) =>
|
||||
'options' in o ? (
|
||||
<optgroup key={o.label} label={o.label}>
|
||||
{o.options.map(({ label, value }) => (
|
||||
<option key={label} value={value}>
|
||||
{label}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
) : (
|
||||
<option key={o.label} value={o.value}>
|
||||
{o.label}
|
||||
</option>
|
||||
),
|
||||
)}
|
||||
</select>
|
||||
</HStack>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ interface HStackProps extends BaseStackProps {
|
||||
}
|
||||
|
||||
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
|
||||
ref: ForwardedRef<any>,
|
||||
) {
|
||||
@@ -27,6 +27,7 @@ export const HStack = forwardRef(function HStack(
|
||||
<BaseStack
|
||||
ref={ref}
|
||||
className={classNames(className, 'flex-row', space != null && gapClasses[space])}
|
||||
alignItems={alignItems}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user