tags working

This commit is contained in:
caranicas 2022-09-27 13:37:28 -04:00
parent 96ad8c823a
commit e5844c926b
6 changed files with 182 additions and 38 deletions

View File

@ -1,23 +1,54 @@
import React from "react"; import React from "react";
import { useImageCreate } from "../../../stores/imageCreateStore"; import {
ModifierPreview,
useImageCreate
} from "../../../stores/imageCreateStore";
import { API_URL } from "../../../api";
import {
ModifierTagMain,
tagPreview
// @ts-expect-error
} from "./modifierTags.css.ts";
interface ModifierTagProps { interface ModifierTagProps {
name: string; name: string;
category: string;
previews: ModifierPreview[];
} }
export default function ModifierTag({ name }: ModifierTagProps) { export default function ModifierTag({ name, category, previews }: ModifierTagProps) {
const hasTag = useImageCreate((state) => state.hasTag(name))
const previewType: 'portrait' | 'landscape' = "portrait";
const hasTag = useImageCreate((state) => state.hasTag(category, name))
? "selected" ? "selected"
: ""; : "";
const toggleTag = useImageCreate((state) => state.toggleTag); const toggleTag = useImageCreate((state) => state.toggleTag);
const _toggleTag = () => { const _toggleTag = () => {
toggleTag(name); toggleTag(category, name);
}; };
return ( return (
<div className={"modifierTag " + hasTag} onClick={_toggleTag}> <div className={[ModifierTagMain, hasTag].join(" ")} onClick={_toggleTag}>
<p>{name}</p> <p>{name}</p>
<div className={tagPreview}>
{previews.map((preview) => {
if (preview.name !== previewType) {
return null;
}
return (
<img
key={preview.name}
src={`${API_URL}/media/modifier-thumbnails/${preview.path}`}
alt={preview.name}
title={preview.name}
/>
);
})}
</div>
</div> </div>
); );
} }

View File

@ -0,0 +1,43 @@
import { style, globalStyle } from "@vanilla-extract/css";
// .modifierTag.selected {
// background-color: rgb(131, 11, 121);
// }
export const ModifierTagMain = style({
display: "inline-block",
padding: "6px",
backgroundColor: "rgb(38, 77, 141)",
color: "#fff",
borderRadius: "5px",
margin: "5px",
});
// export const ModifierTagSelected = style({
// backgroundColor: "rgb(131, 11, 121)",
// });
globalStyle(`${ModifierTagMain}.selected`, {
backgroundColor: "rgb(131, 11, 121)",
})
globalStyle(`${ModifierTagMain} p`, {
margin: 0,
textAlign: "center",
marginBottom: "2px",
});
export const tagPreview = style({
display: 'flex',
justifyContent: 'center',
});
globalStyle(`${tagPreview} img`, {
width: "90px",
height: "100%",
objectFit: "cover",
objectPosition: "center",
});

View File

