From 87c7b3a663f4adfe5c4e00fc63176cb622ac4e46 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Fri, 3 Mar 2023 13:18:57 -0800 Subject: [PATCH] Beginnings of Header Editor --- .eslintrc.cjs | 1 + src-web/components/Button.tsx | 19 ++++--- src-web/components/Dialog.tsx | 53 +++++++++++------- src-web/components/Editor/Editor.css | 2 +- src-web/components/HeaderEditor.tsx | 82 ++++++++++++++++++++++++++++ src-web/components/Input.tsx | 23 +++----- src-web/components/Sidebar.tsx | 6 +- src-web/main.css | 2 +- tailwind.config.cjs | 1 + 9 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 src-web/components/HeaderEditor.tsx diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e6d78a23..63358f8c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -20,6 +20,7 @@ module.exports = { }, }, rules: { + "jsx-a11y/no-autofocus": "warn", "react/react-in-jsx-scope": "off", "@typescript-eslint/consistent-type-imports": ["error", { prefer: "type-imports", diff --git a/src-web/components/Button.tsx b/src-web/components/Button.tsx index 525c78ff..ab745cc1 100644 --- a/src-web/components/Button.tsx +++ b/src-web/components/Button.tsx @@ -1,16 +1,16 @@ -import { +import classnames from 'classnames'; +import type { ButtonHTMLAttributes, ComponentPropsWithoutRef, ElementType, ForwardedRef, - forwardRef, } from 'react'; -import classnames from 'classnames'; +import { forwardRef } from 'react'; import { Icon } from './Icon'; export interface ButtonProps extends ButtonHTMLAttributes { - color?: 'primary' | 'secondary'; + color?: 'primary' | 'secondary' | 'warning' | 'danger'; size?: 'xs' | 'sm' | 'md'; justify?: 'start' | 'center'; forDropdown?: boolean; @@ -34,18 +34,21 @@ export const Button = forwardRef(function Button( return ( diff --git a/src-web/components/Dialog.tsx b/src-web/components/Dialog.tsx index 3527d860..9271e2bd 100644 --- a/src-web/components/Dialog.tsx +++ b/src-web/components/Dialog.tsx @@ -1,5 +1,6 @@ import * as D from '@radix-ui/react-dialog'; import classnames from 'classnames'; +import { motion } from 'framer-motion'; import React from 'react'; import { IconButton } from './IconButton'; import { HStack, VStack } from './Stacks'; @@ -10,30 +11,44 @@ interface Props { onOpenChange: (open: boolean) => void; title: string; description?: string; + className?: string; + wide?: boolean; } -export function Dialog({ children, open, onOpenChange, title, description }: Props) { +export function Dialog({ + children, + className, + wide, + open, + onOpenChange, + title, + description, +}: Props) { return ( ('#radix-portal')}> - - - - - - - - {title} - - {description && {description}} -
{children}
-
-
+ + + + + + + + + {title} + + {description && {description}} +
{children}
+
+
+
); diff --git a/src-web/components/Editor/Editor.css b/src-web/components/Editor/Editor.css index d644e8cb..dda5fa27 100644 --- a/src-web/components/Editor/Editor.css +++ b/src-web/components/Editor/Editor.css @@ -25,7 +25,7 @@ text-shadow: 0 0 1px rgba(0, 0, 0, 0.9); } -.cm-editor .cm-scroller { +.cm-multiline .cm-editor .cm-scroller { @apply rounded-lg bg-gray-50; } diff --git a/src-web/components/HeaderEditor.tsx b/src-web/components/HeaderEditor.tsx new file mode 100644 index 00000000..f3f332da --- /dev/null +++ b/src-web/components/HeaderEditor.tsx @@ -0,0 +1,82 @@ +import type { FormEvent } from 'react'; +import React, { useState } from 'react'; +import type { HttpHeader } from '../lib/models'; +import { IconButton } from './IconButton'; +import { Input } from './Input'; +import { HStack, VStack } from './Stacks'; + +export function HeaderEditor() { + const [headers, setHeaders] = useState([]); + const [newHeader, setNewHeader] = useState({ name: '', value: '' }); + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + setHeaders([...headers, newHeader]); + setNewHeader({ name: '', value: '' }); + }; + + const handleDelete = (index: number) => { + setHeaders((headers) => headers.filter((_, i) => i !== index)); + }; + + const handleChangeHeader = (header: HttpHeader, index: number) => { + setHeaders((headers) => headers.map((h, i) => (i === index ? header : h))); + }; + + return ( +
+ + {headers.map((header, i) => ( + handleChangeHeader(h, i)} + onDelete={() => handleDelete(i)} + /> + ))} + + +
+ ); +} + +function FormRow({ + header, + addSubmit, + onChange, + onDelete, +}: { + header: HttpHeader; + addSubmit?: boolean; + onChange: (header: HttpHeader) => void; + onDelete?: () => void; +}) { + return ( +
+ + { + onChange({ name, value: header.value }); + }} + /> + { + onChange({ name: header.name, value }); + }} + /> + {onDelete && } + + {addSubmit && } +
+ ); +} diff --git a/src-web/components/Input.tsx b/src-web/components/Input.tsx index bf7d9432..d777a2f0 100644 --- a/src-web/components/Input.tsx +++ b/src-web/components/Input.tsx @@ -1,7 +1,7 @@ -import classnames from "classnames"; -import type { InputHTMLAttributes, ReactNode } from "react"; -import Editor from "./Editor/Editor"; -import { HStack, VStack } from "./Stacks"; +import classnames from 'classnames'; +import type { InputHTMLAttributes, ReactNode } from 'react'; +import Editor from './Editor/Editor'; +import { HStack, VStack } from './Stacks'; interface Props extends Omit, 'size' | 'onChange'> { name: string; @@ -45,7 +45,7 @@ export function Input({ htmlFor={id} className={classnames( labelClassName, - 'font-semibold text-sm uppercase text-gray-700 absolute', + 'font-semibold text-sm uppercase text-gray-700', hideLabel && 'sr-only', )} > @@ -55,8 +55,8 @@ export function Input({ items="center" className={classnames( containerClassName, - 'relative w-full bg-gray-50 rounded-md overflow-hidden text-gray-900', - 'border border-transparent focus-within:border-blue-400/40', + 'relative w-full rounded-md overflow-hidden text-gray-900 bg-gray-200/10', + 'border border-gray-500/10 focus-within:border-blue-400/40', size === 'md' && 'h-10', size === 'sm' && 'h-8', )} @@ -72,12 +72,7 @@ export function Input({ onChange={onChange} onSubmit={onSubmit} placeholder={placeholder} - className={classnames( - className, - 'bg-transparent min-w-0 pl-3 pr-2 h-full w-full focus:outline-none', - leftSlot && '!pl-1', - rightSlot && '!pr-1', - )} + className={className} /> ) : ( - -

This is the body

- + + diff --git a/src-web/main.css b/src-web/main.css index 1b1637a4..62aaa5e3 100644 --- a/src-web/main.css +++ b/src-web/main.css @@ -4,7 +4,7 @@ :root { color-scheme: light dark; - --transition-duration: 200ms ease-in-out; + --transition-duration: 100ms ease-in-out; } :not(input):not(textarea), diff --git a/tailwind.config.cjs b/tailwind.config.cjs index d69bf5c5..6145d63b 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -21,6 +21,7 @@ module.exports = { black: 'hsl(var(--color-black) / )', background: 'hsl(var(--color-background) / )', gray: color('gray'), + orange: color('orange'), blue: color('blue'), green: color('green'), pink: color('pink'),