i need to make the library dialog a datagrid.

This commit is contained in:
Jordan 2024-02-29 11:10:04 -08:00
parent ee266ea372
commit 326f3788fa
12 changed files with 113 additions and 58 deletions

View File

@ -54,11 +54,11 @@ function App() {
const promptItems = [
{
id: uuid4(), items: [
{ id: uuid4(), item: libItems[0] },
{ id: uuid4(), item: libItems[1] },
{ id: uuid4(), item: libItems[0], score: -2 },
{ id: uuid4(), item: libItems[1], score: 1 },
], op: Op.AND,
},
{ id: uuid4(), item: libItems[2] },
{ id: uuid4(), item: libItems[2], score: 0, },
] as Composition;
$library.set(libItems);

View File

@ -10,7 +10,7 @@ export interface StyleProps {
export function LibraryItem(props: StyleProps) {
const { item, onInsertItem } = props
return (
<div>
<div className={`library-item ${item.category}`}>
<Button onClick={() => onInsertItem(item)} aria-label="Add">
<AddCircleOutlineOutlinedIcon/>
</Button>

View File

@ -1,4 +1,4 @@
import { Button, FormControl, InputLabel, MenuItem, TextField } from "@material-ui/core";
import { Button, Container, FormControl, InputLabel, MenuItem, Table, TableRow, TextField } from "@material-ui/core";
import Select, { SelectChangeEvent } from '@mui/material/Select';
import { Category, LibraryItem, addItemToLibrary, categoryHasName } from "../lib/prompt";
import { ChangeEvent, useState } from "react";
@ -46,9 +46,8 @@ export function NewLibraryItem(props: NewLibraryItemProps) {
const catChoices = Object.keys(Category);
return (
<div>
<FormControl onSubmit={handleCreateItem}>
<div>
<Container className="new-item-form">
<FormControl onSubmitCapture={handleCreateItem}>
<InputLabel htmlFor="new-prompt-category">Category</InputLabel>
<Select
native
@ -61,17 +60,14 @@ export function NewLibraryItem(props: NewLibraryItemProps) {
<option value={cat} id={cat} key={cat}>{titleCase(cat)}</option>
))}
</Select>
</div>
<div>
{categoryHasName(category) ? (<InputLabel htmlFor="name">Name</InputLabel>) : <></>}
{categoryHasName(category) ? (<TextField aria-label="Prompt Item Name" value={name} onChange={handleNameChange} id="name" />) : <></>}
</div>
<div>
{categoryHasName(category) && <>
<InputLabel htmlFor="name">Name</InputLabel>
<TextField aria-label="Prompt Item Name" value={name} onChange={handleNameChange} id="name" />
</>}
<InputLabel htmlFor="prompt">Prompt</InputLabel>
<TextField aria-label="Prompt Item Text" value={prompt} onChange={handlePromptChange} id="prompt" />
<Button onClick={handleCreateItem} >Create</Button>
</div>
</FormControl>
</div>
</Container>
)
}

View File

@ -1,13 +1,19 @@
.nugget {
.nugget.toplevel {
border: 1px solid slategray;
border-radius: 10pt;
display: inline-flex;
margin: 10pt;
}
.operation .nugget {
border: 1px solid white;
border-radius: 2pt;
display: inline-flex;
}
.nugget > .text, .nugget > .score, .nugget.buttons {
display: flex;
padding: 4pt;
margin-top: 10pt;
vertical-align: text-bottom;
display: inline-block;
}
.nugget .buttons button {
max-height: 12pt;
}

View File

@ -11,6 +11,7 @@ import { useStore } from '@nanostores/react';
export interface NuggetProps extends PromptItemProps {
nugget: NuggetType,
isTopLevel?: boolean,
}
export default function Nugget(props: NuggetProps) {
@ -22,6 +23,7 @@ export default function Nugget(props: NuggetProps) {
onDrop,
onMouseEnter,
onMouseLeave,
isTopLevel,
} = props;
const scoreDisp = nugget.score > 0 ? "+" + nugget.score : nugget.score;
@ -30,6 +32,8 @@ export default function Nugget(props: NuggetProps) {
const composition = useStore($composition)
const thisId = `prompt-item-${nugget.id}`
const className = isTopLevel ? 'nugget toplevel prompt-item' : 'nugget child prompt-item';
const handleOnDragStart = () => {
onDragStart ? onDragStart(nugget) : null;
}
@ -66,7 +70,7 @@ export default function Nugget(props: NuggetProps) {
return (
<div
className='nugget prompt-item'
className={className}
id={thisId}
draggable
onDragStart={handleOnDragStart}

View File

@ -1,16 +1,29 @@
.operation {
display: inline-block;
border: 1px solid lightgray;
}
.operation .title {
padding: 4pt;
margin: 4pt;
text-align: left;
}
.operation .nuggets {
display: inline-flex;
background-color: #ffdddd;
border: 1px solid coral;
border-style: solid;
border-radius: 10pt;
}
.operation.and .nuggets, .operation.joined .nuggets {
background-color: #b983a3;
border-color: #532e44;
}
.operation.swapped .nuggets, .operation.swap .nuggets {
background-color: #8dacbd;
border-color: #4c6978;
}
.operation.blended .nuggets, .operation.blend .nuggets {
background-color: #a1af86;
border-color: #58663d;
}

View File

@ -92,7 +92,7 @@ function Operation(props: OperationProps) {
onDragOver={handleOnDragOver}
onMouseEnter={handleOnMouseEnter}
onMouseOut={handleOnMouseLeave}
className="operation"
className={`operation ${operation.op} prompt-item`}
onContextMenu={handleContextMenu}
data-promptitem-id={operation.id}
>
@ -100,7 +100,7 @@ function Operation(props: OperationProps) {
<div className="nuggets">
{
operation.items.map(nugget => {
return <Nugget nugget={nugget} />
return <Nugget nugget={nugget} isTopLevel={false} />
})
}
</div>

View File

@ -3,3 +3,9 @@
right: 10pt;
top: 10pt;
}
.prompt-item {
margin: 4pt;
padding: 2pt;
border-radius: 5pt;
}

View File

@ -72,7 +72,7 @@ export default function PromptComposer(props: PromptComposerProps) {
return ("op" in promptItem ?
<Operation operation={promptItem} key={key} {...callbacks} />
: <Nugget nugget={promptItem} key={key} {...callbacks} />)
: <Nugget nugget={promptItem} key={key} isTopLevel={true} {...callbacks} />)
}
return (
@ -90,9 +90,9 @@ export default function PromptComposer(props: PromptComposerProps) {
<div>
{
slottedComposition.map((itemCol, i) => (
<Stack>
<>
{itemCol.map((promptItem, j) => promptItemFactory(promptItem, `item-${j}-${j}`))}
</Stack>
</>
))
}
</div>

View File

@ -1,3 +1,18 @@
.prompt-library-dialog .categories div {
display: inline;
margin: 20pt;
}
.library-item button, .library-item span {
display: inline-block;
vertical-align: sub;
}
.new-item-form {
border: 1px solid blue;
}
.hidden {
display: none;
}

View File

@ -34,7 +34,7 @@ export function PromptLibrary(props: SimpleDialogProps) {
const [doCreate, setDoCreate] = useState(false);
const [visibleCategories, setVisibleCategories] = useState([] as Category[]);
const [visibleCategories, setVisibleCategories] = useState(Object.keys(Category) as Category[]);
const handleOnAddItem = (item: LibItemType) => {
// onAddItem(item);
@ -44,12 +44,22 @@ export function PromptLibrary(props: SimpleDialogProps) {
onInsertItem(item);
}
const filterCat = (catKey: string, v: ChangeEvent<HTMLInputElement>) => {
const isChecked = v.target.value === '1';
setVisibleCategories((visibleCategories.includes(catKey as Category) && !isChecked) ? visibleCategories.filter(c => c != catKey) : [...visibleCategories, catKey as Category]);
document.querySelectorAll(`.category-${catKey}`).forEach($el => {
if (isChecked) show($el)
const filterCat = (catKey: string) => {
document.querySelectorAll(`.library-item`).forEach($el => {
console.log("Found %x", $el);
show($el);
});
if (visibleCategories.includes(catKey as Category)) {
setVisibleCategories(visibleCategories.filter((v) => v !== catKey));
} else {
setVisibleCategories([...visibleCategories, catKey as Category]);
}
console.log(visibleCategories);
document.querySelectorAll(`.library-item`).forEach($el => {
Object.keys(Category).forEach(c => {
if (c in visibleCategories) show($el)
else hide($el)
})
});
}
@ -69,8 +79,8 @@ export function PromptLibrary(props: SimpleDialogProps) {
<div className="categories">
{categoryChoices.map(catKey => {
return (
<div key={catKey}>
<Checkbox onChange={v => filterCat(catKey, v)} />
<div key={catKey} onMouseDown={() => filterCat(catKey)}>
<Checkbox checked={visibleCategories.includes(catKey as Category)} />
<span>{title(catKey)}</span>
</div>
)

View File

@ -6,6 +6,11 @@ import { useStore } from "@nanostores/react";
export function TextPrompt() {
const text = useStore($textComposition);
return (
<TextareaAutosize content={text} className="text-prompt" />
<>
<TextareaAutosize
className="text-prompt"
defaultValue={text}
/>
</>
)
}