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 { 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 {
name: string;
category: string;
previews: ModifierPreview[];
}
export default function ModifierTag({ name }: ModifierTagProps) {
const hasTag = useImageCreate((state) => state.hasTag(name))
export default function ModifierTag({ name, category, previews }: ModifierTagProps) {
const previewType: 'portrait' | 'landscape' = "portrait";
const hasTag = useImageCreate((state) => state.hasTag(category, name))
? "selected"
: "";
const toggleTag = useImageCreate((state) => state.toggleTag);
const _toggleTag = () => {
toggleTag(name);
toggleTag(category, name);
};
return (
<div className={"modifierTag " + hasTag} onClick={_toggleTag}>
<div className={[ModifierTagMain, hasTag].join(" ")} onClick={_toggleTag}>
<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>
);
}

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() {
const selectedtags = useImageCreate((state) => state.selectedTags());
console.log("ActiveTags", selectedtags);
return (
<div className="selected-tags">
<p>Active Tags</p>
<ul>
{selectedtags.map((tag) => (
<li key={tag}>
<ModifierTag name={tag}></ModifierTag>
<li key={tag.modifier}>
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
<ModifierTag category={tag.category!} name={tag.modifier} previews={tag.previews} />
</li>
))}
</ul>

View File

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

View File

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

View File

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