Scrollable tables, specify multi-part filename, fix required prop in prompt, better tab padding

This commit is contained in:
Gregory Schier
2025-11-25 08:45:33 -08:00
parent 0cad8f69e2
commit c4ab2965f7
16 changed files with 245 additions and 144 deletions

View File

@@ -69,7 +69,11 @@ export function Dialog({
animate={{ top: 0, scale: 1 }}
className={classNames(
className,
'grid grid-rows-[auto_auto_minmax(0,1fr)]',
'grid',
title != null && description != null && 'grid-rows-[auto_minmax(0,1fr)_minmax_(0,1fr)]',
title == null && description != null && 'grid-rows-[auto_minmax(0,1fr)]',
title != null && description == null && 'grid-rows-[auto_minmax(0,1fr)]',
title == null && description == null && 'grid-rows-[minmax(0,1fr)]',
'grid-cols-1', // must be here for inline code blocks to correctly break words
'relative bg-surface pointer-events-auto',
'rounded-lg',
@@ -83,20 +87,16 @@ export function Dialog({
size === 'dynamic' && 'min-w-[20rem] max-w-[100vw]',
)}
>
{title ? (
{title && (
<Heading className="px-6 mt-4 mb-2" level={1} id={titleId}>
{title}
</Heading>
) : (
<span aria-hidden />
)}
{description ? (
<div className="px-6 text-text-subtle mb-3" id={descriptionId}>
{description && (
<div className="min-h-0 px-6 text-text-subtle mb-3" id={descriptionId}>
{description}
</div>
) : (
<span aria-hidden />
)}
<div

View File

@@ -9,6 +9,7 @@ import {
useSensor,
useSensors,
} from '@dnd-kit/core';
import { basename } from '@tauri-apps/api/path';
import classNames from 'classnames';
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { WrappedEnvironmentVariable } from '../../hooks/useEnvironmentVariables';
@@ -70,6 +71,7 @@ export type Pair = {
name: string;
value: string;
contentType?: string;
filename?: string;
isFile?: boolean;
readOnlyName?: boolean;
};
@@ -492,6 +494,11 @@ export function PairEditorRow({
[onChange, pair],
);
const handleChangeValueFilename = useMemo(
() => (filename: string) => onChange?.({ ...pair, filename }),
[onChange, pair],
);
const handleEditMultiLineValue = useCallback(
() =>
showDialog({
@@ -614,6 +621,7 @@ export function PairEditorRow({
inline
size="xs"
filePath={pair.value}
nameOverride={pair.filename || null}
onChange={handleChangeValueFile}
/>
) : pair.value.includes('\n') ? (
@@ -659,6 +667,7 @@ export function PairEditorRow({
onChangeFile={handleChangeValueFile}
onChangeText={handleChangeValueText}
onChangeContentType={handleChangeValueContentType}
onChangeFilename={handleChangeValueFilename}
onDelete={handleDelete}
editMultiLine={handleEditMultiLineValue}
/>
@@ -687,6 +696,7 @@ function FileActionsDropdown({
onChangeFile,
onChangeText,
onChangeContentType,
onChangeFilename,
onDelete,
editMultiLine,
}: {
@@ -694,6 +704,7 @@ function FileActionsDropdown({
onChangeFile: ({ filePath }: { filePath: string | null }) => void;
onChangeText: (text: string) => void;
onChangeContentType: (contentType: string) => void;
onChangeFilename: (filename: string) => void;
onDelete: () => void;
editMultiLine: () => void;
}) {
@@ -731,6 +742,26 @@ function FileActionsDropdown({
onChangeContentType(contentType);
},
},
{
label: 'Set File Name',
leftSlot: <Icon icon="file_code" />,
onSelect: async () => {
console.log('PAIR', pair);
const defaultFilename = await basename(pair.value ?? '');
const filename = await showPrompt({
id: 'filename',
title: 'Override Filename',
label: 'Filename',
required: false,
placeholder: defaultFilename ?? 'myfile.png',
defaultValue: pair.filename,
confirmText: 'Set',
description: 'Leave blank to use the name of the selected file',
});
if (filename == null) return;
onChangeFilename(filename);
},
},
{
label: 'Unset File',
leftSlot: <Icon icon="x" />,
@@ -747,7 +778,17 @@ function FileActionsDropdown({
color: 'danger',
},
],
[editMultiLine, onChangeContentType, onChangeFile, onDelete, pair.contentType, pair.isFile],
[
editMultiLine,
onChangeContentType,
onChangeFile,
onDelete,
pair.contentType,
pair.isFile,
onChangeFilename,
pair.filename,
pair,
],
);
return (

View File

@@ -1,20 +1,50 @@
import classNames from 'classnames';
import type { ReactNode } from 'react';
export function Table({ children }: { children: ReactNode }) {
export function Table({
children,
className,
scrollable,
}: {
children: ReactNode;
className?: string;
scrollable?: boolean;
}) {
return (
<table className="w-full text-sm mb-auto min-w-full max-w-full divide-y divide-surface-highlight">
{children}
</table>
<div className={classNames('w-full', scrollable && 'h-full overflow-y-auto')}>
<table
className={classNames(
className,
'w-full text-sm mb-auto min-w-full max-w-full',
'border-separate border-spacing-0',
scrollable && '[&_thead]:sticky [&_thead]:top-0 [&_thead]:z-10',
)}
>
{children}
</table>
</div>
);
}
export function TableBody({ children }: { children: ReactNode }) {
return <tbody className="divide-y divide-surface-highlight">{children}</tbody>;
return (
<tbody className="[&>tr:not(:last-child)>td]:border-b [&>tr:not(:last-child)>td]:border-b-surface-highlight">
{children}
</tbody>
);
}
export function TableHead({ children }: { children: ReactNode }) {
return <thead>{children}</thead>;
export function TableHead({ children, className }: { children: ReactNode; className?: string }) {
return (
<thead
className={classNames(
className,
'bg-surface [&_th]:border-b [&_th]:border-b-surface-highlight',
)}
>
{children}
</thead>
);
}
export function TableRow({ children }: { children: ReactNode }) {
@@ -42,9 +72,7 @@ export function TruncatedWideTableCell({
className?: string;
}) {
return (
<TableCell className={classNames(className, 'w-full relative')}>
<div className="absolute inset-0 py-2 truncate">{children}</div>
</TableCell>
<TableCell className={classNames(className, 'truncate max-w-0 w-full')}>{children}</TableCell>
);
}

View File

@@ -87,7 +87,7 @@ export function Tabs({
addBorders && layout === 'horizontal' && 'pl-3 -ml-1',
addBorders && layout === 'vertical' && 'ml-0 mb-2',
'flex items-center hide-scrollbars',
layout === 'horizontal' && 'h-full overflow-auto p-2 -mr-2',
layout === 'horizontal' && 'h-full overflow-auto p-2',
layout === 'vertical' && 'overflow-x-auto overflow-y-visible ',
// Give space for button focus states within overflow boundary.
!addBorders && layout === 'vertical' && 'py-1 pl-3 -ml-5 pr-1',