diff --git a/app/components/Button.tsx b/app/components/Button.tsx index 8afd5ed..0fcf295 100644 --- a/app/components/Button.tsx +++ b/app/components/Button.tsx @@ -1,16 +1,15 @@ import type { Dispatch, SetStateAction } from 'react'; import React, { useRef } from 'react'; -import { Button as AriaButton } from 'react-aria-components'; -import { useButton } from 'react-aria'; +import { useButton, type AriaButtonOptions } from 'react-aria'; import { cn } from '~/utils/cn'; -export interface ButtonProps extends React.HTMLProps { - variant?: 'heavy' - isDisabled?: boolean +export interface ButtonProps extends AriaButtonOptions<'button'> { + variant?: 'heavy' | 'light' + className?: string children?: React.ReactNode } -export default function Button({ variant = 'light', ...props }: Props) { +export default function Button({ variant = 'light', ...props }: ButtonProps) { const ref = useRef(null); const { buttonProps } = useButton(props, ref); diff --git a/app/components/Card.tsx b/app/components/Card.tsx index b6ce641..35351ae 100644 --- a/app/components/Card.tsx +++ b/app/components/Card.tsx @@ -1,17 +1,8 @@ import React from 'react'; import Title from '~/components/Title'; +import Text from '~/components/Text'; import { cn } from '~/utils/cn'; -function Text(props: React.HTMLProps) { - return ( -

- ); -} - -type Props = React.HTMLProps & { - variant?: 'raised' | 'flat'; -}; - interface Props extends React.HTMLProps { variant?: 'raised' | 'flat'; } diff --git a/app/components/Dialog.tsx b/app/components/Dialog.tsx index 5a07e3f..00ec251 100644 --- a/app/components/Dialog.tsx +++ b/app/components/Dialog.tsx @@ -1,17 +1,17 @@ import React, { Dispatch, ReactNode, SetStateAction } from 'react'; import Button, { ButtonProps } from '~/components/Button'; import Title from '~/components/Title'; +import Text from '~/components/Text'; +import Card from '~/components/Card'; import { - Button as AriaButton, Dialog as AriaDialog, DialogTrigger, - Heading as AriaHeading, Modal, ModalOverlay, } from 'react-aria-components'; import { cn } from '~/utils/cn'; -interface ActionProps extends ButtonProps { +interface ActionProps extends Omit { variant: 'cancel' | 'confirm'; } @@ -25,10 +25,16 @@ function Action(props: ActionProps) { ); } -function Text(props: React.HTMLProps) { +interface GutterProps { + children: ReactNode; +} + +function Gutter({ children }: GutterProps) { return ( -

- ); +

+ {children} +
+ ) } interface PanelProps { @@ -42,29 +48,28 @@ function Panel({ children, control, className }: PanelProps) { ); @@ -83,4 +88,11 @@ function Dialog({ children, control }: DialogProps) { return {children}; } -export default Object.assign(Dialog, { Button, Title, Text, Panel, Action }); +export default Object.assign(Dialog, { + Action, + Button, + Gutter, + Panel, + Title, + Text, +}); diff --git a/app/components/IconButton.tsx b/app/components/IconButton.tsx index 29f83f3..a16a88e 100644 --- a/app/components/IconButton.tsx +++ b/app/components/IconButton.tsx @@ -1,17 +1,16 @@ import type { Dispatch, SetStateAction } from 'react'; import React, { useRef } from 'react'; -import { Button as AriaButton } from 'react-aria-components'; -import { useButton } from 'react-aria'; +import { useButton, type AriaButtonOptions } from 'react-aria'; import { cn } from '~/utils/cn'; -interface Props extends React.HTMLProps { - variant?: 'heavy' - isDisabled?: boolean +export interface IconButtonProps extends AriaButtonOptions<'button'> { + variant?: 'heavy' | 'light' + className?: string children: React.ReactNode label: string } -export default function IconButton({ variant = 'light', ...props }: Props) { +export default function IconButton({ variant = 'light', ...props }: IconButtonProps) { const ref = useRef(null); const { buttonProps } = useButton(props, ref); diff --git a/app/components/Text.tsx b/app/components/Text.tsx new file mode 100644 index 0000000..8c600c4 --- /dev/null +++ b/app/components/Text.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { cn } from '~/utils/cn'; + +export interface TextProps { + children: React.ReactNode; + className?: string; +} + +export default function Text({ children, className }: TextProps) { + return ( +

+ {children} +

+ ); +} diff --git a/app/components/Title.tsx b/app/components/Title.tsx index b070c29..157a05a 100644 --- a/app/components/Title.tsx +++ b/app/components/Title.tsx @@ -1,12 +1,14 @@ import React from 'react'; +import { cn } from '~/utils/cn'; export interface TitleProps { children: React.ReactNode; + className?: string; } -export default function Title({ children }: TitleProps) { +export default function Title({ children, className }: TitleProps) { return ( -

+

{children}

); diff --git a/app/routes/machines/components/machine.tsx b/app/routes/machines/components/machine.tsx index f2a73c9..de12084 100644 --- a/app/routes/machines/components/machine.tsx +++ b/app/routes/machines/components/machine.tsx @@ -111,9 +111,12 @@ export default function MachineRow({ machine, routes, magic, users, stats }: Pro
{machine.ipAddresses[0]} - + - + {machine.ipAddresses.map((ip) => ( (); - const routesState = useState(false); + const [showRouting, setShowRouting] = useState(false); useLiveData({ interval: 1000 }); const expired = @@ -201,7 +201,11 @@ export default function Page() {

Subnets & Routing

- +

Subnets let you expose physical network routes onto Tailscale.{' '} @@ -212,7 +216,7 @@ export default function Page() { Learn More

-
@@ -247,13 +251,11 @@ export default function Page() { )} @@ -283,13 +285,11 @@ export default function Page() { )} @@ -322,13 +322,11 @@ export default function Page() { )} diff --git a/app/routes/users/dialogs/remove.tsx b/app/routes/users/dialogs/remove.tsx index 2a33379..0fb2292 100644 --- a/app/routes/users/dialogs/remove.tsx +++ b/app/routes/users/dialogs/remove.tsx @@ -1,8 +1,8 @@ -import { XIcon } from '@primer/octicons-react'; +import { X } from 'lucide-react'; import { Form, useSubmit } from 'react-router'; import { useState } from 'react'; -import Button from '~/components/Button'; +import IconButton from '~/components/IconButton'; import Code from '~/components/Code'; import Dialog from '~/components/Dialog'; @@ -12,19 +12,18 @@ interface Props { export default function Remove({ username }: Props) { const submit = useSubmit(); - const dialogState = useState(false); + const [dialog, setDialog] = useState(false); return ( <> - - - + + + + {(close) => ( <> Delete {username}? diff --git a/app/routes/users/dialogs/rename.tsx b/app/routes/users/dialogs/rename.tsx index a75c0be..d50c813 100644 --- a/app/routes/users/dialogs/rename.tsx +++ b/app/routes/users/dialogs/rename.tsx @@ -1,8 +1,8 @@ -import { PencilIcon } from '@primer/octicons-react'; +import { Pencil } from 'lucide-react'; import { Form, useSubmit } from 'react-router'; import { useState } from 'react'; -import Button from '~/components/Button'; +import IconButton from '~/components/IconButton'; import Dialog from '~/components/Dialog'; import TextField from '~/components/TextField'; @@ -13,20 +13,19 @@ interface Props { export default function Rename({ username, magic }: Props) { const submit = useSubmit(); - const dialogState = useState(false); + const [dialog, setDialog] = useState(false); const [newName, setNewName] = useState(username); return ( <> - - - + + + + {(close) => ( <> Rename {username}?