@ -5,13 +5,17 @@ import ModifierTag from "../../../../atoms/modifierTag";
export default function ActiveTags() { export default function ActiveTags() {
const selectedtags = useImageCreate((state) => state.selectedTags()); const selectedtags = useImageCreate((state) => state.selectedTags());
console.log("ActiveTags", selectedtags);
return ( return (
<div className="selected-tags"> <div className="selected-tags">
<p>Active Tags</p> <p>Active Tags</p>
<ul> <ul>
{selectedtags.map((tag) => ( {selectedtags.map((tag) => (
<li key={tag}> <li key={tag.modifier}>
<ModifierTag name={tag}></ModifierTag> {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
<ModifierTag category={tag.category!} name={tag.modifier} previews={tag.previews} />
</li> </li>
))} ))}
</ul> </ul>

View File

@ -33,7 +33,7 @@ li {
padding: 0; padding: 0;
} }
.modifierTag { /* .modifierTag {
display: inline-block; display: inline-block;
padding: 6px; padding: 6px;
background-color: rgb(38, 77, 141); background-color: rgb(38, 77, 141);
@ -48,7 +48,7 @@ li {
.modifierTag p { .modifierTag p {
margin: 0; margin: 0;
} } */
input[type="file"] { input[type="file"] {
/* Dont show the file name */ /* Dont show the file name */

View File

@ -10,21 +10,22 @@ import {
ModifierListStyle, //@ts-expect-error ModifierListStyle, //@ts-expect-error
} from "./imageModifiers.css.ts"; } from "./imageModifiers.css.ts";
import { useImageCreate } from "../../../../stores/imageCreateStore"; import { ModifierObject, useImageCreate } from "../../../../stores/imageCreateStore";
import { useCreateUI } from "../creationPanelUIStore"; import { useCreateUI } from "../creationPanelUIStore";
import ModifierTag from "../../../atoms/modifierTag"; import ModifierTag from "../../../atoms/modifierTag";
interface ModifierListProps { interface ModifierListProps {
tags: string[]; category: string;
tags: ModifierObject[];
} }
function ModifierList({ tags }: ModifierListProps) { function ModifierList({ tags, category }: ModifierListProps) {
return ( return (
<ul className={ModifierListStyle}> <ul className={ModifierListStyle}>
{tags.map((tag) => ( {tags.map((tag) => (
<li key={tag}> <li key={tag.modifier}>
<ModifierTag name={tag} /> <ModifierTag category={category} name={tag.modifier} previews={tag.previews} />
</li> </li>
))} ))}
</ul> </ul>
@ -33,10 +34,11 @@ function ModifierList({ tags }: ModifierListProps) {
interface ModifierGroupingProps { interface ModifierGroupingProps {
title: string; title: string;
tags: string[]; category: string;
tags: ModifierObject[];
} }
function ModifierGrouping({ title, tags }: ModifierGroupingProps) { function ModifierGrouping({ title, category, tags }: ModifierGroupingProps) {
// doing this localy for now, but could move to a store // doing this localy for now, but could move to a store
// and persist if we wanted to // and persist if we wanted to
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
@ -45,12 +47,14 @@ function ModifierGrouping({ title, tags }: ModifierGroupingProps) {
setIsExpanded(!isExpanded); setIsExpanded(!isExpanded);
}; };
// console.log("ModifierGrouping", tags);
return ( return (
<div className={ImageModifierGrouping}> <div className={ImageModifierGrouping}>
<button type="button" className={MenuButton} onClick={_toggleExpand}> <button type="button" className={MenuButton} onClick={_toggleExpand}>
<h4>{title}</h4> <h4>{title}</h4>
</button> </button>
{isExpanded && <ModifierList tags={tags} />} {isExpanded && <ModifierList category={category} tags={tags} />}
</div> </div>
); );
} }
@ -81,11 +85,12 @@ export default function ImageModifers() {
{imageModifierIsOpen && ( {imageModifierIsOpen && (
<ul className={ImagerModifierGroups}> <ul className={ImagerModifierGroups}>
{allModifiers.map((item, index) => { {allModifiers.map((item, index) => {
// console.log('mod item ', item);
return ( return (
// @ts-expect-error <li key={item.category}>
<li key={item[0]}> <ModifierGrouping title={item.category} category={item.category} tags={item.modifiers} />
{/* @ts-expect-error */}
<ModifierGrouping title={item[0]} tags={item[1]} />
</li> </li>
); );
})} })}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
import create from "zustand"; import create from "zustand";
import produce from "immer"; import produce from "immer";
import { devtools } from "zustand/middleware"; import { devtools } from "zustand/middleware";
@ -75,15 +76,30 @@ export interface ImageRequest {
stream_image_progress: boolean; stream_image_progress: boolean;
} }
type ModifiersList = string[]; export interface ModifierPreview {
type ModifiersOptions = string | ModifiersList[]; name: string;
type ModifiersOptionList = ModifiersOptions[]; path: string;
}
export interface ModifierObject {
category?: string;
modifier: string;
previews: ModifierPreview[];
}
interface ModifiersList {
category: string;
modifiers: ModifierObject[];
}
type ModifiersOptionList = ModifiersList[];
interface ImageCreateState { interface ImageCreateState {
parallelCount: number; parallelCount: number;
requestOptions: ImageRequest; requestOptions: ImageRequest;
allModifiers: ModifiersOptionList; allModifiers: ModifiersOptionList;
tags: string[]; tags: string[];
tagMap: Record<string, string[]>;
isInpainting: boolean; isInpainting: boolean;
setParallelCount: (count: number) => void; setParallelCount: (count: number) => void;
@ -92,9 +108,9 @@ interface ImageCreateState {
setAllModifiers: (modifiers: ModifiersOptionList) => void; setAllModifiers: (modifiers: ModifiersOptionList) => void;
setModifierOptions: (key: string, value: any) => void; setModifierOptions: (key: string, value: any) => void;
toggleTag: (tag: string) => void; toggleTag: (category: string, tag: string) => void;
hasTag: (tag: string) => boolean; hasTag: (category: string, tag: string) => boolean;
selectedTags: () => string[]; selectedTags: () => ModifierObject[];
builtRequest: () => ImageRequest; builtRequest: () => ImageRequest;
uiOptions: ImageCreationUiOptions; uiOptions: ImageCreationUiOptions;
@ -145,6 +161,9 @@ export const useImageCreate = create<ImageCreateState>(
// selected tags // selected tags
tags: [] as string[], tags: [] as string[],
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
tagMap: {} as Record<string, string[]>,
uiOptions: { uiOptions: {
// TODO proper persistence of all UI / user settings centrally somewhere? // TODO proper persistence of all UI / user settings centrally somewhere?
// localStorage.getItem('ui:advancedSettingsIsOpen') === 'true', // localStorage.getItem('ui:advancedSettingsIsOpen') === 'true',
@ -153,7 +172,7 @@ export const useImageCreate = create<ImageCreateState>(
isSoundEnabled: false, isSoundEnabled: false,
}, },
allModifiers: [[[]]] as ModifiersOptionList, allModifiers: [] as ModifiersOptionList,
isInpainting: false, isInpainting: false,
@ -184,36 +203,78 @@ export const useImageCreate = create<ImageCreateState>(
); );
}, },
toggleTag: (tag: string) => { toggleTag: (category: string, tag: string) => {
set( set(
produce((state) => { produce((state) => {
const index = state.tags.indexOf(tag);
if (index > -1) { if (Object.keys(state.tagMap).includes(category)) {
state.tags.splice(index, 1); if (state.tagMap[category].includes(tag)) {
state.tagMap[category] = state.tagMap[category].filter((t: string) => t !== tag);
} else { } else {
state.tags.push(tag); state.tagMap[category].push(tag);
} }
} else {
state.tagMap[category] = [tag];
}
// const index = state.tags.indexOf(tag);
// if (index > -1) {
// state.tags.splice(index, 1);
// } else {
// state.tags.push(tag);
// }
}) })
); );
}, },
hasTag: (tag: string) => { hasTag: (category: string, tag: string) => {
return get().tags.includes(tag); return get().tagMap[category]?.includes(tag);
}, },
selectedTags: () => { selectedTags: () => {
return get().tags; // get all the modifiers and all the tags
const allModifiers = get().allModifiers;
const selectedTags = get().tagMap;
let selected: ModifierObject[] = [];
// for each mappped tag
for (const [category, tags] of Object.entries(selectedTags)) {
// find the modifier
const modifier = allModifiers.find((m) => m.category === category);
if (modifier) {
// for each tag in the modifier
for (const tag of tags) {
// find the tag
const tagObject = modifier.modifiers.find((m) => m.modifier === tag);
if (tagObject) {
// add the previews to the selected list
selected = selected.concat({
...tagObject,
category: modifier.category
});
}
}
}
}
return selected;
}, },
// the request body to send to the server // the request body to send to the server
// this is a computed value, just adding the tags to the request // this is a computed value, just adding the tags to the request
builtRequest: () => { builtRequest: () => {
const state = get(); const state = get();
const requestOptions = state.requestOptions; const requestOptions = state.requestOptions;
const tags = state.tags; const selectedTags = get().selectedTags();
const tags = selectedTags.map((t: ModifierObject) => t.modifier);
// join all the tags with a comma and add it to the prompt // join all the tags with a comma and add it to the prompt
const prompt = `${requestOptions.prompt} ${tags.join(",")}`; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
const prompt = `${requestOptions.prompt}, ${tags.join(",")}`;
const request = { const request = {
...requestOptions, ...requestOptions,