Even better styles

This commit is contained in:
Gregory Schier
2024-02-01 00:36:49 -08:00
parent 1628d0c843
commit a3c979a987
5 changed files with 67 additions and 53 deletions

View File

@@ -1,17 +1,16 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { m } from 'framer-motion';
import type { CSSProperties, FormEvent } from 'react'; import type { CSSProperties, FormEvent } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useAlert } from '../hooks/useAlert'; import { useAlert } from '../hooks/useAlert';
import type { GrpcMessage } from '../hooks/useGrpc'; import type { GrpcMessage } from '../hooks/useGrpc';
import { useGrpc } from '../hooks/useGrpc'; import { useGrpc } from '../hooks/useGrpc';
import { useKeyValue } from '../hooks/useKeyValue'; import { useKeyValue } from '../hooks/useKeyValue';
import { tryFormatJson } from '../lib/formatters';
import { Banner } from './core/Banner'; import { Banner } from './core/Banner';
import { Editor } from './core/Editor'; import { Editor } from './core/Editor';
import { HotKeyList } from './core/HotKeyList'; import { HotKeyList } from './core/HotKeyList';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
import { IconButton } from './core/IconButton';
import { JsonAttributeTree } from './core/JsonAttributeTree'; import { JsonAttributeTree } from './core/JsonAttributeTree';
import { Select } from './core/Select'; import { Select } from './core/Select';
import { Separator } from './core/Separator'; import { Separator } from './core/Separator';
@@ -144,12 +143,30 @@ export function GrpcConnectionLayout({ style }: Props) {
id="foo" id="foo"
url={url.value ?? ''} url={url.value ?? ''}
method={null} method={null}
submitIcon={null}
forceUpdateKey="to-do" forceUpdateKey="to-do"
placeholder="localhost:50051" placeholder="localhost:50051"
onSubmit={handleConnect} onSubmit={handleConnect}
isLoading={grpc.unary.isLoading} isLoading={grpc.unary.isLoading}
onUrlChange={url.set} onUrlChange={url.set}
submitIcon={ />
<Select
hideLabel
name="service"
label="Service"
className="text-gray-800"
size="sm"
value={select.value}
onChange={handleChangeService}
options={select.options}
/>
<IconButton
className="border border-highlight"
size="sm"
title="ofo"
hotkeyAction="request.send"
onClick={handleConnect}
icon={
!activeMethod?.clientStreaming && activeMethod?.serverStreaming !activeMethod?.clientStreaming && activeMethod?.serverStreaming
? 'arrowDownToDot' ? 'arrowDownToDot'
: activeMethod?.clientStreaming && !activeMethod?.serverStreaming : activeMethod?.clientStreaming && !activeMethod?.serverStreaming
@@ -159,15 +176,6 @@ export function GrpcConnectionLayout({ style }: Props) {
: 'sendHorizontal' : 'sendHorizontal'
} }
/> />
<Select
hideLabel
name="service"
label="Service"
size="sm"
value={select.value}
onChange={handleChangeService}
options={select.options}
/>
</div> </div>
<GrpcEditor <GrpcEditor
forceUpdateKey={[service, method].join('::')} forceUpdateKey={[service, method].join('::')}
@@ -225,10 +233,10 @@ export function GrpcConnectionLayout({ style }: Props) {
activeMessage ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-[100%]', activeMessage ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-[100%]',
)} )}
> >
<div className="pb-2 px-2"> <div className="pb-1 px-2">
<Separator /> <Separator />
</div> </div>
<div className="pl-2"> <div className="pl-2 pb-1">
<JsonAttributeTree <JsonAttributeTree
depth={0} depth={0}
attrValue={JSON.parse(activeMessage?.message ?? '{}')} attrValue={JSON.parse(activeMessage?.message ?? '{}')}

View File

@@ -180,9 +180,9 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
<WebPageViewer response={activeResponse} /> <WebPageViewer response={activeResponse} />
) : contentType?.match(/csv|tab-separated/) ? ( ) : contentType?.match(/csv|tab-separated/) ? (
<CsvViewer className="pb-2" response={activeResponse} /> <CsvViewer className="pb-2" response={activeResponse} />
) : contentType?.startsWith('application/json') ? (
<JsonViewer response={activeResponse} />
) : ( ) : (
// ) : contentType?.startsWith('application/json') ? (
// <JsonViewer response={activeResponse} />
<TextViewer response={activeResponse} pretty={viewMode === 'pretty'} /> <TextViewer response={activeResponse} pretty={viewMode === 'pretty'} />
)} )}
</TabContent> </TabContent>

View File

