Moving the arttags table to tags table part 2

This commit is contained in:
2026-02-02 13:48:49 +01:00
parent 7605ccb0aa
commit ed81662ae5
13 changed files with 195 additions and 245 deletions

View File

@ -171,7 +171,7 @@ export default function ArtworkDetails({
v: (
<div className="flex flex-wrap gap-2 text-xs">
<Badge variant="secondary">{(artwork.categories?.length ?? 0)} categories</Badge>
<Badge variant="secondary">{(artwork.tagsV2?.length ?? 0)} tags</Badge>
<Badge variant="secondary">{(artwork.tags?.length ?? 0)} tags</Badge>
<Badge variant="secondary">{(artwork.colors?.length ?? 0)} colors</Badge>
<Badge variant="secondary">{(artwork.variants?.length ?? 0)} variants</Badge>
</div>

View File

@ -39,7 +39,7 @@ export default function EditArtworkForm({ artwork, categories, tags }:
year: artwork.year || undefined,
creationDate: artwork.creationDate ? new Date(artwork.creationDate) : undefined,
categoryIds: artwork.categories?.map(cat => cat.id) ?? [],
tagIds: artwork.tagsV2?.map(tag => tag.id) ?? [],
tagIds: artwork.tags?.map(tag => tag.id) ?? [],
newCategoryNames: [],
newTagNames: []
}
@ -283,6 +283,12 @@ export default function EditArtworkForm({ artwork, categories, tags }:
.filter((t) => selectedTagIds.includes(t.id))
.map((t) => ({ label: t.name, value: t.id }));
const fallbackSelectedOptions =
artwork.tags
?.filter((t) => selectedTagIds.includes(t.id))
.filter((t) => !selectedExistingOptions.some((o) => o.value === t.id))
.map((t) => ({ label: t.name, value: t.id })) ?? [];
// Selected "new" tags (so they remain visible)
const selectedNewOptions = newTagNames.map((name) => ({
label: `Create: ${name}`,
@ -302,7 +308,11 @@ export default function EditArtworkForm({ artwork, categories, tags }:
placeholder="Select or type to create tags"
hidePlaceholderWhenSelected
selectFirstItem
value={[...selectedExistingOptions, ...selectedNewOptions]}
value={[
...selectedExistingOptions,
...fallbackSelectedOptions,
...selectedNewOptions,
]}
creatable
createOption={(raw) => ({
value: `__new__:${raw}`,

View File

@ -142,15 +142,6 @@ function removePickedOption(groupOption: GroupOption, picked: Option[]) {
return cloneOption;
}
function isOptionsExist(groupOption: GroupOption, targetOption: Option[]) {
for (const [, value] of Object.entries(groupOption)) {
if (value.some((option) => targetOption.find((p) => p.value === option.value))) {
return true;
}
}
return false;
}
function normalizeInput(s: string) {
return s.trim().replace(/\s+/g, " ");
}
@ -238,7 +229,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
[selected],
);
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
const handleClickOutside = React.useCallback((event: MouseEvent | TouchEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
@ -248,7 +239,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
setOpen(false);
inputRef.current.blur();
}
};
}, []);
const handleUnselect = React.useCallback(
(option: Option) => {
@ -294,7 +285,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchend', handleClickOutside);
};
}, [open]);
}, [open, handleClickOutside]);
useEffect(() => {
if (value) {
@ -311,7 +302,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
if (JSON.stringify(newOption) !== JSON.stringify(options)) {
setOptions(newOption);
}
}, [arrayDefaultOptions, arrayOptions, groupBy, onSearch, options]);
}, [arrayOptions, groupBy, onSearch, options]);
useEffect(() => {
/** sync search */
@ -334,8 +325,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
};
void exec();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);
}, [debouncedSearchTerm, groupBy, onSearchSync, open, triggerSearchOnFocus]);
useEffect(() => {
/** async search */
@ -360,8 +350,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
};
void exec();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);
}, [debouncedSearchTerm, groupBy, onSearch, open, triggerSearchOnFocus]);
const CreatableItem = () => {
if (!creatable) return undefined;
@ -448,14 +437,10 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
return commandProps.filter;
}
if (creatable) {
return (value: string, search: string) => {
return value.toLowerCase().includes(search.toLowerCase()) ? 1 : -1;
};
}
// Using default filter in `cmdk`. We don't have to provide it.
return undefined;
}, [creatable, commandProps?.filter]);
return (value: string, search: string) => {
return value.toLowerCase().includes(search.toLowerCase()) ? 1 : -1;
};
}, [commandProps?.filter]);
const orderedGroupEntries = React.useMemo(() => {
const entries = Object.entries(selectables);
@ -495,7 +480,8 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
} // When onSearch is provided, we don't want to filter the options. You can still override it.
filter={commandFilter()}
>
<div
<button
type="button"
className={cn(
'min-h-10 rounded-md border border-input text-base ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 md:text-sm',
{
@ -508,6 +494,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
if (disabled) return;
inputRef?.current?.focus();
}}
disabled={disabled}
>
<div className="relative flex flex-wrap gap-1">
{selected.map((option) => {
@ -594,7 +581,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
<X />
</button>
</div>
</div>
</button>
<div className="relative">
{open && (
<CommandList
@ -626,7 +613,7 @@ const MultipleSelector = React.forwardRef<MultipleSelectorRef, MultipleSelectorP
return (
<CommandItem
key={option.value}
value={option.value}
value={`${option.label}::${option.value}`}
disabled={disabledItem}
onMouseDown={(e) => {
e.preventDefault();