diff --git a/src-web/components/RequestMethodDropdown.tsx b/src-web/components/RequestMethodDropdown.tsx index c72907ab..bee0d9cf 100644 --- a/src-web/components/RequestMethodDropdown.tsx +++ b/src-web/components/RequestMethodDropdown.tsx @@ -1,5 +1,9 @@ -import { memo } from 'react'; +import { memo, useMemo } from 'react'; +import { usePrompt } from '../hooks/usePrompt'; import { Button } from './core/Button'; +import type { DropdownItem } from './core/Dropdown'; +import { Icon } from './core/Icon'; +import type { RadioDropdownItem } from './core/RadioDropdown'; import { RadioDropdown } from './core/RadioDropdown'; type Props = { @@ -8,7 +12,15 @@ type Props = { onChange: (method: string) => void; }; -const methodItems = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'].map((m) => ({ +const radioItems: RadioDropdownItem[] = [ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'OPTIONS', + 'HEAD', +].map((m) => ({ value: m, label: m, })); @@ -18,8 +30,32 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({ onChange, className, }: Props) { + const prompt = usePrompt(); + const extraItems = useMemo( + () => [ + { type: 'separator' }, + { + key: 'custom', + label: 'CUSTOM', + leftSlot: , + onSelect: async () => { + const newMethod = await prompt({ + label: 'Http Method', + name: 'httpMethod', + defaultValue: '', + title: 'Custom Method', + description: 'Enter a custom method name', + placeholder: 'CUSTOM', + }); + onChange(newMethod); + }, + }, + ], + [onChange, prompt], + ); + return ( - + diff --git a/src-web/components/SettingsDialog.tsx b/src-web/components/SettingsDialog.tsx index 3faff84f..2e3d8ed9 100644 --- a/src-web/components/SettingsDialog.tsx +++ b/src-web/components/SettingsDialog.tsx @@ -21,7 +21,7 @@ export const SettingsDialog = () => { return ( - +
Appearance
, onSelect: () => sendRequest.mutate(), }, - { - key: 'sendAndDownloadRequest', - label: 'Send and Download', - leftSlot: , - onSelect: () => sendAndDownloadRequest.mutate(), - }, { type: 'separator' }, { key: 'duplicateRequest', diff --git a/src-web/components/core/Icon.tsx b/src-web/components/core/Icon.tsx index c9b9fba6..cd637f00 100644 --- a/src-web/components/core/Icon.tsx +++ b/src-web/components/core/Icon.tsx @@ -1,63 +1,64 @@ import * as lucide from 'lucide-react'; import classNames from 'classnames'; -import type {HTMLAttributes} from 'react'; -import {memo} from 'react'; +import type { HTMLAttributes } from 'react'; +import { memo } from 'react'; const icons = { - archive: lucide.ArchiveIcon, - box: lucide.BoxIcon, - chat: lucide.MessageSquare, - check: lucide.CheckIcon, - chevronDown: lucide.ChevronDownIcon, - chevronRight: lucide.ChevronRightIcon, - code: lucide.CodeIcon, - copy: lucide.CopyIcon, - download: lucide.DownloadIcon, - externalLink: lucide.ExternalLinkIcon, - eye: lucide.EyeIcon, - eyeClosed: lucide.EyeOffIcon, - filter: lucide.FilterIcon, - flask: lucide.FlaskConicalIcon, - gripVertical: lucide.GripVerticalIcon, - keyboard: lucide.KeyboardIcon, - leftPanelHidden: lucide.PanelLeftOpenIcon, - leftPanelVisible: lucide.PanelLeftCloseIcon, - magicWand: lucide.Wand2Icon, - moreVertical: lucide.MoreVerticalIcon, - pencil: lucide.PencilIcon, - plus: lucide.PlusIcon, - plusCircle: lucide.PlusCircleIcon, - question: lucide.ShieldQuestionIcon, - sendHorizontal: lucide.SendHorizonalIcon, - settings2: lucide.Settings2Icon, - settings: lucide.SettingsIcon, - trash: lucide.TrashIcon, - update: lucide.RefreshCcwIcon, - upload: lucide.UploadIcon, - x: lucide.XIcon, + archive: lucide.ArchiveIcon, + box: lucide.BoxIcon, + chat: lucide.MessageSquare, + check: lucide.CheckIcon, + chevronDown: lucide.ChevronDownIcon, + chevronRight: lucide.ChevronRightIcon, + code: lucide.CodeIcon, + copy: lucide.CopyIcon, + download: lucide.DownloadIcon, + externalLink: lucide.ExternalLinkIcon, + eye: lucide.EyeIcon, + eyeClosed: lucide.EyeOffIcon, + filter: lucide.FilterIcon, + flask: lucide.FlaskConicalIcon, + gripVertical: lucide.GripVerticalIcon, + keyboard: lucide.KeyboardIcon, + leftPanelHidden: lucide.PanelLeftOpenIcon, + leftPanelVisible: lucide.PanelLeftCloseIcon, + magicWand: lucide.Wand2Icon, + moreVertical: lucide.MoreVerticalIcon, + pencil: lucide.PencilIcon, + plus: lucide.PlusIcon, + plusCircle: lucide.PlusCircleIcon, + question: lucide.ShieldQuestionIcon, + sendHorizontal: lucide.SendHorizonalIcon, + settings2: lucide.Settings2Icon, + settings: lucide.SettingsIcon, + sparkles: lucide.SparklesIcon, + trash: lucide.TrashIcon, + update: lucide.RefreshCcwIcon, + upload: lucide.UploadIcon, + x: lucide.XIcon, - empty: (props: HTMLAttributes) => , + empty: (props: HTMLAttributes) => , }; export interface IconProps { - icon: keyof typeof icons; - className?: string; - size?: 'xs' | 'sm' | 'md'; - spin?: boolean; + icon: keyof typeof icons; + className?: string; + size?: 'xs' | 'sm' | 'md'; + spin?: boolean; } -export const Icon = memo(function Icon({icon, spin, size = 'md', className}: IconProps) { - const Component = icons[icon] ?? icons.question; - return ( - - ); +export const Icon = memo(function Icon({ icon, spin, size = 'md', className }: IconProps) { + const Component = icons[icon] ?? icons.question; + return ( + + ); }); diff --git a/src-web/components/core/RadioDropdown.tsx b/src-web/components/core/RadioDropdown.tsx index e8297da2..7454da80 100644 --- a/src-web/components/core/RadioDropdown.tsx +++ b/src-web/components/core/RadioDropdown.tsx @@ -16,18 +16,20 @@ export interface RadioDropdownProps { value: T; onChange: (value: T) => void; items: RadioDropdownItem[]; + extraItems?: DropdownProps['items']; children: DropdownProps['children']; } export function RadioDropdown({ value, items, + extraItems, onChange, children, }: RadioDropdownProps) { const dropdownItems = useMemo( - () => - items.map((item) => { + () => [ + ...items.map((item) => { if (item.type === 'separator') { return item; } else { @@ -40,7 +42,9 @@ export function RadioDropdown({ }; } }), - [items, value, onChange], + ...(extraItems ?? []), + ], + [items, extraItems, value, onChange], ); return {children}; diff --git a/src-web/hooks/Prompt.tsx b/src-web/hooks/Prompt.tsx index 74e6cf54..23dd0d1a 100644 --- a/src-web/hooks/Prompt.tsx +++ b/src-web/hooks/Prompt.tsx @@ -10,10 +10,11 @@ export interface PromptProps { onResult: (value: string) => void; label: InputProps['label']; name: InputProps['name']; - defaultValue: InputProps['defaultValue']; + defaultValue?: InputProps['defaultValue']; + placeholder?: InputProps['placeholder']; } -export function Prompt({ onHide, label, name, defaultValue, onResult }: PromptProps) { +export function Prompt({ onHide, label, name, defaultValue, placeholder, onResult }: PromptProps) { const [value, setValue] = useState(defaultValue ?? ''); const handleSubmit = useCallback( (e: FormEvent) => { @@ -33,6 +34,7 @@ export function Prompt({ onHide, label, name, defaultValue, onResult }: PromptPr hideLabel require autoSelect + placeholder={placeholder} label={label} name={name} defaultValue={defaultValue} diff --git a/src-web/hooks/usePrompt.ts b/src-web/hooks/usePrompt.ts index 89b72707..25261b61 100644 --- a/src-web/hooks/usePrompt.ts +++ b/src-web/hooks/usePrompt.ts @@ -1,3 +1,4 @@ +import { dialog } from '@tauri-apps/api'; import type { DialogProps } from '../components/core/Dialog'; import { useDialog } from '../components/DialogContext'; import type { PromptProps } from './Prompt'; @@ -11,20 +12,17 @@ export function usePrompt() { name, label, defaultValue, - }: { - title: DialogProps['title']; - description?: DialogProps['description']; - name: PromptProps['name']; - label: PromptProps['label']; - defaultValue: PromptProps['defaultValue']; - }) => + placeholder, + }: Pick & + Pick) => new Promise((onResult: PromptProps['onResult']) => { dialog.show({ title, description, hideX: true, size: 'sm', - render: ({ hide }) => Prompt({ onHide: hide, onResult, name, label, defaultValue }), + render: ({ hide }) => + Prompt({ onHide: hide, onResult, name, label, defaultValue, placeholder }), }); }); } diff --git a/src-web/lib/theme/theme.ts b/src-web/lib/theme/theme.ts index a52d8d01..12025935 100644 --- a/src-web/lib/theme/theme.ts +++ b/src-web/lib/theme/theme.ts @@ -101,6 +101,22 @@ export function generateColors( } const lightnessMap: Record> = { + system: { + // Not actually used + 0: 1, + 50: 1, + 100: 0.9, + 200: 0.7, + 300: 0.4, + 400: 0.2, + 500: 0, + 600: -0.2, + 700: -0.4, + 800: -0.6, + 900: -0.8, + 950: -0.9, + 1000: -1, + }, light: { 0: 1, 50: 1,