@@ -14,7 +14,7 @@ type Props = Pick<HttpRequest, 'id' | 'url'> & {
placeholder: string; placeholder: string;
onSubmit: (e: FormEvent) => void; onSubmit: (e: FormEvent) => void;
onUrlChange: (url: string) => void; onUrlChange: (url: string) => void;
submitIcon?: IconProps['icon']; submitIcon?: IconProps['icon'] | null;
onMethodChange?: (method: string) => void; onMethodChange?: (method: string) => void;
isLoading: boolean; isLoading: boolean;
forceUpdateKey: string; forceUpdateKey: string;
@@ -74,16 +74,18 @@ export const UrlBar = memo(function UrlBar({
) )
} }
rightSlot={ rightSlot={
<IconButton submitIcon !== null && (
size="xs" <IconButton
iconSize="md" size="xs"
title="Send Request" iconSize="md"
type="submit" title="Send Request"
className="w-8 mr-0.5 my-0.5" type="submit"
icon={isLoading ? 'update' : submitIcon} className="w-8 mr-0.5 my-0.5"
spin={isLoading} icon={isLoading ? 'update' : submitIcon}
hotkeyAction="request.send" spin={isLoading}
/> hotkeyAction="request.send"
/>
)
} }
/> />
</form> </form>

View File

@@ -38,8 +38,8 @@ export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPa
)) ))
: null, : null,
isExpandable: true, isExpandable: true,
label: isExpanded ? undefined : `{⋯}`, label: isExpanded ? '{ }' : `{⋯}`,
labelClassName: 'text-gray-500', labelClassName: 'text-gray-600',
}; };
} else if (jsonType === '[object Array]') { } else if (jsonType === '[object Array]') {
return { return {
@@ -54,8 +54,8 @@ export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPa
)) ))
: null, : null,
isExpandable: true, isExpandable: true,
label: isExpanded ? undefined : `[⋯]`, label: isExpanded ? '[ ]' : `[⋯]`,
labelClassName: 'text-gray-500', labelClassName: 'text-gray-600',
}; };
} else { } else {
return { return {
@@ -72,25 +72,38 @@ export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPa
} }
}, [attrValue, attrKeyJsonPath, isExpanded, depth]); }, [attrValue, attrKeyJsonPath, isExpanded, depth]);
const labelEl = (
<span className={classNames(labelClassName, 'select-text group-hover:text-gray-800')}>
{label}
</span>
);
return ( return (
<div className={classNames(depth === 0 && '-ml-4', 'font-mono text-xs')}> <div className={classNames(/*depth === 0 && '-ml-4',*/ 'font-mono text-xs')}>
<div className="flex items-center"> <div className="flex items-center">
{depth === 0 ? null : isExpandable ? ( {isExpandable ? (
<button className="relative flex items-center pl-4" onClick={toggleExpanded}> <button className="group relative flex items-center pl-4" onClick={toggleExpanded}>
<Icon <Icon
className={classNames(
'left-0 absolute transition-transform text-gray-500 flex gap-1 items-center',
isExpanded ? 'rotate-90' : '',
)}
size="xs" size="xs"
icon="chevronRight" icon="chevronRight"
className={classNames(
'left-0 absolute transition-transform text-gray-600 flex items-center',
'group-hover:text-gray-900',
isExpanded ? 'rotate-90' : '',
)}
/> />
<span className="text-violet-600 mr-1.5 whitespace-nowrap">{attrKey}:</span> <span className="text-violet-600 mr-1.5 whitespace-nowrap">
{attrKey === undefined ? '$' : attrKey}:
</span>
{labelEl}
</button> </button>
) : ( ) : (
<span className="text-violet-600 mr-1.5 pl-4 whitespace-nowrap">{attrKey}:</span> <>
<span className="text-violet-600 mr-1.5 pl-4 whitespace-nowrap select-text">
{attrKey}:
</span>
{labelEl}
</>
)} )}
<span className={classNames(labelClassName, 'select-text')}>{label}</span>
</div> </div>
{children && <div className="ml-4 whitespace-nowrap">{children}</div>} {children && <div className="ml-4 whitespace-nowrap">{children}</div>}
</div> </div>

View File

@@ -19,20 +19,8 @@ export function useGrpc(url: string | null) {
useListenToTauriEvent<string>( useListenToTauriEvent<string>(
'grpc_message', 'grpc_message',
(event) => { (event) => {
console.log('GOT MESSAGE', event);
setMessages((prev) => [ setMessages((prev) => [
...prev, ...prev,
{
message: JSON.stringify({
dummy: 'Yo, this is a dummy message',
another: 'property',
list: [1, 2, 3, 4, 5],
null: null,
bool: true,
}),
time: new Date(),
isServer: false,
},
{ message: event.payload, time: new Date(), isServer: true }, { message: event.payload, time: new Date(), isServer: true },
]); ]);
}, },
@@ -59,6 +47,9 @@ export function useGrpc(url: string | null) {
mutationKey: ['grpc_server_streaming', url], mutationKey: ['grpc_server_streaming', url],
mutationFn: async ({ service, method, message }) => { mutationFn: async ({ service, method, message }) => {
if (url === null) throw new Error('No URL provided'); if (url === null) throw new Error('No URL provided');
setMessages([
{ isServer: false, message: JSON.stringify(JSON.parse(message)), time: new Date() },
]);
return (await invoke('grpc_server_streaming', { return (await invoke('grpc_server_streaming', {
endpoint: url, endpoint: url,
service, service,