Environments in URL and better rendering

This commit is contained in:
Gregory Schier
2023-10-25 11:13:00 -07:00
parent 3b660ddbd0
commit 33c406ce49
44 changed files with 226 additions and 160 deletions

View File

@@ -7,6 +7,7 @@ import RouteError from './RouteError';
import Workspace from './Workspace';
import Workspaces from './Workspaces';
import { DialogProvider } from './DialogContext';
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
const router = createBrowserRouter([
{
@@ -23,12 +24,16 @@ const router = createBrowserRouter([
element: <Workspaces />,
},
{
path: routePaths.workspace({ workspaceId: ':workspaceId' }),
path: routePaths.workspace({
workspaceId: ':workspaceId',
environmentId: ':environmentId',
}),
element: <WorkspaceOrRedirect />,
},
{
path: routePaths.request({
workspaceId: ':workspaceId',
environmentId: ':environmentId',
requestId: ':requestId',
}),
element: <Workspace />,
@@ -42,18 +47,23 @@ export function AppRouter() {
}
function WorkspaceOrRedirect() {
const environmentId = useActiveEnvironmentId();
const recentRequests = useRecentRequests();
const requests = useRequests();
const request = requests.find((r) => r.id === recentRequests[0]);
const routes = useAppRoutes();
if (request === undefined) {
if (request === undefined || environmentId === null) {
return <Workspace />;
}
return (
<Navigate
to={routes.paths.request({ workspaceId: request.workspaceId, requestId: request.id })}
to={routes.paths.request({
workspaceId: request.workspaceId,
environmentId,
requestId: request.id,
})}
/>
);
}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import React, { memo } from 'react';
interface Props {
@@ -9,7 +9,7 @@ export const DropMarker = memo(
function DropMarker({ className }: Props) {
return (
<div
className={classnames(
className={classNames(
className,
'relative w-full h-0 overflow-visible pointer-events-none',
)}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import { memo, useMemo } from 'react';
import { Button } from './core/Button';
import type { DropdownItem } from './core/Dropdown';
@@ -12,6 +12,7 @@ import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
import { usePrompt } from '../hooks/usePrompt';
import { useDialog } from './DialogContext';
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
import { useAppRoutes } from '../hooks/useAppRoutes';
type Props = {
className?: string;
@@ -21,11 +22,12 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
className,
}: Props) {
const environments = useEnvironments();
const [activeEnvironment, setActiveEnvironment] = useActiveEnvironment();
const activeEnvironment = useActiveEnvironment();
const updateEnvironment = useUpdateEnvironment(activeEnvironment?.id ?? null);
const createEnvironment = useCreateEnvironment();
const prompt = usePrompt();
const dialog = useDialog();
const routes = useAppRoutes();
const items: DropdownItem[] = useMemo(() => {
const environmentItems = environments.map(
@@ -33,7 +35,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
key: e.id,
label: e.name,
onSelect: async () => {
setActiveEnvironment(e);
routes.setEnvironment(e);
},
}),
[],
@@ -112,15 +114,15 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
dialog,
environments,
prompt,
setActiveEnvironment,
updateEnvironment,
routes,
]);
return (
<Dropdown items={items}>
<Button
size="sm"
className={classnames(className, 'text-gray-800 !px-2 truncate')}
className={classNames(className, 'text-gray-800 !px-2 truncate')}
forDropdown
>
{activeEnvironment?.name ?? <span className="italic text-gray-500">No Environment</span>}

View File

@@ -5,14 +5,17 @@ import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
import type { Environment } from '../lib/models';
import { Button } from './core/Button';
import { Editor } from './core/Editor';
import classnames from 'classnames';
import classNames from 'classnames';
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
import { Link } from 'react-router-dom';
import { useAppRoutes } from '../hooks/useAppRoutes';
export const EnvironmentEditDialog = function() {
const routes = useAppRoutes();
const prompt = usePrompt();
const environments = useEnvironments();
const createEnvironment = useCreateEnvironment();
const [activeEnvironment, setActiveEnvironment] = useActiveEnvironment();
const activeEnvironment = useActiveEnvironment();
return (
<div className="h-full grid gap-3 grid-cols-[auto_minmax(0,1fr)]">
@@ -20,14 +23,14 @@ export const EnvironmentEditDialog = function() {
{environments.map((e) => (
<Button
size="sm"
className={classnames(
className={classNames(
'w-full',
activeEnvironment?.id === e.id && 'bg-gray-100 text-gray-1000',
)}
justify="start"
key={e.id}
onClick={() => {
setActiveEnvironment(e);
routes.setEnvironment(e);
}}
>
{e.name}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import FocusTrap from 'focus-trap-react';
import { motion } from 'framer-motion';
import type { ReactNode } from 'react';
@@ -26,7 +26,7 @@ export function Overlay({ zIndex = 30, open, onClose, portalName, children }: Pr
{open && (
<FocusTrap>
<motion.div
className={classnames('fixed inset-0', zIndexes[zIndex])}
className={classNames('fixed inset-0', zIndexes[zIndex])}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>

View File

@@ -1,6 +1,6 @@
import { invoke } from '@tauri-apps/api';
import { appWindow } from '@tauri-apps/api/window';
import classnames from 'classnames';
import classNames from 'classnames';
import type { CSSProperties } from 'react';
import { memo, useCallback, useMemo, useState } from 'react';
import { createGlobalState } from 'react-use';
@@ -152,7 +152,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
return (
<div
style={style}
className={classnames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
className={classNames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
>
{activeRequest && (
<>

View File

@@ -1,5 +1,5 @@
import useResizeObserver from '@react-hook/resize-observer';
import classnames from 'classnames';
import classNames from 'classnames';
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
import { useLocalStorage } from 'react-use';
@@ -120,7 +120,7 @@ export const RequestResponse = memo(function RequestResponse({ style }: Props) {
<ResizeHandle
style={drag}
isResizing={isResizing}
className={classnames(vertical ? 'translate-y-0.5' : 'translate-x-0.5')}
className={classNames(vertical ? 'translate-y-0.5' : 'translate-x-0.5')}
onResizeStart={handleResizeStart}
onReset={handleReset}
side={vertical ? 'top' : 'left'}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
import React from 'react';
@@ -28,7 +28,7 @@ export function ResizeHandle({
aria-hidden
draggable
style={style}
className={classnames(
className={classNames(
className,
'group z-10 flex',
vertical ? 'w-full h-3 cursor-row-resize' : 'h-full w-3 cursor-col-resize',
@@ -45,7 +45,7 @@ export function ResizeHandle({
{/* Show global overlay with cursor style to ensure cursor remains the same when moving quickly */}
{isResizing && (
<div
className={classnames(
className={classNames(
'fixed -left-20 -right-20 -top-20 -bottom-20',
vertical && 'cursor-row-resize',
!vertical && 'cursor-col-resize',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { HttpResponse } from '../lib/models';
import { HStack } from './core/Stacks';
@@ -14,7 +14,7 @@ export function ResponseHeaders({ headers }: Props) {
<HStack
space={3}
key={i}
className={classnames(i > 0 ? 'border-t border-highlightSecondary py-1' : 'pb-1')}
className={classNames(i > 0 ? 'border-t border-highlightSecondary py-1' : 'pb-1')}
>
<dd className="w-1/3 text-violet-600 select-text cursor-text">{h.name}</dd>
<dt className="w-2/3 select-text cursor-text break-all">{h.value}</dt>

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { CSSProperties } from 'react';
import { useCallback, memo, useEffect, useMemo, useState } from 'react';
import { createGlobalState } from 'react-use';
@@ -84,7 +84,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
return (
<div
style={style}
className={classnames(
className={classNames(
className,
'bg-gray-50 max-h-full h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1',
'dark:bg-gray-100 rounded-md border border-highlight',
@@ -96,7 +96,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
<>
<HStack
alignItems="center"
className={classnames(
className={classNames(
'text-gray-700 text-sm w-full flex-shrink-0',
// Remove a bit of space because the tabs have lots too
'-mb-1.5',

View File

@@ -7,13 +7,14 @@ import { VStack } from './core/Stacks';
export default function RouteError() {
const error = useRouteError();
console.log("Error", error);
const stringified = JSON.stringify(error);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const message = (error as any).message ?? stringified;
const routes = useAppRoutes();
return (
<div className="flex items-center justify-center h-full">
<VStack space={5} className="max-w-[30rem] !h-auto">
<VStack space={5} className="max-w-[50rem] !h-auto">
<Heading>Route Error 🔥</Heading>
<FormattedError>{message}</FormattedError>
<VStack space={2}>

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { ForwardedRef } from 'react';
import React, { forwardRef, Fragment, memo, useCallback, useMemo, useRef, useState } from 'react';
import type { XYCoord } from 'react-dnd';
@@ -19,6 +19,7 @@ import { Icon } from './core/Icon';
import { VStack } from './core/Stacks';
import { StatusTag } from './core/StatusTag';
import { DropMarker } from './DropMarker';
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
interface Props {
className?: string;
@@ -32,6 +33,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
const { hidden } = useSidebarHidden();
const sidebarRef = useRef<HTMLDivElement>(null);
const activeRequestId = useActiveRequestId();
const activeEnvironmentId = useActiveEnvironmentId();
const unorderedRequests = useRequests();
const deleteAnyRequest = useDeleteAnyRequest();
const routes = useAppRoutes();
@@ -58,11 +60,15 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
const index = requests.findIndex((r) => r.id === requestId);
const request = requests[index];
if (!request) return;
routes.navigate('request', { requestId, workspaceId: request.workspaceId });
routes.navigate('request', {
requestId,
workspaceId: request.workspaceId,
environmentId: activeEnvironmentId,
});
setSelectedIndex(index);
focusActiveRequest(index);
},
[focusActiveRequest, requests, routes],
[focusActiveRequest, requests, routes, activeEnvironmentId],
);
const handleFocus = useCallback(() => {
@@ -143,7 +149,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
onFocus={handleFocus}
onBlur={handleBlur}
tabIndex={hidden ? -1 : 0}
className={classnames(className, 'h-full relative grid grid-rows-[minmax(0,1fr)_auto]')}
className={classNames(className, 'h-full relative grid grid-rows-[minmax(0,1fr)_auto]')}
>
<VStack
as="ul"
@@ -299,7 +305,7 @@ const _SidebarItem = forwardRef(function SidebarItem(
}, [onSelect, requestId]);
return (
<li ref={ref} className={classnames(className, 'block group/item px-2 pb-0.5')}>
<li ref={ref} className={classNames(className, 'block group/item px-2 pb-0.5')}>
<button
// tabIndex={-1} // Will prevent drag-n-drop
onClick={handleSelect}
@@ -307,7 +313,7 @@ const _SidebarItem = forwardRef(function SidebarItem(
onDoubleClick={handleStartEditing}
data-active={isActive}
data-selected={selected}
className={classnames(
className={classNames(
'w-full flex items-center text-sm h-xs px-2 rounded-md transition-colors',
editing && 'ring-1 focus-within:ring-focus',
isActive && 'bg-highlight text-gray-800',
@@ -324,7 +330,7 @@ const _SidebarItem = forwardRef(function SidebarItem(
onKeyDown={handleInputKeyDown}
/>
) : (
<span className={classnames('truncate', !requestName && 'text-gray-400 italic')}>
<span className={classNames('truncate', !requestName && 'text-gray-400 italic')}>
{requestName || 'New Request'}
</span>
)}
@@ -396,7 +402,7 @@ const DraggableSidebarItem = memo(function DraggableSidebarItem({
<SidebarItem
ref={ref}
draggable
className={classnames(isDragging && 'opacity-20')}
className={classNames(isDragging && 'opacity-20')}
requestName={requestName}
requestId={requestId}
{...props}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { EditorView } from 'codemirror';
import type { FormEvent } from 'react';
import { memo, useCallback, useRef } from 'react';
@@ -44,7 +44,7 @@ export const UrlBar = memo(function UrlBar({ id: requestId, url, method, classNa
});
return (
<form onSubmit={handleSubmit} className={classnames('url-bar', className)}>
<form onSubmit={handleSubmit} className={classNames('url-bar', className)}>
<Input
ref={inputRef}
size="sm"

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import { motion } from 'framer-motion';
import type {
CSSProperties,
@@ -113,7 +113,7 @@ export default function Workspace() {
return (
<div
style={styles}
className={classnames(
className={classNames(
'grid w-full h-full',
// Animate sidebar width changes but only when not resizing
// because it's too slow to animate on mouse move
@@ -125,7 +125,7 @@ export default function Workspace() {
<motion.div
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
className={classnames(
className={classNames(
'absolute top-0 left-0 bottom-0 bg-gray-100 border-r border-highlight w-[14rem]',
'grid grid-rows-[auto_1fr]',
)}
@@ -140,7 +140,7 @@ export default function Workspace() {
</Overlay>
) : (
<>
<div style={side} className={classnames('overflow-hidden bg-gray-100')}>
<div style={side} className={classNames('overflow-hidden bg-gray-100')}>
<Sidebar className="border-r border-highlight" />
</div>
<ResizeHandle
@@ -173,7 +173,7 @@ function HeaderSize({ className, ...props }: HeaderSizeProps) {
const platform = useOsInfo();
return (
<div
className={classnames(
className={classNames(
className,
'h-md pt-[1px] flex items-center w-full pr-3 pl-20 border-b',
platform?.osType === 'Darwin' && 'pl-20',

View File

@@ -1,5 +1,5 @@
import { invoke } from '@tauri-apps/api';
import classnames from 'classnames';
import classNames from 'classnames';
import { memo, useMemo } from 'react';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes';
@@ -15,6 +15,7 @@ import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode';
import { HStack } from './core/Stacks';
import { useDialog } from './DialogContext';
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
type Props = {
className?: string;
@@ -24,6 +25,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace();
const activeWorkspaceId = activeWorkspace?.id ?? null;
const environmentId = useActiveEnvironmentId();
const createWorkspace = useCreateWorkspace({ navigateAfter: true });
const updateWorkspace = useUpdateWorkspace(activeWorkspaceId);
const deleteWorkspace = useDeleteWorkspace(activeWorkspace);
@@ -53,7 +55,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
color="gray"
onClick={() => {
hide();
routes.navigate('workspace', { workspaceId: w.id });
routes.navigate('workspace', { workspaceId: w.id, environmentId });
}}
>
This Window
@@ -66,7 +68,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
onClick={async () => {
hide();
await invoke('new_window', {
url: routes.paths.workspace({ workspaceId: w.id }),
url: routes.paths.workspace({ workspaceId: w.id, environmentId }),
});
}}
>
@@ -150,7 +152,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
<Dropdown items={items}>
<Button
size="sm"
className={classnames(className, 'text-gray-800 !px-2 truncate')}
className={classNames(className, 'text-gray-800 !px-2 truncate')}
forDropdown
>
{activeWorkspace?.name}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import { memo } from 'react';
import { useActiveRequest } from '../hooks/useActiveRequest';
import { IconButton } from './core/IconButton';
@@ -20,7 +20,7 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
<HStack
justifyContent="center"
alignItems="center"
className={classnames(className, 'w-full h-full')}
className={classNames(className, 'w-full h-full')}
>
<HStack space={0.5} className="flex-1 pointer-events-none" alignItems="center">
<SidebarActions />

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { ReactNode } from 'react';
interface Props {
@@ -9,7 +9,7 @@ export function Banner({ children, className }: Props) {
return (
<div>
<div
className={classnames(
className={classNames(
className,
'border border-red-500 bg-red-300/10 text-red-800 px-3 py-2 rounded select-auto cursor-text',
)}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { HTMLAttributes, ReactNode } from 'react';
import { forwardRef, memo, useMemo } from 'react';
import { Icon } from './Icon';
@@ -45,7 +45,7 @@ const _Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
) {
const classes = useMemo(
() =>
classnames(
classNames(
className,
'flex-shrink-0 outline-none whitespace-nowrap',
'focus-visible-or-class:ring',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import { useCallback } from 'react';
import { Icon } from './Icon';
@@ -20,7 +20,7 @@ export function Checkbox({ checked, onChange, className, disabled }: Props) {
aria-checked={checked ? 'true' : 'false'}
disabled={disabled}
onClick={handleClick}
className={classnames(
className={classNames(
className,
'flex-shrink-0 w-4 h-4 border border-gray-200 rounded',
'focus:border-focus',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
interface Props {
count: number;
@@ -10,7 +10,7 @@ export function CountBadge({ count, className }: Props) {
return (
<div
aria-hidden
className={classnames(
className={classNames(
className,
'opacity-70 border border-highlight text-3xs rounded mb-0.5 px-1 ml-1 h-4 font-mono',
)}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import { motion } from 'framer-motion';
import type { ReactNode } from 'react';
import { useMemo } from 'react';
@@ -51,7 +51,7 @@ export function Dialog({
<motion.div
initial={{ top: 5, scale: 0.97 }}
animate={{ top: 0, scale: 1 }}
className={classnames(
className={classNames(
className,
'gap-2 grid grid-rows-[auto_minmax(0,1fr)]',
'relative bg-gray-50 pointer-events-auto',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import FocusTrap from 'focus-trap-react';
import { motion } from 'framer-motion';
import type { CSSProperties, HTMLAttributes, MouseEvent, ReactElement, ReactNode } from 'react';
@@ -278,7 +278,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
dir="ltr"
ref={containerRef}
style={containerStyles}
className={classnames(className, 'outline-none mt-1 pointer-events-auto fixed z-50')}
className={classNames(className, 'outline-none mt-1 pointer-events-auto fixed z-50')}
>
<span
aria-hidden
@@ -290,7 +290,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
space={0.5}
ref={initMenu}
style={menuStyles}
className={classnames(
className={classNames(
className,
'h-auto bg-gray-50 rounded-md shadow-lg dark:shadow-gray-0 py-1.5 border',
'border-gray-200 overflow-auto mb-1 mx-0.5',
@@ -356,7 +356,7 @@ function MenuItem({ className, focused, onFocus, item, onSelect, ...props }: Men
onFocus={handleFocus}
onClick={handleClick}
justify="start"
className={classnames(
className={classNames(
className,
'min-w-[8rem] outline-none px-2 mx-1.5 flex text-sm text-gray-700 whitespace-nowrap',
'focus:bg-highlight focus:text-gray-900 rounded',
@@ -366,7 +366,7 @@ function MenuItem({ className, focused, onFocus, item, onSelect, ...props }: Men
>
{item.leftSlot && <div className="pr-2 flex justify-start">{item.leftSlot}</div>}
<div
className={classnames(
className={classNames(
// Add padding on right when no right slot, for some visual balance
!item.rightSlot && 'pr-4',
)}

View File

@@ -2,7 +2,7 @@ import { defaultKeymap } from '@codemirror/commands';
import { Compartment, EditorState, Transaction } from '@codemirror/state';
import type { ViewUpdate } from '@codemirror/view';
import { keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
import classnames from 'classnames';
import classNames from 'classnames';
import { EditorView } from 'codemirror';
import type { MutableRefObject, ReactNode } from 'react';
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef } from 'react';
@@ -168,7 +168,7 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
const cmContainer = (
<div
ref={initEditorRef}
className={classnames(
className={classNames(
className,
'cm-wrapper text-base bg-gray-50',
type === 'password' && 'cm-obscure-text',

View File

@@ -1,10 +1,17 @@
import classNames from 'classnames';
interface Props {
children: string;
}
export function FormattedError({ children }: Props) {
return (
<pre className="text-sm select-auto cursor-text bg-gray-100 p-3 rounded whitespace-normal border border-red-500 border-dashed">
<pre
className={classNames(
'text-sm select-auto cursor-text bg-gray-100 p-3 rounded',
'whitespace-normal border border-red-500 border-dashed',
)}
>
{children}
</pre>
);

View File

@@ -1,9 +1,9 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
export function Heading({ className, children, ...props }: HTMLAttributes<HTMLHeadingElement>) {
return (
<h1 className={classnames(className, 'text-2xl font-semibold text-gray-900 mb-3')} {...props}>
<h1 className={classNames(className, 'text-2xl font-semibold text-gray-900 mb-3')} {...props}>
{children}
</h1>
);

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
interface Props {
modifier: 'Meta' | 'Control' | 'Shift';
@@ -13,7 +13,7 @@ const keys: Record<Props['modifier'], string> = {
export function HotKey({ modifier, keyName }: Props) {
return (
<span className={classnames('text-sm text-gray-600')}>
<span className={classNames('text-sm text-gray-600')}>
{keys[modifier]}
{keyName}
</span>

View File

@@ -36,7 +36,7 @@ import {
TriangleRightIcon,
UpdateIcon,
} from '@radix-ui/react-icons';
import classnames from 'classnames';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { memo } from 'react';
import { ReactComponent as LeftPanelHiddenIcon } from '../../assets/icons/LeftPanelHiddenIcon.svg';
@@ -95,7 +95,7 @@ export const Icon = memo(function Icon({ icon, spin, size = 'md', className }: I
const Component = icons[icon] ?? icons.question;
return (
<Component
className={classnames(
className={classNames(
className,
'text-inherit',
size === 'md' && 'h-4 w-4',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { MouseEvent } from 'react';
import { forwardRef, useCallback } from 'react';
import { useTimedBoolean } from '../../hooks/useTimedBoolean';
@@ -45,7 +45,7 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
disabled={icon === 'empty'}
tabIndex={tabIndex ?? icon === 'empty' ? -1 : undefined}
onClick={handleClick}
className={classnames(
className={classNames(
className,
'flex-shrink-0 text-gray-700 hover:text-gray-1000',
'!px-0',
@@ -60,7 +60,7 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButt
size={iconSize}
icon={confirmed ? 'check' : icon}
spin={spin}
className={classnames(
className={classNames(
iconClassName,
props.disabled && 'opacity-70',
confirmed && 'text-green-600',

View File

@@ -1,10 +1,10 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
export function InlineCode({ className, ...props }: HTMLAttributes<HTMLSpanElement>) {
return (
<code
className={classnames(
className={classNames(
className,
'font-mono text-sm bg-highlight border-0 border-gray-200 px-1.5 py-0.5 rounded text-gray-800 shadow-inner',
)}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { EditorView } from 'codemirror';
import type { HTMLAttributes, ReactNode } from 'react';
import { forwardRef, useCallback, useMemo, useState } from 'react';
@@ -68,7 +68,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
}, [onBlur]);
const id = `input-${name}`;
const inputClassName = classnames(
const inputClassName = classNames(
className,
'!bg-transparent min-w-0 h-full w-full focus:outline-none placeholder:text-placeholder',
// Bump things over if the slots are occupied
@@ -94,7 +94,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
<VStack className="w-full">
<label
htmlFor={id}
className={classnames(
className={classNames(
labelClassName,
'font-semibold text-xs uppercase text-gray-700',
hideLabel && 'sr-only',
@@ -104,7 +104,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
</label>
<HStack
alignItems="center"
className={classnames(
className={classNames(
containerClassName,
'relative w-full rounded-md text-gray-900',
'border',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import React, { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { XYCoord } from 'react-dnd';
import { useDrag, useDrop } from 'react-dnd';
@@ -134,7 +134,7 @@ export const PairEditor = memo(function PairEditor({
return (
<div
className={classnames(
className={classNames(
className,
'@container',
'pb-2 grid overflow-auto max-h-full',
@@ -264,7 +264,7 @@ const FormRow = memo(function FormRow({
return (
<div
ref={ref}
className={classnames(
className={classNames(
className,
'group grid grid-cols-[auto_auto_minmax(0,1fr)_auto]',
'grid-rows-1 items-center',
@@ -273,7 +273,7 @@ const FormRow = memo(function FormRow({
>
{!isLast ? (
<div
className={classnames(
className={classNames(
'py-2 h-7 w-3 flex items-center',
'justify-center opacity-0 hover:opacity-100',
)}
@@ -286,11 +286,11 @@ const FormRow = memo(function FormRow({
<Checkbox
disabled={isLast}
checked={isLast ? false : !!pairContainer.pair.enabled}
className={classnames('mr-2', isLast && '!opacity-disabled')}
className={classNames('mr-2', isLast && '!opacity-disabled')}
onChange={handleChangeEnabled}
/>
<div
className={classnames(
className={classNames(
'grid items-center',
'@xs:gap-2 @xs:!grid-rows-1 @xs:!grid-cols-[minmax(0,1fr)_minmax(0,1fr)]',
'gap-0.5 grid-cols-1 grid-rows-2',
@@ -303,7 +303,7 @@ const FormRow = memo(function FormRow({
validate={nameValidate}
useTemplating
forceUpdateKey={forceUpdateKey}
containerClassName={classnames(isLast && 'border-dashed')}
containerClassName={classNames(isLast && 'border-dashed')}
defaultValue={pairContainer.pair.name}
label="Name"
name="name"
@@ -315,7 +315,7 @@ const FormRow = memo(function FormRow({
<Input
hideLabel
size="sm"
containerClassName={classnames(isLast && 'border-dashed')}
containerClassName={classNames(isLast && 'border-dashed')}
validate={valueValidate}
forceUpdateKey={forceUpdateKey}
defaultValue={pairContainer.pair.value}

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
interface Props {
orientation?: 'horizontal' | 'vertical';
@@ -14,10 +14,10 @@ export function Separator({
label,
}: Props) {
return (
<div role="separator" className={classnames(className, 'flex items-center')}>
<div role="separator" className={classNames(className, 'flex items-center')}>
{label && <div className="text-xs text-gray-500 mx-2 whitespace-nowrap">{label}</div>}
<div
className={classnames(
className={classNames(
variant === 'primary' && 'bg-highlight',
variant === 'secondary' && 'bg-highlightSecondary',
orientation === 'horizontal' && 'w-full h-[1px]',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { ComponentType, ForwardedRef, HTMLAttributes, ReactNode } from 'react';
import { forwardRef } from 'react';
@@ -25,7 +25,7 @@ export const HStack = forwardRef(function HStack(
return (
<BaseStack
ref={ref}
className={classnames(className, 'flex-row', space != null && gapClasses[space])}
className={classNames(className, 'flex-row', space != null && gapClasses[space])}
{...props}
>
{children}
@@ -45,7 +45,7 @@ export const VStack = forwardRef(function VStack(
return (
<BaseStack
ref={ref}
className={classnames(className, 'flex-col', space != null && gapClasses[space])}
className={classNames(className, 'flex-col', space != null && gapClasses[space])}
{...props}
>
{children}
@@ -69,7 +69,7 @@ const BaseStack = forwardRef(function BaseStack(
return (
<Component
ref={ref}
className={classnames(
className={classNames(
className,
'flex',
alignItems === 'center' && 'items-center',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { HttpResponse } from '../../lib/models';
interface Props {
@@ -12,7 +12,7 @@ export function StatusTag({ response, className, showReason }: Props) {
const label = error ? 'ERR' : status;
return (
<span
className={classnames(
className={classNames(
className,
'font-mono',
status >= 0 && status < 100 && 'text-red-600',

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { ReactNode } from 'react';
import { memo, useCallback, useEffect, useRef } from 'react';
import { Button } from '../Button';
@@ -67,11 +67,11 @@ export function Tabs({
return (
<div
ref={ref}
className={classnames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
className={classNames(className, 'h-full grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1')}
>
<div
aria-label={label}
className={classnames(
className={classNames(
tabListClassName,
'flex items-center overflow-x-auto overflow-y-visible hide-scrollbars mt-1 mb-2',
// Give space for button focus states within overflow boundary.
@@ -81,7 +81,7 @@ export function Tabs({
<HStack space={2} className="flex-shrink-0">
{tabs.map((t) => {
const isActive = t.value === value;
const btnClassName = classnames(
const btnClassName = classNames(
isActive ? '' : 'text-gray-600 hover:text-gray-800',
'!px-2 ml-[1px]',
);
@@ -108,7 +108,7 @@ export function Tabs({
: option?.label ?? 'Unknown'}
<Icon
icon="triangleDown"
className={classnames('-mr-1.5', isActive ? 'opacity-100' : 'opacity-20')}
className={classNames('-mr-1.5', isActive ? 'opacity-100' : 'opacity-20')}
/>
</Button>
</RadioDropdown>
@@ -149,7 +149,7 @@ export const TabContent = memo(function TabContent({
<div
tabIndex={-1}
data-tab={value}
className={classnames(className, 'tab-content', 'hidden w-full h-full')}
className={classNames(className, 'tab-content', 'hidden w-full h-full')}
>
{children}
</div>

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import type { ReactNode } from 'react';
interface Props {
@@ -10,7 +10,7 @@ export function WindowDragRegion({ className, ...props }: Props) {
return (
<div
data-tauri-drag-region
className={classnames(className, 'w-full flex-shrink-0')}
className={classNames(className, 'w-full flex-shrink-0')}
{...props}
/>
);

View File

@@ -1,4 +1,4 @@
import classnames from 'classnames';
import classNames from 'classnames';
import Papa from 'papaparse';
import { useMemo } from 'react';
import { useResponseBodyText } from '../../hooks/useResponseBodyText';
@@ -21,10 +21,10 @@ export function CsvViewer({ response, className }: Props) {
return (
<div className="overflow-auto h-full">
<table className={classnames(className, 'text-sm')}>
<table className={classNames(className, 'text-sm')}>
<tbody>
{parsed.data.map((row, i) => (
<tr key={i} className={classnames('border-l border-t', i > 0 && 'border-b')}>
<tr key={i} className={classNames('border-l border-t', i > 0 && 'border-b')}>
{row.map((col, j) => (
<td key={j} className="border-r px-1.5">
{col}

View File

@@ -1,5 +1,5 @@
import { convertFileSrc } from '@tauri-apps/api/tauri';
import classnames from 'classnames';
import classNames from 'classnames';
import type { HttpResponse } from '../../lib/models';
interface Props {
@@ -17,7 +17,7 @@ export function ImageViewer({ response, className }: Props) {
<img
src={src}
alt="Response preview"
className={classnames(className, 'max-w-full max-h-full')}
className={classNames(className, 'max-w-full max-h-full')}
/>
);
}