Merge pull request #275 from caranicas/react-base-tag-upgrade

React base Big Update
This commit is contained in:
cmdr2 2022-10-07 19:14:24 +05:30 committed by GitHub
commit e0c0935d3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 2334 additions and 1039 deletions

View File

@ -13,6 +13,7 @@
"@tanstack/react-query": "^4.2.3",
"@tanstack/react-query-devtools": "^4.2.3",
"@vanilla-extract/css": "^1.9.0",
"@vanilla-extract/css-utils": "^0.1.2",
"@vanilla-extract/recipes": "^0.2.5",
"@vanilla-extract/vite-plugin": "^3.5.0",
"i18next": "^21.9.2",
@ -1166,6 +1167,11 @@
"outdent": "^0.8.0"
}
},
"node_modules/@vanilla-extract/css-utils": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@vanilla-extract/css-utils/-/css-utils-0.1.2.tgz",
"integrity": "sha512-qoxIu5E/UhJtoKsPL1JaU9nhTN0Xl5zYV0pScOgsvc3JN46TvTTt0L3GV8x3PQpZP7x3elw8BsC9czYbhJy9Gg=="
},
"node_modules/@vanilla-extract/css/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@ -5733,6 +5739,11 @@
}
}
},
"@vanilla-extract/css-utils": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@vanilla-extract/css-utils/-/css-utils-0.1.2.tgz",
"integrity": "sha512-qoxIu5E/UhJtoKsPL1JaU9nhTN0Xl5zYV0pScOgsvc3JN46TvTTt0L3GV8x3PQpZP7x3elw8BsC9czYbhJy9Gg=="
},
"@vanilla-extract/integration": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@vanilla-extract/integration/-/integration-5.0.1.tgz",

View File

@ -15,6 +15,7 @@
"@tanstack/react-query": "^4.2.3",
"@tanstack/react-query-devtools": "^4.2.3",
"@vanilla-extract/css": "^1.9.0",
"@vanilla-extract/css-utils": "^0.1.2",
"@vanilla-extract/recipes": "^0.2.5",
"@vanilla-extract/vite-plugin": "^3.5.0",
"i18next": "^21.9.2",

View File

@ -1,24 +1,18 @@
import React, { useState } from "react";
import React from "react";
import { ReactLocation, Router } from "@tanstack/react-location";
import Home from "./pages/Home";
import Settings from "./pages/Settings";
import { darkTheme, lightTheme } from "./styles/theme/index.css";
import "./Translation/config";
const location = new ReactLocation();
function App() {
// just check for the theme one 1 time
// var { matches } = window.matchMedia('(prefers-color-scheme: dark)')
const matches = true;
const themeClass = matches ? darkTheme : lightTheme;
return (
<Router
location={location}
routes={[
{ path: "/", element: <Home className={themeClass} /> },
{ path: "/settings", element: <Settings className={themeClass} /> },
{ path: "/", element: <Home /> },
{ path: "/settings", element: <Settings /> },
]}
></Router>
);

View File

@ -60,6 +60,7 @@ export const toggleBetaConfig = async (branch: string) => {
export interface ImageRequest {
session_id: string;
prompt: string;
negative_prompt: string;
seed: number;
num_outputs: number;
num_inference_steps: number;
@ -136,3 +137,10 @@ export const doMakeImage = async (reqBody: ImageRequest) => {
});
return res;
};
export const doStopImage = async () => {
const response = await fetch(`${API_URL}/image/stop`);
const data = await response.json();
return data;
};

View File

@ -0,0 +1,140 @@
// would prefer to use a var here, but it doesn't work
// vars: {
// '--button-base-saturation': vars.colorMod.saturation.normal,
// '--button-base-lightness': vars.colorMod.lightness.normal,
// },
import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
export const buttonStyle = recipe({
base: {
fontSize: vars.fonts.sizes.Subheadline,
fontWeight: "bold",
color: vars.colors.text.normal,
padding: vars.spacing.small,
border: "0",
borderRadius: vars.trim.smallBorderRadius,
},
variants: {
color: {
primary: {
// @ts-expect-error
'--button-hue': vars.brandHue,
'--button-base-saturation': vars.colorMod.saturation.normal,
'--button-base-lightness': vars.colorMod.lightness.normal,
},
secondary: {
// @ts-expect-error
'--button-hue': vars.secondaryHue,
'--button-base-saturation': vars.colorMod.saturation.normal,
'--button-base-lightness': vars.colorMod.lightness.normal,
},
tertiary: {
// @ts-expect-error
'--button-hue': vars.tertiaryHue,
'--button-base-saturation': vars.colorMod.saturation.normal,
'--button-base-lightness': vars.colorMod.lightness.normal,
},
cancel: {
// @ts-expect-error
'--button-hue': vars.errorHue,
'--button-base-saturation': vars.colorMod.saturation.normal,
'--button-base-lightness': vars.colorMod.lightness.normal,
},
accent: {
// @ts-expect-error
'--button-hue': vars.backgroundAccentHue,
'--button-base-saturation': vars.backgroundAccentSaturation,
'--button-base-lightness': vars.backgroundAccentLightness,
},
clear: {
backgroundColor: "transparent",
},
},
type: {
fill: {
backgroundColor: `hsl(var(--button-hue),var(--button-base-saturation),${vars.colorMod.lightness.normal})`,
border: `1px solid hsl(var(--button-hue),var(--button-base-saturation),${vars.colorMod.lightness.normal})`,
":hover": {
backgroundColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.normal})`,
border: `1px solid hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.normal})`,
},
":active": {
backgroundColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
border: `1px solid hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":focus": {
backgroundColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
border: `1px solid hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":disabled": {
backgroundColor: `hsl(var(--button-hue),${vars.colorMod.saturation.dim},${vars.colorMod.lightness.dim})`,
border: `1px solid hsl(var(--button-hue),${vars.colorMod.saturation.dim},${vars.colorMod.lightness.dim})`,
},
},
outline: {
backgroundColor: "transparent",
border: `1px solid hsl(var(--button-hue),var(--button-base-saturation),${vars.colorMod.lightness.normal})`,
":hover": {
borderColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.normal})`,
},
":active": {
borderColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":focus": {
borderColor: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":disabled": {
borderColor: `hsl(var(--button-hue),${vars.colorMod.saturation.dim},${vars.colorMod.lightness.dim})`,
},
},
action: {
backgroundColor: "transparent",
color: `hsl(var(--button-hue),var(--button-base-saturation),${vars.colorMod.lightness.normal})`,
textDecoration: "underline",
":hover": {
color: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.normal})`,
},
":active": {
color: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":focus": {
color: `hsl(var(--button-hue),${vars.colorMod.saturation.bright},${vars.colorMod.lightness.dim})`,
},
":disabled": {
color: `hsl(var(--button-hue),${vars.colorMod.saturation.dim},${vars.colorMod.lightness.dim})`,
},
}
},
size: {
slim: {
padding: vars.spacing.min,
fontSize: vars.fonts.sizes.Caption,
},
large: {
width: "100%",
fontSize: vars.fonts.sizes.Headline,
}
}
},
defaultVariants: {
color: "primary",
type: "fill",
},
});

View File

@ -0,0 +1,51 @@
import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
export const card = recipe({
base: {
color: vars.colors.text.normal,
padding: vars.spacing.medium,
},
variants: {
backing: {
normal: {
background: vars.backgroundMain,
},
light: {
background: vars.backgroundLight,
},
dark: {
background: vars.backgroundDark,
},
},
rounded: {
true: {
borderRadius: vars.trim.smallBorderRadius,
},
},
info: {
true: {
background: vars.backgroundDark,
border: `1px solid ${vars.backgroundAccentMain}`,
},
},
level: {
flat: {},
1: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
2: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
3: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
},
},
defaultVariants: {
backing: "light",
level: 'flat',
rounded: true,
},
});

View File

@ -0,0 +1,24 @@
import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
export const card = recipe({
base: {
background: vars.backgroundMain,
color: vars.colors.text.normal,
padding: vars.spacing.medium,
borderRadius: vars.trim.smallBorderRadius,
},
variants: {
level: {
1: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
2: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
3: { boxShadow: "0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)" },
},
},
defaultVariants: {
level: 1,
},
});

View File

@ -1,7 +1,12 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
// import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
import {
card
} from "./card.css";
export const PopoverMain = style({
position: 'relative'
@ -19,16 +24,16 @@ globalStyle(`${PopoverButtonStyle} > i`, {
marginRight: vars.spacing.small,
});
export const PopoverPanelMain = style({
export const PopoverPanelMain = style([card(
{
backing: 'dark',
level: 2,
}
), {
position: 'absolute',
top: '100%',
right: '0',
zIndex: '1',
background: vars.colors.backgroundDark,
color: vars.colors.text.normal,
padding: vars.spacing.medium,
borderRadius: vars.trim.smallBorderRadius,
marginBottom: vars.spacing.medium,
});
}]);

View File

@ -1,6 +1,7 @@
import { style, } from "@vanilla-extract/css";
//import { vars } from "../../../styles/theme/index.css";
// import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
export const SwitchGroupMain = style({
});

View File

@ -0,0 +1,60 @@
import { style } from '@vanilla-extract/css';
import { recipe } from "@vanilla-extract/recipes";
import { vars } from "../../styles/theme/index.css";
export const tabStyles = recipe({
base: {
background: vars.backgroundMain,
color: vars.colors.text.normal,
padding: vars.spacing.small,
borderRadius: `${vars.trim.smallBorderRadius} ${vars.trim.smallBorderRadius} 0 0`,
border: `1px solid ${vars.backgroundLight}`,
borderBottom: 'none',
marginLeft: vars.spacing.small,
boxShadow: `0px -1px 4px -2px ${vars.backgroundAccentMain} inset`,
width: 'fit-content',
':focus': {
outline: 'none',
},
},
variants: {
selected: {
true: {
background: vars.backgroundLight,
color: vars.colors.text.normal,
boxShadow: `0px -1px 4px -2px ${vars.backgroundDark} inset`,
}
}
}
});
export const tabPanelStyles = recipe({
base: {
color: vars.colors.text.normal,
// borderRadius: `0 0 ${vars.trim.smallBorderRadius} ${vars.trim.smallBorderRadius}`,
background: vars.backgroundLight,
padding: vars.spacing.medium,
flexGrow: 1,
overflow: 'auto',
// "::-webkit-scrollbar": {
// width: "4px",
// },
},
variants: {
backing: {
normal: {
background: vars.backgroundMain,
},
light: {
background: vars.backgroundLight,
},
dark: {
background: vars.backgroundDark,
},
},
},
});

View File

@ -1,53 +0,0 @@
import React from "react";
import {
ModifierPreview,
useImageCreate
} from "../../../stores/imageCreateStore";
import { API_URL } from "../../../api";
import {
ModifierTagMain,
tagPreview
} from "./modifierTags.css";
interface ModifierTagProps {
name: string;
category: string;
previews: ModifierPreview[];
}
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(category, name);
};
return (
<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

@ -1,43 +0,0 @@
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

@ -0,0 +1,34 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
import {
tabPanelStyles,
} from "../../_recipes/tabs_headless.css";
export const TabpanelScrollFlop = style([tabPanelStyles(), {
direction: 'rtl',
// position: 'relative',
overflow: 'overlay',
"::-webkit-scrollbar": {
position: 'absolute',
width: "6px",
backgroundColor: vars.backgroundAccentMain,
},
"::-webkit-scrollbar-thumb": {
backgroundColor: vars.backgroundDark,
borderRadius: "4px",
},
// "::-webkit-scrollbar-button: {
// backgroundColor: vars.backgroundDark,
// }
}]);
globalStyle(`${TabpanelScrollFlop} > *`, {
direction: 'ltr',
});

View File

@ -0,0 +1,61 @@
import React, { Fragment } from "react";
import { Tab } from '@headlessui/react';
import CreationPanel from "../../organisms/creationPanel";
import QueueDisplay from "../../organisms/queueDisplay";
import ProcessingStatus from "../../molecules/queueStatusTab";
import {
tabStyles,
} from "../../_recipes/tabs_headless.css";
import {
TabpanelScrollFlop
} from "./creationTabs.css";
export default function CreationTabs() {
return (
<Tab.Group>
<Tab.List>
<Tab as={Fragment}>
{({ selected }) => (
<button
className={tabStyles({
selected,
})}
>
Create
</button>
)}
</Tab>
<Tab as={Fragment}>
{({ selected }) => (
<button
className={tabStyles({
selected,
})}
>
<ProcessingStatus></ProcessingStatus>
</button>
)}
</Tab>
</Tab.List>
<Tab.Panels className={TabpanelScrollFlop}>
<Tab.Panel>
<CreationPanel></CreationPanel>
</Tab.Panel>
<Tab.Panel>
<QueueDisplay></QueueDisplay>
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
}

View File

@ -0,0 +1,107 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
import {
tabStyles
} from "../../_recipes/tabs_headless.css";
export const basicDisplayLayout = style({
width: "100%",
height: "100%",
display: "grid",
gridTemplateColumns: "1fr 250px",
gridTemplateRows: "1fr 250px",
gridTemplateAreas: `
"content info"
"history history"`,
overflow: "hidden",
selectors: {
'&[data-hide-info]': {
gridTemplateColumns: "1fr",
gridTemplateRows: "1fr 250px",
// gridTemplateAreas: `
// "content"
// "history"`,
},
'&[data-hide-history]': {
gridTemplateColumns: "1fr 250px",
gridTemplateRows: "1fr 0px",
// gridTemplateAreas: `
// "content info"`,
},
'&[data-hide-info][data-hide-history]': {
gridTemplateColumns: "1fr 0px",
gridTemplateRows: "1fr 0px",
// gridTemplateAreas: `
// "content"`,
},
},
// "@media": {
// "screen and (max-width: 800px)": {
// gridTemplateColumns: "1fr",
// gridTemplateRows: "100px 300px 1fr",
// gridTemplateAreas: `
// "header"
// "create"
// "display"
// `,
// },
// },
});
// globalStyle(`${basicDisplayLayout}.hideHistory`, {
// });
export const contentLayout = style({
gridArea: "content",
});
export const infoLayout = style({
gridArea: "info",
position: "relative",
});
export const historyLayout = style({
gridArea: "history",
position: "relative",
});
globalStyle(`${historyLayout} > button`, {
position: "absolute",
top: '-29px',
});
export const displayContainer = style({
flexGrow: 1,
overflow: 'auto',
display: "flex",
});
export const displayData = style({
width: '250px',
height: '100%',
backgroundColor: 'rebeccapurple',
position: 'relative',
});
export const DataTab = style([tabStyles(), {
position: 'absolute',
top: '0',
left: '0',
// pretty sure this is a magic number
transformOrigin: '37% 275%',
transform: 'rotate(-90deg)',
}]);
// export const previousImages = style({
// minHeight: '250px',
// });

View File

@ -0,0 +1,65 @@
import React, { useState, useRef, useEffect } from "react";
import { Transition } from '@headlessui/react'
import CurrentDisplay from "../../organisms/currentDisplay";
import CompletedImages from "../../organisms/completedImages";
import CurrentInfo from "../../organisms/currentInfo";
import {
tabStyles
} from "../../_recipes/tabs_headless.css";
import {
basicDisplayLayout,
contentLayout,
infoLayout,
historyLayout
} from "./basicDisplay.css";
export default function BasicDisplay() {
const [isShowingHistory, setIsShowingHistory] = useState(true)
const layoutRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (layoutRef.current != undefined) {
// set the hide-history data attribute
if (isShowingHistory) {
layoutRef.current.removeAttribute('data-hide-history');
}
else {
// layoutRef.current.dataset.hideHistory = "true";
layoutRef.current.setAttribute('data-hide-history', '');
}
}
}, [layoutRef, isShowingHistory]);
return (
<div
ref={layoutRef}
className={basicDisplayLayout}
>
<div className={contentLayout}>
<CurrentDisplay></CurrentDisplay>
</div>
{/* <div className={infoLayout}>
<CurrentInfo ></CurrentInfo>
</div> */}
<div className={historyLayout}>
<button
className={tabStyles({})}
onClick={() => setIsShowingHistory((isShowingHistory) => !isShowingHistory)}>
{isShowingHistory ? "Hide History" : "Show History"}
</button>
<CompletedImages></CompletedImages>
</div>
</div>
);
}

View File

@ -0,0 +1,35 @@
import React from "react";
import { doStopImage } from "../../../api";
import { useRequestQueue } from "../../../stores/requestQueueStore";
import {
buttonStyle
} from "../../_recipes/button.css";
export default function ClearQueue() {
const hasQueue = useRequestQueue((state) => state.hasAnyQueue());
const clearQueue = useRequestQueue((state) => state.clearQueue);
const stopAll = async () => {
try {
clearQueue();
const res = await doStopImage();
} catch (e) {
console.log(e);
}
};
return (
<button className={buttonStyle(
{
color: "cancel",
size: "large",
}
)}
disabled={!hasQueue} onClick={() => void stopAll()}>
STOP ALL
</button>
);
}

View File

@ -1,31 +1,37 @@
/* eslint-disable @typescript-eslint/naming-convention */
import React, { useEffect, useRef } from "react";
import { useImageCreate } from "../../../../../stores/imageCreateStore";
import { useImageQueue } from "../../../../../stores/imageQueueStore";
import { useImageCreate } from "../../../stores/imageCreateStore";
import {
QueueStatus,
useRequestQueue
} from "../../../stores/requestQueueStore";
import {
FetchingStates,
useImageFetching
} from "../../../../../stores/imageFetchingStore";
} from "../../../stores/imageFetchingStore";
import { useImageDisplay } from "../../../../../stores/imageDisplayStore";
import { useImageDisplay } from "../../../stores/imageDisplayStore";
import { v4 as uuidv4 } from "uuid";
import { useRandomSeed } from "../../../../../utils";
import { useRandomSeed } from "../../../utils";
import {
ImageRequest,
ImageReturnType,
ImageOutput,
doMakeImage,
} from "../../../../../api";
} from "../../../api";
import {
MakeButtonStyle,
} from "./makeButton.css";
buttonStyle
} from "../../_recipes/button.css";
import { useTranslation } from "react-i18next";
import AudioDing from "../../../../molecules/audioDing";
import AudioDing from "../../molecules/audioDing";
const idDelim = "_batch";
@ -39,10 +45,12 @@ export default function MakeButton() {
const isRandomSeed = useImageCreate((state) => state.isRandomSeed());
const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const addNewImage = useImageQueue((state) => state.addNewImage);
const hasQueue = useImageQueue((state) => state.hasQueuedImages());
const removeFirstInQueue = useImageQueue((state) => state.removeFirstInQueue);
const { id, options } = useImageQueue((state) => state.firstInQueue());
const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled());
const addtoQueue = useRequestQueue((state) => state.addtoQueue);
const hasQueue = useRequestQueue((state) => state.hasPendingQueue());
const { id, options } = useRequestQueue((state) => state.firstInQueue());
const updateQueueStatus = useRequestQueue((state) => state.updateStatus);
const status = useImageFetching((state) => state.status);
const setStatus = useImageFetching((state) => state.setStatus);
@ -59,10 +67,13 @@ export default function MakeButton() {
const hackJson = (jsonStr: string, id: string) => {
try {
const parsed = JSON.parse(jsonStr);
const { status, request, output: outputs } = parsed as ImageReturnType;
if (status === 'succeeded') {
updateQueueStatus(id, QueueStatus.complete);
outputs.forEach((output: any, index: number) => {
const { data, seed } = output as ImageOutput;
@ -77,11 +88,13 @@ export default function MakeButton() {
else {
console.warn(`Unexpected status: ${status}`);
updateQueueStatus(id, QueueStatus.error);
}
}
catch (e) {
console.log("Error HACKING JSON: ", e)
updateQueueStatus(id, QueueStatus.error);
console.warn("Error HACKING JSON: ", e)
}
}
@ -93,10 +106,11 @@ export default function MakeButton() {
const { done, value } = await reader.read();
const jsonStr = decoder.decode(value);
if (done) {
removeFirstInQueue();
setStatus(FetchingStates.COMPLETE);
hackJson(finalJSON, id);
void dingRef.current?.play();
if (isSoundEnabled) {
void dingRef.current?.play();
}
break;
}
@ -129,18 +143,17 @@ export default function MakeButton() {
// TODO this should be the the new out instead of the try catch
// wait for the path to come back instead of the data
setStatus(FetchingStates.SUCCEEDED);
console.log(update);
}
else if (status === 'failed') {
console.warn('failed');
console.log(update);
console.warn(update);
}
else {
console.log("UNKNOWN ?", update);
console.warn("UNKNOWN ?", update);
}
}
catch (e) {
console.log('EXPECTED PARSE ERRROR')
// console.log('EXPECTED PARSE ERRROR')
finalJSON += jsonStr;
}
@ -149,8 +162,8 @@ export default function MakeButton() {
const startStream = async (id: string, req: ImageRequest) => {
try {
updateQueueStatus(id, QueueStatus.processing);
resetForFetching();
const res = await doMakeImage(req);
const reader = res.body?.getReader();
@ -161,12 +174,13 @@ export default function MakeButton() {
} catch (e) {
console.log('TOP LINE STREAM ERROR')
updateQueueStatus(id, QueueStatus.error);
console.log(e);
}
}
const queueImageRequest = async (req: ImageRequest) => {
const queueImageRequest = (req: ImageRequest) => {
// the actual number of request we will make
const requests = [];
// the number of images we will make
@ -198,7 +212,7 @@ export default function MakeButton() {
seed = useRandomSeed();
}
// add the request to the queue
addNewImage(uuidv4(), {
addtoQueue(uuidv4(), {
...req,
// updated the number of images to make
num_outputs: num,
@ -216,12 +230,12 @@ export default function MakeButton() {
}
// the request that we have built
const req = builtRequest();
await queueImageRequest(req);
queueImageRequest(req);
};
useEffect(() => {
const makeImages = async (options: ImageRequest) => {
// potentially update the seed
// removeFirstInQueue();
await startStream(id ?? "", options);
}
@ -235,6 +249,7 @@ export default function MakeButton() {
console.log('req is undefined');
return;
}
makeImages(options).catch((e) => {
console.log('HAS QUEUE ERROR');
console.log(e);
@ -246,11 +261,12 @@ export default function MakeButton() {
return (
<>
<button
className={MakeButtonStyle}
className={buttonStyle({
size: "large",
})}
onClick={() => {
void makeImageQueue();
}}
disabled={hasQueue}
>
{t("home.make-img-btn")}
</button>

View File

@ -0,0 +1,93 @@
import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import {
ModifierPreview,
useImageCreate
} from "../../../stores/imageCreateStore";
import { API_URL } from "../../../api";
import {
IconFont,
} from "../../../styles/shared.css";
import {
ModifierTagMain,
ModifierActions,
tagPreview,
TagText,
TagToggle,
} from "./modifierTags.css";
interface ModifierTagProps {
name: string;
category: string;
previews: ModifierPreview[];
}
export default function ModifierTag({ name, category, previews }: ModifierTagProps) {
const previewType: 'portrait' | 'landscape' = "portrait";
const [showActions, setShowActions] = useState(false);
const handleHover = () => {
setShowActions(true);
};
const handleLeave = () => {
setShowActions(false);
};
const addCreateTag = useImageCreate((state) => state.addCreateTag);
const setPositivePrompt = () => {
addCreateTag({ id: uuidv4(), name, type: 'positive' });
}
const setNegativePrompt = () => {
addCreateTag({ id: uuidv4(), name, type: 'negative' });
}
const hasTag = useImageCreate((state) => state.hasTag(category, name))
? "selected"
: "";
const toggleTag = useImageCreate((state) => state.toggleTag);
const _toggleTag = () => {
toggleTag(category, name);
};
// , hasTag].join(" ")
return (
<div className={ModifierTagMain}
onMouseEnter={handleHover}
onMouseLeave={handleLeave}>
<p className={!showActions ? TagText : TagToggle}>{name}</p>
{showActions && (
<div className={ModifierActions}>
<button onClick={setPositivePrompt}>
<i className={[IconFont, 'fa-solid', 'fa-plus'].join(" ")}></i>
</button>
<button onClick={setNegativePrompt}>
<i className={[IconFont, 'fa-solid', 'fa-minus'].join(" ")}></i>
</button>
</div>
)}
{/* <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,69 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from '../../../styles/theme/index.css';
import { card } from '../../_recipes/card.css';
export const ModifierTagMain = style([
card({
backing: 'normal',
level: 1,
info: true
}), {
position: "relative",
width: "fit-content",
borderColor: `hsl(${vars.brandHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
padding: vars.spacing.small,
}
]);
globalStyle(`${ModifierTagMain}.selected`, {
backgroundColor: "rgb(131, 11, 121)",
})
globalStyle(`${ModifierTagMain} p`, {
margin: 0,
textAlign: "center",
marginBottom: "2px",
});
export const TagText = style({
opacity: 1,
});
export const TagToggle = style({
opacity: 0.3,
});
export const ModifierActions = style({
position: "absolute",
top: "0",
left: "0",
height: "100%",
width: "100%",
display: "flex",
flexDirection: "row",
});
globalStyle(`${ModifierActions} button`, {
flexGrow: 1,
backgroundColor: "transparent",
border: "none",
boxShadow: `inset 0 0 24px 0px rgb(255 255 255 / 50%)`,
borderRadius: "5px",
padding: "0",
});
export const tagPreview = style({
display: 'flex',
justifyContent: 'center',
});
globalStyle(`${tagPreview} img`, {
width: "90px",
height: "100%",
objectFit: "cover",
objectPosition: "center",
});

View File

@ -0,0 +1,68 @@
import React, { useState } from "react";
import { useImageCreate } from "../../../stores/imageCreateStore";
import {
IconFont,
} from "../../../styles/shared.css";
import {
PromptTagMain,
TagToggle,
TagRemoveButton,
PromptTagText,
PromptTagToggle
} from "./promptTag.css";
interface PromptTagProps {
id: string;
name: string;
category?: string;
previews?: string[];
type: string;
};
export default function PromptTag({ id, name, category, previews, type }: PromptTagProps) {
const [showToggle, setShowToggle] = useState(false);
const removeCreateTag = useImageCreate((state) => state.removeCreateTag);
const changeCreateTagType = useImageCreate((state) => state.changeCreateTagType);
const handleHover = () => {
setShowToggle(true);
};
const handleLeave = () => {
setShowToggle(false);
};
const toggleType = () => {
if (type === 'positive') {
changeCreateTagType(id, 'negative');
}
else {
changeCreateTagType(id, 'positive');
}
};
const handleRemove = () => {
console.log('remove');
removeCreateTag(id);
};
return (
<div
onMouseEnter={handleHover}
onMouseLeave={handleLeave}
className={[PromptTagMain, type].join(' ')}>
<p className={!showToggle ? PromptTagText : PromptTagToggle}>{name}</p>
{showToggle && <button className={TagToggle} onClick={toggleType}>
{type === 'positive' ? <i className={[IconFont, 'fa-solid', 'fa-minus'].join(" ")}></i> : <i className={[IconFont, 'fa-solid', 'fa-plus'].join(" ")}></i>}
</button>}
{showToggle && <button className={TagRemoveButton} onClick={handleRemove}>
<i className={[IconFont, 'fa-solid', 'fa-close'].join(" ")}></i>
</button>}
</div>
);
};

View File

@ -0,0 +1,55 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { style, globalStyle } from '@vanilla-extract/css';
import { XButton } from "../../../styles/shared.css";
import { vars } from '../../../styles/theme/index.css';
import { card } from '../../_recipes/card.css';
export const PromptTagMain = style([
card({
backing: 'normal',
level: 1,
info: true
}), {
position: "relative",
width: "fit-content",
backgroundColor: `hsl(${vars.backgroundLight}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
padding: vars.spacing.small,
}
]);
export const PromptTagText = style({
opacity: 1,
fontSize: vars.fonts.sizes.Plain,
});
export const PromptTagToggle = style({
opacity: 0.3,
fontSize: vars.fonts.sizes.Plain,
});
globalStyle(`${PromptTagMain}.positive`, {
borderColor: `hsl(${vars.brandHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
globalStyle(`${PromptTagMain}.negative`, {
borderColor: `hsl(${vars.errorHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
export const TagToggle = style({
position: "absolute",
top: "0",
right: "0",
height: "100%",
width: "100%",
border: "none",
backgroundColor: "transparent",
boxShadow: `inset 0 0 24px 0px rgb(255 255 255 / 50%)`,
});
export const TagRemoveButton = style([XButton, {
top: '-4px',
left: '4px',
padding: '0',
}]);

View File

@ -0,0 +1,70 @@
import React, { useEffect, useState } from "react";
import { FetchingStates, useImageFetching } from "../../../stores/imageFetchingStore";
import { useRequestQueue } from "../../../stores/requestQueueStore";
export default function QueueStatusTab() {
const [showBasicQueue, setShowBasicQueue] = useState(true);
const hasPendingQueue = useRequestQueue((state) => state.hasPendingQueue());
const pendingRequests = useRequestQueue((state) => state.pendingRequests());
const status = useImageFetching((state) => state.status);
const step = useImageFetching((state) => state.step);
const totalSteps = useImageFetching((state) => state.totalSteps);
const startTime = useImageFetching((state) => state.timeStarted);
const timeNow = useImageFetching((state) => state.timeNow);
const [timeRemaining, setTimeRemaining] = useState(0);
const [percent, setPercent] = useState(0);
useEffect(() => {
if (totalSteps > 0) {
setPercent(Math.round((step / totalSteps) * 100));
} else {
setPercent(0);
}
}, [step, totalSteps]);
useEffect(() => {
// find the remaining time
const timeTaken = +timeNow - +startTime;
const timePerStep = step == 0 ? 0 : timeTaken / step;
const totalTime = timePerStep * totalSteps;
const timeRemaining = (totalTime - timeTaken) / 1000;
// @ts-expect-error
setTimeRemaining(timeRemaining.toPrecision(3));
}, [step, totalSteps, startTime, timeNow, setTimeRemaining]);
useEffect(() => {
if (hasPendingQueue) {
setShowBasicQueue(false);
}
}, [status, hasPendingQueue]);
// {/* {showBasicQueue
// ? <> */}
// Queue
// {/* </>
// : <>
// <span>Percent: {percent}%</span>
// </>npm
// } */}
return (
<>
<span>Queue </span>
{hasPendingQueue && <span> Items Remaining: {pendingRequests.length} </span>}
</>
)
}

View File

@ -0,0 +1,25 @@
import React from "react";
import { doStopImage } from "../../../api";
import {
buttonStyle
} from "../../_recipes/button.css";
export default function StopButton() {
const stopMake = async () => {
try {
const res = await doStopImage();
} catch (e) {
console.log(e);
}
};
return <button className={buttonStyle(
{
color: "cancel",
size: "large",
}
)} onClick={() => void stopMake()}>Stop</button>;
}

View File

@ -1,13 +1,26 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../../styles/theme/index.css";
import { vars } from "../../../styles/theme/index.css";
import {
card as cardStyle,
} from '../../_recipes/card.css'
export const completedImagesMain = style({
height: "100%",
position: "relative",
});
// globalStyle(`${completedImagesMain} > button`, {
// position: "absolute",
// top: '-29px',
// });
export const completedImagesContent = style([cardStyle(), {
height: "250px",
width: "100%",
display: "flex",
paddingBottom: vars.spacing.medium,
});
padding: vars.spacing.medium,
borderRadius: 0,
}]);
export const completedImagesList = style({
display: "flex",
@ -19,15 +32,15 @@ export const completedImagesList = style({
paddingLeft: vars.spacing.none,
});
globalStyle(`${completedImagesMain} li`, {
globalStyle(`${completedImagesContent} li`, {
position: "relative",
});
globalStyle(`${completedImagesMain} > li:first-of-type`, {
globalStyle(`${completedImagesContent} > li:first-of-type`, {
marginLeft: vars.spacing.medium,
});
globalStyle(`${completedImagesMain} > li:last-of-type`, {
globalStyle(`${completedImagesContent} > li:last-of-type`, {
marginRight: 0,
});
@ -48,12 +61,3 @@ globalStyle(`${imageContain} img`, {
width: "100%",
objectFit: "contain",
});
export const RemoveButton = style({
marginLeft: vars.spacing.small,
backgroundColor: vars.colors.brand,
border: "0 none",
padding: vars.spacing.small,
cursor: "pointer",
borderRadius: vars.trim.smallBorderRadius,
});

View File

@ -0,0 +1,87 @@
import React, { useState } from "react";
import { useImageDisplay } from "../../../stores/imageDisplayStore";
import {
completedImagesMain,
completedImagesContent,
completedImagesList,
imageContain,
} from "./completedImages.css";
import {
buttonStyle
} from "../../_recipes/button.css";
// import { Transition } from '@headlessui/react'
// import {
// tabStyles
// } from "../../_recipes/tabs_headless.css";
export default function CompletedImages(
) {
const [isShowing, setIsShowing] = useState(false)
const images = useImageDisplay((state) => state.images);
const setCurrentImage = useImageDisplay((state) => state.setCurrentImage);
const clearDisplay = useImageDisplay((state) => state.clearDisplay);
const removeImagesAll = () => {
clearDisplay();
};
return (
<div className={completedImagesMain}>
{/* <button
className={tabStyles({})}
onClick={() => setIsShowing((isShowing) => !isShowing)}>
{isShowing ? "Hide History" : "Show History"}
</button> */}
{/* <Transition
show={isShowing}
> */}
<div className={completedImagesContent}>
{/* Adjust the dom do we dont do this check twice */}
{images != null && images.length > 0 && (
<button
className={buttonStyle()}
onClick={() => {
removeImagesAll();
}}
>
REMOVE ALL
</button>
)}
<ul className={completedImagesList}>
{images?.map((image, index) => {
if (void 0 === image) {
console.warn(`image ${index} is undefined`);
return null;
}
return (
<li key={image.id}>
<button
className={imageContain}
onClick={() => {
setCurrentImage(image);
}}
>
<img src={image.data} alt={image.info.prompt} />
</button>
</li>
);
})}
</ul>
</div>
{/* </Transition> */}
</div>
);
}

View File

@ -2,12 +2,11 @@ import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../../styles/theme/index.css";
export const AdvancedSettingsList = style({
paddingLeft: 0,
listStyleType: "none",
});
export const AdvancedSettingGrouping = style({
marginTop: vars.spacing.medium,
marginTop: vars.spacing.small,
});

View File

@ -5,9 +5,12 @@ import { useCreateUI } from "../../creationPanelUIStore";
import {
SettingItem,
MenuButton,
} from "../../../../../styles/shared.css";
import {
buttonStyle,
} from "../../../../_recipes/button.css";
import { useTranslation } from "react-i18next";
export default function ImprovementSettings() {
@ -57,10 +60,13 @@ export default function ImprovementSettings() {
<div>
<button
type="button"
className={MenuButton}
className={buttonStyle({
type: 'action',
color: 'accent',
})}
onClick={toggleImprovementOpen}
>
<h4>Improvement Settings</h4>
Improvement Settings
</button>
{improvementOpen && (
<>

View File

@ -1,7 +1,15 @@
import React, { useEffect } from "react";
import { useCreateUI } from "../creationPanelUIStore";
import { PanelBox } from "../../../../styles/shared.css";
import {
card
} from '../../../_recipes/card.css';
import {
buttonStyle,
} from "../../../_recipes/button.css";
import {
AdvancedSettingsList,
@ -38,15 +46,24 @@ export default function AdvancedSettings() {
);
return (
<div className={PanelBox}>
<div className={card(
{
level: 1,
backing: 'normal'
}
)}>
<button
type="button"
onClick={toggleAdvancedSettingsIsOpen}
className="panel-box-toggle-btn"
className={buttonStyle({
type: 'action',
color: 'secondary',
size: 'large'
})}
>
<h3>Advanced Settings</h3>
Advanced Settings
</button>
{advancedSettingsIsOpen && <SettingsList />}
</div>
</div >
);
}

View File

@ -4,10 +4,14 @@ import { useCreateUI } from "../../creationPanelUIStore";
import {
SettingItem,
MenuButton
} from "../../../../../styles/shared.css";
import {
buttonStyle,
} from "../../../../_recipes/button.css";
import { useTranslation } from "react-i18next";
@ -71,8 +75,11 @@ export default function PropertySettings() {
return (
<div>
<button type="button" className={MenuButton} onClick={togglePropertyOpen}>
<h4>Property Settings</h4>
<button type="button" className={buttonStyle({
type: 'action',
color: 'accent',
})} onClick={togglePropertyOpen}>
Property Settings
</button>
{propertyOpen && (
<>

View File

@ -5,9 +5,11 @@ import { useCreateUI } from "../../creationPanelUIStore";
import {
SettingItem,
MenuButton,
} from "../../../../../styles/shared.css";
import {
buttonStyle,
} from "../../../../_recipes/button.css";
import { useTranslation } from "react-i18next";
@ -30,8 +32,11 @@ export default function WorkflowSettings() {
return (
<div>
<button type="button" className={MenuButton} onClick={toggleWorkflowOpen}>
<h4>Workflow Settings</h4>
<button type="button" className={buttonStyle({
type: 'action',
color: 'accent',
})} onClick={toggleWorkflowOpen}>
Workflow Settings
</button>
{workflowOpen && (
<>

View File

@ -1,22 +0,0 @@
import React from "react";
import { useImageCreate } from "../../../../../stores/imageCreateStore";
import ModifierTag from "../../../../atoms/modifierTag";
export default function ActiveTags() {
const selectedtags = useImageCreate((state) => state.selectedTags());
return (
<div className="selected-tags">
<p>Active Tags</p>
<ul>
{selectedtags.map((tag) => (
<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>
</div>
);
}

View File

@ -1,24 +1,20 @@
import { style, globalStyle } from "@vanilla-extract/css";
export const CreationBasicMain = style({
position: "relative",
width: "100%",
});
import { card } from "../../../_recipes/card.css";
globalStyle(`${CreationBasicMain} > *`, {
marginBottom: "10px",
});
export const CreationBasicMain = style([
card({
backing: 'normal',
level: 1
}), {
position: "relative",
width: "100%",
}]
);
export const PromptDisplay = style({});
globalStyle(`${PromptDisplay} > p`, {
fontSize: "1.5em",
fontWeight: "bold",
marginBottom: "10px",
});
globalStyle(`${PromptDisplay} > textarea`, {
width: "100%",
resize: "vertical",
height: "100px",
globalStyle(`${CreationBasicMain} > *`, {
marginBottom: '10px'
});

View File

@ -6,9 +6,12 @@ import {
PromptDisplay,
} from "./basicCreation.css";
import MakeButton from "../../../molecules/makeButton";
import PromptCreator from "./promptCreator";
// import CreationActions from "./creationActions";
import SeedImage from "./seedImage";
import ActiveTags from "./activeTags";
import MakeButton from "./makeButton";
import ActiveTags from "./promptCreator/activeTags";
import { useTranslation } from "react-i18next";
@ -26,15 +29,9 @@ export default function BasicCreation() {
return (
<div className={CreationBasicMain}>
<div className={PromptDisplay}>
<p>{t("home.editor-title")}</p>
<textarea value={promptText} onChange={handlePromptChange}></textarea>
</div>
<MakeButton></MakeButton>
<PromptCreator></PromptCreator>
<SeedImage></SeedImage>
<ActiveTags></ActiveTags>
</div>
);
}

View File

@ -1,10 +0,0 @@
import { style } from "@vanilla-extract/css";
import { vars } from "../../../../../styles/theme/index.css";
import { BrandedButton } from "../../../../../styles/shared.css";
export const MakeButtonStyle = style([BrandedButton, {
width: "100%",
fontSize: vars.fonts.sizes.Headline,
}]);

View File

@ -0,0 +1,18 @@
import { style } from '@vanilla-extract/css';
import { vars } from '../../../../../../styles/theme/index.css';
export const ActiveTagListMain = style({
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
gap: '10px',
width: '100%',
height: '100%',
overflow: 'visible',
scrollbarWidth: 'none',
msOverflowStyle: 'none',
'::-webkit-scrollbar': {
display: 'none',
},
});

View File

@ -0,0 +1,39 @@
import React from "react";
import { useImageCreate } from "../../../../../../stores/imageCreateStore";
import ModifierTag from "../../../../../molecules/modifierTag";
// import {
// card
// } from '../../../../../_recipes/card.css';
import PromptTag from "../../../../../molecules/promptTag";
import {
ActiveTagListMain
} from "./activeTags.css";
export default function ActiveTags() {
const selectedtags = useImageCreate((state) => state.selectedTags());
const createTags = useImageCreate((state) => state.createTags);
return (
<div>
<ul className={ActiveTagListMain}>
{createTags.map((tag) => {
console.log(tag);
return (
<li key={tag.id}>
{/* @ts-expect-error */}
<PromptTag id={tag.id} name={tag.name} category={tag?.category} previews={tag?.previews} type={tag.type} />
</li>)
}
)}
</ul>
</div>
);
}

View File

@ -0,0 +1,108 @@
import React, { useState, ChangeEvent, KeyboardEventHandler, Fragment } from "react";
import { v4 as uuidv4 } from "uuid";
import { Switch } from '@headlessui/react'
import { useImageCreate } from "../../../../../stores/imageCreateStore";
import ActiveTags from "./activeTags";
import {
IconFont,
} from "../../../../../styles/shared.css";
import {
buttonStyle,
} from "../../../../_recipes/button.css";
import {
PromptCreatorMain,
ToggleGroupMain,
ToggleMain,
ToggleLabel,
ToggleEnabled,
TogglePill,
buttonRow,
} from "./promptCreator.css";
import { useTranslation } from "react-i18next";
import { type } from "os";
interface TagTypeProps {
positive: boolean;
setPositive: (positive: boolean) => void;
};
function TagTypeToggle({ positive, setPositive }: TagTypeProps) {
return (
<Switch.Group as={Fragment}>
<div className={ToggleGroupMain}>
<Switch.Label> Type </Switch.Label>
<Switch className={ToggleMain} checked={positive} onChange={setPositive}>
<span
className={TogglePill}
>
{positive
? <i className={[IconFont, 'fa-solid', 'fa-plus'].join(" ")}></i>
: <i className={[IconFont, 'fa-solid', 'fa-minus'].join(" ")}></i>}
</span>
</Switch>
</div>
</Switch.Group>
);
}
export default function PromptCreator() {
const [positive, setPositive] = useState(true)
const [tagText, setTagText] = useState('An astronaut riding a horse');
const addCreateTag = useImageCreate((state) => state.addCreateTag);
const { t } = useTranslation();
const checkForEnter = (event: KeyboardEventHandler<HTMLInputElement>) => {
// @ts-expect-error
if (event.key === "Enter") {
if (tagText !== '') {
const type = positive ? "positive" : "negative";
tagText.split(',').map((tag) => tag.trim()).forEach((tag) => {
addCreateTag({ id: uuidv4(), name: tag, type });
});
//debugger;
setTagText('');
}
}
};
return (
<div className={PromptCreatorMain}>
<div>
<p>{t("home.editor-title")}</p>
{/* @ts-expect-error */}
<input value={tagText} onKeyDown={checkForEnter} onChange={(event) => {
setTagText(event.target.value)
}}></input>
</div>
<div className={buttonRow}>
<button
className={buttonStyle(
{
size: 'slim'
}
)}
onClick={() => {
}}
>
Add Prompt
</button>
<TagTypeToggle positive={positive} setPositive={setPositive}></TagTypeToggle>
</div>
<ActiveTags></ActiveTags>
</div >
);
}

View File

@ -0,0 +1,79 @@
import { style, globalStyle } from '@vanilla-extract/css';
import { vars } from "../../../../../styles/theme/index.css";
export const PromptCreatorMain = style({
display: 'flex',
flexDirection: 'column',
width: '100%',
height: '100%',
marginBottom: 0,
});
globalStyle(`${PromptCreatorMain} input`, {
width: '100%',
});
globalStyle(`${PromptCreatorMain} > div`, {
marginBottom: vars.spacing.small,
});
export const ToggleGroupMain = style({
// '--toggle-size': '30px',
});
export const ToggleMain = style({
background: vars.backgroundDark,
height: '22px',
borderRadius: '15px',
width: '34px',
border: 0,
position: 'relative',
display: 'inline-flex',
padding: 0,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
boxShadow: `0 0 2px 0 ${vars.backgroundDark}`,
});
export const ToggleLabel = style({
});
export const ToggleEnabled = style({
});
globalStyle(`${ToggleMain}[data-headlessui-state="checked"]`, {
background: vars.backgroundLight,
});
export const TogglePill = style({
display: 'inline-flex',
height: '18px',
width: '30px',
borderRadius: '15px',
background: vars.backgroundDark,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
});
globalStyle(`${ToggleMain}[data-headlessui-state="checked"] ${TogglePill}`, {
background: vars.backgroundAccentMain,
});
globalStyle(`${TogglePill} p`, {
color: vars.colors.text.normal,
});
export const buttonRow = style({
marginTop: vars.spacing.small,
display: 'flex',
flexDirection: 'row',
});
globalStyle(`${buttonRow} > button`, {
flexGrow: 1,
marginRight: vars.spacing.medium,
});

View File

@ -1,13 +1,20 @@
import React, { useRef, ChangeEvent } from "react";
import { XButton } from "../../../../../styles/shared.css";
import {
ImageInputDisplay,
InputLabel,
ImageInput,
ImageInputButton,
ImageFixer,
XButton,
} from "./seedImage.css";
import {
buttonStyle
} from "../../../../_recipes/button.css";
import { useImageCreate } from "../../../../../stores/imageCreateStore";
import { useTranslation } from "react-i18next";
@ -69,7 +76,7 @@ export default function SeedImage(_props: any) {
type="file"
onChange={_handleFileSelect}
/>
<button className={ImageInputButton} onClick={_startFileSelect}>
<button className={buttonStyle()} onClick={_startFileSelect}>
{t("home.initial-img-btn")}
</button>
</div>
@ -98,4 +105,4 @@ export default function SeedImage(_props: any) {
</div>
</div>
);
}
}

View File

@ -2,8 +2,6 @@ import { style } from "@vanilla-extract/css";
import { vars } from "../../../../../styles/theme/index.css";
import { BrandedButton } from "../../../../../styles/shared.css";
export const ImageInputDisplay = style({
display: "flex",
});
@ -17,28 +15,9 @@ export const ImageInput = style({
display: "none",
});
export const ImageInputButton = style([BrandedButton]);
// this is needed to fix an issue with the image input text
// when that is a drag an drop we can remove this
export const ImageFixer = style({
marginLeft: "20px",
});
// just a 1 off component for now
// dont bother bringing in line with the rest of the app
export const XButton = style({
position: "absolute",
transform: "translateX(-50%) translateY(-35%)",
background: "black",
color: "white",
border: "2pt solid #ccc",
padding: "0",
cursor: "pointer",
outline: "inherit",
borderRadius: "8pt",
width: "16pt",
height: "16pt",
fontFamily: "Verdana",
fontSize: "8pt",
});

View File

@ -0,0 +1,21 @@
import React from "react";
import { useCreateUI } from "../../creationPanelUIStore";
export default function ShowQueue() {
const showQueue = useCreateUI((state) => state.showQueue);
const toggleQueue = useCreateUI((state) => state.toggleQueue);
return (
<label>
<input
type="checkbox"
checked={showQueue}
onChange={() => toggleQueue()}
>
</input>
Display Queue
</label>
);
}

View File

@ -1,56 +0,0 @@
.create-layout {
padding: 10px;
}
/* .panel-box-toggle-btn {
display: block;
width: 100%;
text-align: left;
background-color: transparent;
color: #fff;
border: 0 none;
cursor: pointer;
} */
.selected-tags {
margin: 10px 0;
}
.selected-tags ul {
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
}
li {
list-style: none;
}
.modifier-list {
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0;
}
/* .modifierTag {
display: inline-block;
padding: 6px;
background-color: rgb(38, 77, 141);
color: #fff;
border-radius: 5px;
margin: 5px;
}
.modifierTag.selected {
background-color: rgb(131, 11, 121);
}
.modifierTag p {
margin: 0;
} */
input[type="file"] {
/* Dont show the file name */
color: transparent;
}

View File

@ -1,11 +1,15 @@
import { style } from "@vanilla-extract/css";
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
export const CreationPaneMain = style({
position: "relative",
width: "100%",
height: "100%",
padding: "0 10px",
overflowY: "auto",
overflowX: "hidden",
});
globalStyle(`${CreationPaneMain} > div`, {
marginBottom: vars.spacing.medium,
});
export const InpaintingSlider = style({

View File

@ -8,6 +8,7 @@ export interface ImageCreationUIOptions {
isOpenAdvPropertySettings: boolean;
isOpenAdvWorkflowSettings: boolean;
isOpenImageModifier: boolean;
showQueue: boolean;
toggleAdvancedSettings: () => void;
toggleAdvImprovementSettings: () => void;
@ -15,7 +16,8 @@ export interface ImageCreationUIOptions {
toggleAdvWorkflowSettings: () => void;
toggleImageModifier: () => void;
// addImageModifier: (modifier: string) => void;
toggleQueue: () => void;
}
export const useCreateUI = create<ImageCreationUIOptions>(
@ -27,6 +29,7 @@ export const useCreateUI = create<ImageCreationUIOptions>(
isOpenAdvPropertySettings: false,
isOpenAdvWorkflowSettings: false,
isOpenImageModifier: false,
showQueue: false,
toggleAdvancedSettings: () => {
set(
@ -68,6 +71,15 @@ export const useCreateUI = create<ImageCreationUIOptions>(
})
);
},
toggleQueue: () => {
set(
produce((state: ImageCreationUIOptions) => {
state.showQueue = !state.showQueue;
})
);
},
}),
{
name: "createUI",

View File

@ -15,12 +15,17 @@ export const ImageModifierGrouping = style({
marginTop: vars.spacing.medium,
});
globalStyle(`${ImageModifierGrouping} h4`, {
fontSize: vars.fonts.sizes.Plain,
});
export const ModifierListStyle = style({
paddingLeft: 0,
listStyleType: "none",
display: "flex",
flexWrap: "wrap",
gap: vars.spacing.small,
});
globalStyle(`${ModifierListStyle} li`, {

View File

@ -1,11 +1,17 @@
import React, { useState } from "react";
import {
PanelBox,
MenuButton,
} from "../../../../styles/shared.css";
import {
card
} from '../../../_recipes/card.css';
import {
buttonStyle,
} from "../../../_recipes/button.css";
import {
ImagerModifierGroups,
ImageModifierGrouping,
@ -15,7 +21,7 @@ import {
import { ModifierObject, useImageCreate } from "../../../../stores/imageCreateStore";
import { useCreateUI } from "../creationPanelUIStore";
import ModifierTag from "../../../atoms/modifierTag";
import ModifierTag from "../../../molecules/modifierTag";
interface ModifierListProps {
category: string;
@ -49,11 +55,12 @@ function ModifierGrouping({ title, category, tags }: ModifierGroupingProps) {
setIsExpanded(!isExpanded);
};
// console.log("ModifierGrouping", tags);
return (
<div className={ImageModifierGrouping}>
<button type="button" className={MenuButton} onClick={_toggleExpand}>
<button type="button" className={buttonStyle({
type: 'action',
color: 'accent',
})} onClick={_toggleExpand}>
<h4>{title}</h4>
</button>
{isExpanded && <ModifierList category={category} tags={tags} />}
@ -74,22 +81,27 @@ export default function ImageModifers() {
};
return (
<div className={PanelBox}>
<div className={card(
{
level: 1,
backing: 'normal'
}
)}>
<button
type="button"
onClick={handleClick}
className="panel-box-toggle-btn"
className={buttonStyle({
type: 'action',
color: 'secondary',
size: 'large'
})}
>
{/* TODO: swap this manual collapse stuff out for some UI component? */}
<h3>Image Modifiers (art styles, tags, ect)</h3>
Image Modifiers
</button>
{imageModifierIsOpen && (
<ul className={ImagerModifierGroups}>
{allModifiers.map((item, index) => {
// console.log('mod item ', item);
return (
<li key={item.category}>
<ModifierGrouping title={item.category} category={item.category} tags={item.modifiers} />

View File

@ -1,160 +0,0 @@
import {
createGlobalTheme,
createThemeContract,
createTheme,
} from "@vanilla-extract/css";
/**
* Colors are all the same across the themes, this is just to set up a contract
* Colors can be decided later. I am just the architect.
* Tried to pull things from the original app.
*
* Lots of these arent used yet, but once they are defined and useable then they can be set.
*/
// Link color 0, 102, 204
const colors = createThemeContract({
brand: null,
brandDimmed: null,
brandHover: null,
brandActive: null,
brandAccent: null,
brandAccentDimmed: null,
brandAccentActive: null,
secondary: null,
secondaryDimmed: null,
secondaryHover: null,
secondaryActive: null,
secondaryAccent: null,
secondaryAccentDimmed: null,
secondaryAccentActive: null,
background: null,
backgroundAccent: null,
backgroundAlt: null,
backgroundAltAccent: null,
text: {
normal: null,
dimmed: null,
secondary: null,
secondaryDimmed: null,
accent: null,
accentDimmed: null,
},
link: null,
warning: null,
error: null,
success: null,
});
const app = createGlobalTheme(":root", {
spacing: {
small: "5px",
medium: "10px",
large: "25px",
},
trim: {
smallBorderRadius: "5px",
},
fonts: {
body: "Arial, Helvetica, sans-serif;",
sizes: {
Title: "2em",
Headline: "1.5em",
Subheadline: "1.20em",
SubSubheadline: "1em",
Body: "1em",
Caption: ".75em",
Overline: ".5em",
},
},
colors: colors,
});
export const darkTheme = createTheme(colors, {
brand: "#5000b9", // purple
brandDimmed: "#433852", // muted purple
brandHover: "#5d00d6", // bringhter purple
brandActive: "#5d00d6", // bringhter purple
brandAccent: "#28004e", // darker purple
brandAccentDimmed: "#28004e", // darker purple
brandAccentActive: "#28004e", // darker purple
secondary: "#0b8334", // green
secondaryDimmed: "#0b8334", // green
secondaryHover: "#0b8334", // green
secondaryActive: "#0b8334", // green
secondaryAccent: "#0b8334", // green
secondaryAccentDimmed: "#0b8334", // green
secondaryAccentActive: "#0b8334", // green
background: "#202124", // dark grey
backgroundAccent: " #383838", // lighter grey
backgroundAlt: "#2c2d30", // med grey
backgroundAltAccent: "#383838", // lighter grey
text: {
normal: "#ffffff", // white
dimmed: "#d1d5db", // off white
secondary: "#ffffff", // white
secondaryDimmed: "#d1d5db", // off white
accent: "#e7ba71", // orange
accentDimmed: "#7d6641", // muted orange
},
link: "#0066cc", // blue
warning: "#f0ad4e",
error: "#d9534f",
success: "#5cb85c",
});
// Generated by co-pilot
export const lightTheme = createTheme(colors, {
brand: "#1E40AF",
brandDimmed: "#1E40AF",
brandHover: "#1E40AF",
brandActive: "#1E40AF",
brandAccent: "#1E40AF",
brandAccentDimmed: "#1E40AF",
brandAccentActive: "#1E40AF",
secondary: "#DB2777",
secondaryDimmed: "#DB2777",
secondaryHover: "#DB2777",
secondaryActive: "#DB2777",
secondaryAccent: "#DB2777",
secondaryAccentDimmed: "#DB2777",
secondaryAccentActive: "#DB2777",
background: "#EFF6FF",
backgroundAccent: "#EFF6FF",
backgroundAlt: "#EFF6FF",
backgroundAltAccent: "#EFF6FF",
text: {
normal: "#1F2937",
dimmed: "#6B7280",
secondary: "#1F2937",
secondaryDimmed: "#6B7280",
accent: "#1F2937",
accentDimmed: "#6B7280",
},
link: "#0066cc", // blue
warning: "yellow",
error: "red",
success: "green",
});
export const vars = { ...app, colors };

View File

@ -1,25 +1,30 @@
import React, { ChangeEvent } from "react";
import BasicCreation from "./basicCreation";
import AdvancedSettings from "./advancedSettings";
import ImageModifiers from "./imageModifiers";
import InpaintingPanel from "./inpaintingPanel";
import QueueDisplay from "../queueDisplay";
// this works but causes type errors so its not worth it for now
// import { useImageCreate } from "@stores/imageCreateStore.ts";
import { useImageCreate } from "../../../stores/imageCreateStore";
import { useRequestQueue } from "../../../stores/requestQueueStore";
import "./creationPanel.css";
import {
CreationPaneMain,
InpaintingSlider,
} from "./creationpane.css";
} from "./creationPanel.css";
import BasicCreation from "./basicCreation";
export default function CreationPanel() {
const isInPaintingMode = useImageCreate((state) => state.isInpainting);
const hasQueue = useRequestQueue((state) => state.hasAnyQueue());
return (
<>
<div className={CreationPaneMain}>

View File

@ -1,7 +1,6 @@
import { style, globalStyle } from '@vanilla-extract/css'
import { vars } from '../../../../../styles/theme/index.css'
import { vars } from '../../../../styles/theme/index.css'
export const imageDisplayMain = style({
height: '100%',

View File

@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/naming-convention */
import React from "react";
import { useImageCreate } from "../../../../../stores/imageCreateStore";
import { CompletedImagesType } from "../../../../../stores/imageDisplayStore";
import { useImageCreate } from "../../../../stores/imageCreateStore";
import { CompletedImagesType } from "../../../../stores/imageDisplayStore";
import GeneratedImage from "../../../../molecules/generatedImage";
import GeneratedImage from "../../../molecules/generatedImage";
import {
imageDisplayMain,
@ -12,15 +12,17 @@ import {
imageDisplayContent,
} from './imageDisplay.css';
import {
BrandedButton
} from '../../../../../styles/shared.css'
buttonStyle
} from "../../../_recipes/button.css";
export default function ImageDisplay({ info, data }: CompletedImagesType) {
const createFileName = () => {
const {
prompt,
negative_prompt,
seed,
num_inference_steps,
guidance_scale,
@ -73,9 +75,17 @@ export default function ImageDisplay({ info, data }: CompletedImagesType) {
<div className={imageDisplayContent}>
<div>
<p> {info?.prompt}</p>
<p> {info?.negative_prompt}</p>
<div>
<button className={BrandedButton} onClick={_handleSave}>Save</button>
<button className={BrandedButton} onClick={_handleUseAsInput}>Use as Input</button>
<button className={buttonStyle(
)} onClick={_handleSave}>Save</button>
<button className={buttonStyle(
{
color: "secondary",
type: "outline",
}
)} onClick={_handleUseAsInput}>Use as Input</button>
</div>
</div>
<GeneratedImage imageData={data} metadata={info}></GeneratedImage>

View File

@ -0,0 +1,58 @@
import React, { useEffect, useState } from "react";
import { FetchingStates, useImageFetching } from "../../../stores/imageFetchingStore";
import { useImageDisplay } from "../../../stores/imageDisplayStore";
import { API_URL } from "../../../api";
import {
currentDisplayMain,
} from './currentDisplay.css';
import ImageDisplay from "./imageDisplay";
const IdleDisplay = () => {
return (
<h4 className="no-image">Try Making a new image!</h4>
);
};
const LoadingDisplay = ({ images }: { images: string[] }) => {
return (
<>
{images.map((image, index) => {
if (index == images.length - 1) {
return (
<img src={`${API_URL}${image}`} key={index} />
)
}
})
}
</>
);
};
export default function CurrentDisplay() {
const status = useImageFetching((state) => state.status);
const currentImage = useImageDisplay((state) => state.currentImage);
const progressImages = useImageFetching((state) => state.progressImages);
return (
<div className={currentDisplayMain}>
{(currentImage == null) && <IdleDisplay />}
{/* {(status === FetchingStates.FETCHING || status === FetchingStates.PROGRESSING) && <LoadingDisplay />}
{(currentImage != null) && <ImageDisplay info={currentImage?.info} data={currentImage?.data} />} */}
{
(progressImages.length > 0)
? <LoadingDisplay images={progressImages} />
: (currentImage != null) && <ImageDisplay info={currentImage?.info} data={currentImage?.data} />
}
</div>
);
}

View File

@ -0,0 +1,22 @@
import { style } from '@vanilla-extract/css'
import {
card as cardStyles,
} from '../../_recipes/card.css'
export const currentInfoMain = style([
cardStyles(
{
backing: 'dark',
}
),
{
// display: 'flex',
// flexDirection: 'column',
// justifyContent: 'center',
// alignItems: 'center',
// height: '100%',
width: '250px',
padding: '0 0 0 0',
},
])

View File

@ -0,0 +1,7 @@
import React from "react";
import { currentInfoMain } from "./currentInfo.css";
export default function CurrentInfo() {
return <div className={
currentInfoMain
}> current info</div>;
}

View File

@ -1,65 +0,0 @@
import React from "react";
import { useImageDisplay } from "../../../../stores/imageDisplayStore";
import {
completedImagesMain,
completedImagesList,
imageContain,
RemoveButton,
} from "./completedImages.css";
export default function CompletedImages(
) {
const images = useImageDisplay((state) => state.images);
const setCurrentImage = useImageDisplay((state) => state.setCurrentImage);
const clearDisplay = useImageDisplay((state) => state.clearDisplay);
const removeImagesAll = () => {
clearDisplay();
};
return (
<div className={completedImagesMain}>
{/* Adjust the dom do we dont do this check twice */}
{images != null && images.length > 0 && (
<button
className={RemoveButton}
onClick={() => {
removeImagesAll();
}}
>
REMOVE
</button>
)}
<ul className={completedImagesList}>
{images?.map((image, index) => {
if (void 0 === image) {
console.warn(`image ${index} is undefined`);
return null;
}
return (
<li key={image.id}>
<button
className={imageContain}
onClick={() => {
setCurrentImage(image);
}}
>
<img src={image.data} alt={image.info.prompt} />
</button>
</li>
);
})}
</ul>
</div>
);
}

View File

@ -1,86 +0,0 @@
import React, { useEffect, useState } from "react";
import { FetchingStates, useImageFetching } from "../../../../stores/imageFetchingStore";
import { useImageDisplay } from "../../../../stores/imageDisplayStore";
import { API_URL } from "../../../../api";
import {
currentDisplayMain,
} from './currentDisplay.css';
import ImageDisplay from "./imageDisplay";
const IdleDisplay = () => {
return (
<h4 className="no-image">Try Making a new image!</h4>
);
};
const LoadingDisplay = () => {
const step = useImageFetching((state) => state.step);
const totalSteps = useImageFetching((state) => state.totalSteps);
const progressImages = useImageFetching((state) => state.progressImages);
const startTime = useImageFetching((state) => state.timeStarted);
const timeNow = useImageFetching((state) => state.timeNow);
const [timeRemaining, setTimeRemaining] = useState(0);
const [percent, setPercent] = useState(0);
useEffect(() => {
if (totalSteps > 0) {
setPercent(Math.round((step / totalSteps) * 100));
} else {
setPercent(0);
}
}, [step, totalSteps]);
useEffect(() => {
// find the remaining time
const timeTaken = +timeNow - +startTime;
const timePerStep = step == 0 ? 0 : timeTaken / step;
const totalTime = timePerStep * totalSteps;
const timeRemaining = (totalTime - timeTaken) / 1000;
// @ts-expect-error
setTimeRemaining(timeRemaining.toPrecision(3));
}, [step, totalSteps, startTime, timeNow, setTimeRemaining]);
return (
<>
<h4 className="loading">Loading...</h4>
<p>{percent} % Complete </p>
{timeRemaining != 0 && <p>Time Remaining: {timeRemaining} s</p>}
{progressImages.map((image, index) => {
if (index == progressImages.length - 1) {
return (
<img src={`${API_URL}${image}`} key={index} />
)
}
})
}
</>
);
};
export default function CurrentDisplay() {
const status = useImageFetching((state) => state.status);
const currentImage = useImageDisplay((state) => state.currentImage);
return (
<div className={currentDisplayMain}>
{status === FetchingStates.IDLE && <IdleDisplay />}
{(status === FetchingStates.FETCHING || status === FetchingStates.PROGRESSING) && <LoadingDisplay />}
{(status === FetchingStates.COMPLETE && currentImage != null) && <ImageDisplay info={currentImage?.info} data={currentImage?.data} />}
</div>
);
}

View File

@ -1,18 +0,0 @@
import { style } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
export const displayPanel = style({
height: "100%",
display: "flex",
flexDirection: "column",
paddingRight: vars.spacing.medium,
});
export const displayContainer = style({
flexGrow: 1,
overflow: 'auto',
});
export const previousImages = style({
minHeight: '250px',
});

View File

@ -1,30 +0,0 @@
import React from "react";
import CurrentDisplay from "./currentDisplay";
import CompletedImages from "./completedImages";
import {
displayPanel,
displayContainer,
previousImages,
} from "./displayPanel.css";
export default function DisplayPanel() {
return (
<div className={displayPanel}>
<div className={displayContainer}>
<CurrentDisplay
></CurrentDisplay>
</div>
<div className={previousImages}>
<CompletedImages
></CompletedImages>
</div>
</div>
);
}

View File

@ -6,7 +6,11 @@ import {
PopoverMain,
PopoverButtonStyle,
PopoverPanelMain,
} from "../../../_headless/popover/index.css";
} from "../../../_recipes/popover_headless.css";
import {
card
} from '../../../_recipes/card.css';
import {
IconFont,

View File

@ -3,13 +3,13 @@ import { style } from "@vanilla-extract/css";
import { vars } from "../../../../styles/theme/index.css";
export const StartingStatus = style({
color: vars.colors.warning,
color: `hsl(${vars.warningHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
export const ErrorStatus = style({
color: vars.colors.error,
color: `hsl(${vars.errorHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
export const SuccessStatus = style({
color: vars.colors.success,
color: `hsl(${vars.successHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});

View File

@ -17,7 +17,7 @@ import {
PopoverMain,
PopoverButtonStyle,
PopoverPanelMain,
} from "../../../_headless/popover/index.css";
} from "../../../_recipes/popover_headless.css";
import {
SettingContent
@ -48,7 +48,7 @@ export default function SystemSettings() {
state.getValueForRequestKey("use_full_precision")
);
const isSoundEnabled = true; //useImageCreate((state) => state.isSoundEnabled());
const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled());
const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const toggleUseAutoSave = useImageCreate((state) => state.toggleUseAutoSave);

View File

@ -0,0 +1,52 @@
import React from "react";
import { ImageRequest } from "../../../api";
import { QueuedRequest, useRequestQueue } from "../../../stores/requestQueueStore";
import {
QueueDisplayMain,
QueueListButtons,
} from "./queueDisplay.css";
import {
buttonStyle
} from "../../_recipes/button.css";
import ClearQueue from "../../molecules/clearQueue";
import QueueItem from "./queueItem";
export default function QueueDisplay() {
const requests: QueuedRequest[] = useRequestQueue((state) => state.requests);
const removeCompleted = useRequestQueue((state) => state.removeCompleted);
const removeErrored = useRequestQueue((state) => state.removeErrored);
const clearCompleted = () => {
removeCompleted();
}
const clearErrored = () => {
removeErrored();
}
return (
<div className={QueueDisplayMain}>
<ClearQueue />
<div className={QueueListButtons}>
<button
className={buttonStyle({
type: 'outline',
})}
onClick={clearCompleted}>Clear Completed</button>
<button
className={buttonStyle({
type: 'outline',
})}
onClick={clearErrored}>Clear Errored</button>
</div>
{requests.map((request) => {
return <QueueItem key={request.id} request={request}></QueueItem>;
})}
</div>
);
};

View File

@ -0,0 +1,28 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../styles/theme/index.css";
export const QueueDisplayMain = style({
display: "flex",
flexDirection: "column",
width: '100%',
height: '100%',
});
export const QueueListButtons = style({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: vars.spacing.medium,
marginTop: vars.spacing.medium,
});
globalStyle(`${QueueListButtons} button`, {
flexGrow: 1,
});
globalStyle(`${QueueListButtons} button:first-child`, {
marginRight: vars.spacing.medium,
});

View File

@ -0,0 +1,125 @@
/* eslint-disable @typescript-eslint/naming-convention */
import React from "react";
import { QueueStatus, QueuedRequest, useRequestQueue } from '../../../../stores/requestQueueStore';
import StopButton from '../../../molecules/stopButton';
import {
QueueItemMain,
QueueItemInfo,
QueueButtons,
} from "./queueItem.css";
import {
buttonStyle
} from "../../../_recipes/button.css";
interface QueueItemProps {
request: QueuedRequest;
}
export default function QueueItem({ request }: QueueItemProps) {
const removeItem = useRequestQueue((state) => state.removeItem);
const updateStatus = useRequestQueue((state) => state.updateStatus);
const sendPendingToTop = useRequestQueue((state) => state.sendPendingToTop);
const {
id,
options: {
prompt,
num_outputs,
seed,
sampler,
guidance_scale,
num_inference_steps,
},
status,
} = request;
const removeFromQueue = () => {
removeItem(id);
}
const pauseItem = () => {
updateStatus(id, QueueStatus.paused);
}
const retryRequest = () => {
updateStatus(id, QueueStatus.pending);
}
const sendToTop = () => {
sendPendingToTop(id);
}
return (
<div className={[QueueItemMain, status].join(' ')}>
<div className={QueueItemInfo}>
<p>{prompt}</p>
<p>Making {num_outputs} concurrent images</p>
<p>
<span>Seed: {seed} </span>
<span>Sampler: {sampler} </span>
<span>Guidance Scale: {guidance_scale} </span>
<span>Num Inference Steps: {num_inference_steps} </span>
</p>
</div>
<div className={QueueButtons}>
{status === QueueStatus.processing && (
<StopButton></StopButton>
)}
{status === QueueStatus.complete && (
<button
className={buttonStyle({
size: "large",
})}
onClick={removeFromQueue}>
Clear
</button>
)}
{status === QueueStatus.pending && (
<>
<button className={buttonStyle({
color: "cancel",
})} onClick={removeFromQueue}>Remove</button>
<button className={buttonStyle({
color: "secondary",
type: "outline",
})} onClick={pauseItem}>Pause</button>
<button className={buttonStyle({
color: "tertiary",
type: "action",
})} onClick={sendToTop}>Send to top</button>
</>
)}
{status === QueueStatus.paused && (
<button
className={buttonStyle({
size: "large",
})} onClick={retryRequest}>Resume</button>
)}
{status === QueueStatus.error && (
<button
className={buttonStyle({
size: "large",
})} onClick={retryRequest}>Retry</button>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,61 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../../styles/theme/index.css";
import { QueueStatus } from "../../../../stores/requestQueueStore";
import {
card
} from '../../../_recipes/card.css';
export const QueueItemMain = style([card(
{
info: true,
level: 1
}
), {
display: "flex",
flexDirection: "column",
width: "100%",
marginBottom: vars.spacing.medium,
}]);
export const QueueItemInfo = style({
});
globalStyle(`${QueueItemInfo} p`, {
marginBottom: vars.spacing.small,
});
globalStyle(`${QueueItemMain}.${QueueStatus.complete}`, {
borderColor: `hsl(${vars.secondaryHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
globalStyle(`${QueueItemMain}.${QueueStatus.processing}`, {
borderColor: `hsl(${vars.tertiaryHue}, ${vars.colorMod.saturation.bright}, ${vars.colorMod.lightness.bright})`,
});
globalStyle(`${QueueItemMain}.${QueueStatus.pending}`, {
borderColor: `hsl(${vars.backgroundAccentMain}, ${vars.colorMod.saturation.bright}, ${vars.colorMod.lightness.normal})`,
});
globalStyle(`${QueueItemMain}.${QueueStatus.paused}`, {
borderColor: `hsl(${vars.backgroundAccentMain}, ${vars.colorMod.saturation.dim}, ${vars.colorMod.lightness.dim})`,
backgroundColor: `hsl(${vars.backgroundAccentMain}, ${vars.colorMod.saturation.dim}, ${vars.colorMod.lightness.dim})`,
});
globalStyle(`${QueueItemMain}.${QueueStatus.error}`, {
borderColor: `hsl(${vars.errorHue}, ${vars.colorMod.saturation.normal}, ${vars.colorMod.lightness.normal})`,
});
export const QueueButtons = style({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
});

View File

@ -1,34 +1,34 @@
import { style } from "@vanilla-extract/css";
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../styles/theme/index.css";
export const AppLayout = style({
position: "relative",
backgroundColor: vars.colors.background,
width: "100%",
height: "100%",
width: "100vw",
height: "100vh",
pointerEvents: "auto",
display: "grid",
// backgroundColor: "rgb(32, 33, 36)",
backgroundColor: vars.backgroundMain,
gridTemplateColumns: "400px 1fr",
gridTemplateRows: "100px 1fr 115px",
gridTemplateRows: "70px 1fr 115px",
gridTemplateAreas: `
"header header header"
"create display display"
"create footer footer"
"create display display"
`,
"@media": {
"screen and (max-width: 800px)": {
gridTemplateColumns: "1fr",
gridTemplateRows: "100px 300px 1fr 100px",
gridTemplateAreas: `
"header"
"create"
"display"
"footer"
`,
},
},
// "@media": {
// "screen and (max-width: 800px)": {
// gridTemplateColumns: "1fr",
// gridTemplateRows: "100px 300px 1fr",
// gridTemplateAreas: `
// "header"
// "create"
// "display"
// `,
// },
// },
});
export const HeaderLayout = style({
@ -38,6 +38,8 @@ export const HeaderLayout = style({
export const CreateLayout = style({
gridArea: "create",
position: "relative",
display: "flex",
flexDirection: "column",
});
export const DisplayLayout = style({

View File

@ -16,11 +16,11 @@ import { useImageCreate } from "../../stores/imageCreateStore";
// Todo - import components here
import HeaderDisplay from "../../components/organisms/headerDisplay";
import CreationPanel from "../../components/organisms/creationPanel";
import DisplayPanel from "../../components/organisms/displayPanel";
import BasicDisplay from "../../components/layouts/basicDisplay";
import FooterDisplay from "../../components/organisms/footerDisplay";
import CreationTabs from "../../components/layouts/creationTabs";
function Home({ className }: { className: any }) {
function Home() {
// Get the original save directory
const setRequestOption = useImageCreate((state) => state.setRequestOptions);
@ -51,20 +51,22 @@ function Home({ className }: { className: any }) {
}, [setRequestOption, statusMods, dataMoads]);
return (
<div className={[AppLayout, className].join(" ")}>
<header className={HeaderLayout}>
<HeaderDisplay></HeaderDisplay>
</header>
<nav className={CreateLayout}>
<CreationPanel></CreationPanel>
</nav>
<main className={DisplayLayout}>
<DisplayPanel></DisplayPanel>
</main>
<>
<div className={[AppLayout].join(" ")}>
<header className={HeaderLayout}>
<HeaderDisplay></HeaderDisplay>
</header>
<nav className={CreateLayout}>
<CreationTabs></CreationTabs>
</nav>
<main className={DisplayLayout}>
<BasicDisplay></BasicDisplay>
</main>
</div>
<footer className={FooterLayout}>
<FooterDisplay></FooterDisplay>
</footer>
</div>
</>
);
}

View File

@ -1,6 +1,6 @@
import React from "react";
export default function Settings({ className }: { className: any }) {
export default function Settings() {
return (
<div>
<h1>Settings</h1>

View File

@ -42,11 +42,20 @@ interface ModifiersList {
type ModifiersOptionList = ModifiersList[];
export interface promptTag {
id: string;
name: string;
type: 'positive' | 'negative';
}
interface ImageCreateState {
parallelCount: number;
requestOptions: ImageRequest;
allModifiers: ModifiersOptionList;
tags: string[];
createTags: promptTag[];
// negativeTags: promptTag[];
tagMap: Record<string, string[]>;
isInpainting: boolean;
@ -59,6 +68,11 @@ interface ImageCreateState {
toggleTag: (category: string, tag: string) => void;
hasTag: (category: string, tag: string) => boolean;
selectedTags: () => ModifierObject[];
addCreateTag: (tag: promptTag) => void;
removeCreateTag: (id: string) => void;
changeCreateTagType: (id: string, type: 'positive' | 'negative') => void;
reorderCreateTag: (tag: promptTag, index: number) => void;
builtRequest: () => ImageRequest;
uiOptions: ImageCreationUiOptions;
@ -85,6 +99,7 @@ export const useImageCreate = create<ImageCreateState>(
requestOptions: {
session_id: new Date().getTime().toString(),
prompt: "a photograph of an astronaut riding a horse",
negative_prompt: "",
seed: useRandomSeed(),
num_outputs: 1,
num_inference_steps: 50,
@ -108,7 +123,8 @@ export const useImageCreate = create<ImageCreateState>(
},
// selected tags
tags: [] as string[],
createTags: [] as promptTag[],
// negativeTags: [] as promptTag[],
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
tagMap: {} as Record<string, string[]>,
@ -202,7 +218,48 @@ export const useImageCreate = create<ImageCreateState>(
return selected;
},
addCreateTag: (tag: promptTag) => {
set(
produce((state) => {
state.createTags.push(tag);
})
);
},
removeCreateTag: (id: string) => {
set(
produce((state) => {
// @ts-expect-error
state.createTags = state.createTags.filter((t) => t.id !== id);
})
);
},
changeCreateTagType: (id: string, type: 'positive' | 'negative') => {
set(
produce((state) => {
// @ts-expect-error
const tag = state.createTags.find((t) => t.id === id);
if (tag) {
tag.type = type;
}
})
);
},
reorderCreateTag: (tag: promptTag, index: number) => {
set(
produce((state) => {
const tagIndex = state.createTags.indexOf(tag);
if (tagIndex !== -1) {
state.createTags.splice(tagIndex, 1);
state.createTags.splice(index, 0, tag);
}
})
);
},
// the request body to send to the server
// this is a computed value, just adding the tags to the request
@ -212,13 +269,17 @@ export const useImageCreate = create<ImageCreateState>(
const selectedTags = get().selectedTags();
const tags = selectedTags.map((t: ModifierObject) => t.modifier);
const positivePrompt = state.createTags.filter((t) => t.type === "positive").map((t) => t.name).join(",");
const negativePrompt = state.createTags.filter((t) => t.type === "negative").map((t) => t.name).join(",");
// join all the tags with a comma and add it to the prompt
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
const prompt = `${requestOptions.prompt}, ${tags.join(",")}`;
// const prompt = `${requestOptions.prompt}, ${tags.join(",")}`;
const request = {
...requestOptions,
prompt,
prompt: positivePrompt,
negative_prompt: negativePrompt,
};
// if we arent using auto save clear the save path
if (!state.uiOptions.isUseAutoSave) {
@ -317,7 +378,6 @@ export const useImageCreate = create<ImageCreateState>(
set(
produce((state: ImageCreateState) => {
state.uiOptions.isSoundEnabled = !state.uiOptions.isSoundEnabled;
//localStorage.setItem('ui:isSoundEnabled', state.uiOptions.isSoundEnabled);
})
);
},

View File

@ -27,7 +27,6 @@ interface ImageFetchingState {
setStartTime: () => void;
setNowTime: () => void;
resetForFetching: () => void;
}
export const useImageFetching = create<ImageFetchingState>((set) => ({

View File

@ -1,69 +0,0 @@
import create from "zustand";
import produce from "immer";
import { useRandomSeed } from "../utils";
import { ImageRequest } from "../api";
interface QueueItem {
id?: string;
options?: ImageRequest;
status?: "pending" | "complete" | "error";
}
interface ImageQueueState {
images: QueueItem[];
completedImageIds: string[];
addNewImage: (id: string, imgRec: ImageRequest) => void;
hasQueuedImages: () => boolean;
firstInQueue: () => QueueItem;
removeFirstInQueue: () => void;
clearCachedIds: () => void;
}
export const useImageQueue = create<ImageQueueState>((set, get) => ({
images: [],
completedImageIds: [],
// use produce to make sure we don't mutate state
addNewImage: (id: string, imgRec: ImageRequest) => {
set(
produce((state) => {
const item: QueueItem = { id, options: imgRec, status: "pending" };
state.images.push(item);
})
);
},
hasQueuedImages: () => {
return get().images.length > 0;
},
firstInQueue: () => {
const { images } = get();
if (images.length > 0) {
return images[0];
}
// // cast an empty object to QueueItem
const empty: QueueItem = {};
return empty;
},
removeFirstInQueue: () => {
set(
produce((state) => {
const image = state.images.shift();
if (void 0 !== image) {
state.completedImageIds.push(image.id);
}
})
);
},
clearCachedIds: () => {
set(
produce((state) => {
state.completedImageIds = [];
})
);
},
}));

View File

@ -0,0 +1,160 @@
import create from "zustand";
import produce from "immer";
import { ImageRequest } from "../api";
export enum QueueStatus {
pending = "pending",
processing = "processing",
complete = "complete",
paused = "paused",
error = "error",
}
export interface QueuedRequest {
id: string;
options: ImageRequest;
status: QueueStatus[keyof QueueStatus];
//"pending" | "processing" | "complete" | "error";
}
interface RequestQueueState {
requests: QueuedRequest[];
addtoQueue: (id: string, imgRec: ImageRequest) => void;
pendingRequests: () => QueuedRequest[];
hasPendingQueue: () => boolean;
hasAnyQueue: () => boolean;
firstInQueue: () => QueuedRequest;
updateStatus: (id: string, status: QueueStatus[keyof QueueStatus]) => void;
sendPendingToTop: (id: string) => void;
removeItem: (id: string) => void;
removeCompleted: () => void;
removeErrored: () => void;
clearQueue: () => void;
}
export const useRequestQueue = create<RequestQueueState>((set, get) => ({
requests: [],
// use produce to make sure we don't mutate state
addtoQueue: (id: string, imgRec: ImageRequest) => {
set(
produce((state) => {
const item: QueuedRequest = { id, options: imgRec, status: QueueStatus.pending };
state.requests.push(item);
})
);
},
pendingRequests: () => {
return get().requests.filter((item) => item.status === QueueStatus.pending);
},
hasPendingQueue: () => {
return get().pendingRequests().length > 0;
},
hasAnyQueue: () => {
return get().requests.length > 0;
},
firstInQueue: () => {
const pending = get().pendingRequests()[0];
if (pending === undefined) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const temp: QueuedRequest = { id: "", options: ({} as ImageRequest), status: QueueStatus.pending };
return temp;
}
return pending;
},
updateStatus: (id: string, status: QueueStatus[keyof QueueStatus]) => {
set(
produce((state) => {
const item = state.requests.find((item: QueuedRequest) => item.id === id);
if (void 0 !== item) {
item.status = status;
}
})
);
},
sendPendingToTop: (id: string) => {
set(
produce((state) => {
const item = state.requests.find((item: QueuedRequest) => item.id === id);
if (void 0 !== item) {
// remove from current position
const index = state.requests.indexOf(item);
state.requests.splice(index, 1);
// find the first available stop and insert it there
for (let i = 0; i < state.requests.length; i++) {
const curStatus = state.requests[i].status;
// skip over any items that are not pending or paused
if (curStatus === QueueStatus.processing) {
continue;
}
if (curStatus === QueueStatus.complete) {
continue;
}
if (curStatus === QueueStatus.error) {
continue;
}
// insert infront of any pending or paused items
state.requests.splice(i, 0, item);
break;
}
}
})
);
},
removeItem: (id: string) => {
set(
produce((state) => {
const index = state.requests.findIndex((item: QueuedRequest) => item.id === id);
if (index > -1) {
state.requests.splice(index, 1);
}
})
);
},
removeCompleted: () => {
set(
produce((state) => {
const completed = state.requests.filter((item: QueuedRequest) => item.status === QueueStatus.complete);
completed.forEach((item: QueuedRequest) => {
const index = state.requests.indexOf(item);
state.requests.splice(index, 1);
});
})
);
},
removeErrored: () => {
set(
produce((state) => {
const errored = state.requests.filter((item: QueuedRequest) => item.status === QueueStatus.error);
errored.forEach((item: QueuedRequest) => {
const index = state.requests.indexOf(item);
state.requests.splice(index, 1);
});
})
);
},
clearQueue: () => {
set(
produce((state) => {
state.requests = [];
})
);
},
}));

View File

@ -8,6 +8,10 @@ globalStyle("body", {
minHeight: "100vh",
});
// single page style
globalStyle("#root", {
position: "absolute",
@ -15,7 +19,11 @@ globalStyle("#root", {
left: 0,
width: "100vw",
height: "100vh",
overflow: "hidden",
overflow: 'auto',
overflowX: 'hidden',
// "::-webkit-scrollbar": {
// width: "0",
// },
});
// border box all
@ -41,12 +49,14 @@ globalStyle(`h1, h2, h3, h4, h5, h6, p, label, ul, textarea`, {
globalStyle(`h3`, {
fontSize: vars.fonts.sizes.Subheadline,
marginBottom: vars.spacing.small,
});
globalStyle(`h4, h5`, {
fontSize: vars.fonts.sizes.SubSubheadline,
marginBottom: vars.spacing.medium,
});
globalStyle(`h6`, {
fontSize: vars.fonts.sizes.Body,
});
globalStyle(`p, label`, {
@ -63,4 +73,8 @@ globalStyle(`textarea`, {
globalStyle(`a`, {
color: vars.colors.link,
textDecoration: "none",
});
globalStyle(`ul`, {
listStyle: "none",
});

View File

@ -1,22 +0,0 @@
import { recipe } from "@vanilla-extract/recipes";
export const button = recipe({
variants: {
color: {
neutral: { background: "whitesmoke" },
brand: { background: "blueviolet" },
accent: { background: "slateblue" },
},
size: {
small: { padding: 12 },
medium: { padding: 16 },
large: { padding: 24 },
},
},
});
// export const card = recipe({
// variants: {
// color: {
// alt: { background: 'whitesmoke' },

View File

@ -1,38 +1,15 @@
import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "./theme/index.css";
export const PanelBox = style({
background: vars.colors.backgroundAlt,
color: vars.colors.text.normal,
padding: vars.spacing.medium,
borderRadius: vars.trim.smallBorderRadius,
marginBottom: vars.spacing.medium,
// TODO move this to the theme
boxShadow:
"0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15)",
});
globalStyle(`${PanelBox} .panel-box-toggle-btn`, {
display: "block",
width: "100%",
textAlign: "left",
backgroundColor: "transparent",
color: vars.colors.text.normal,
border: "0 none",
cursor: "pointer",
padding: "0",
});
//TODO this should probably just be for all li elements
export const SettingItem = style({
marginBottom: vars.spacing.medium,
selectors: {
"&:last-of-type": {
marginBottom: vars.spacing.none,
},
},
});
@ -42,6 +19,24 @@ export const IconFont = style({
});
export const XButton = style({
position: "absolute",
transform: "translateX(-50%) translateY(-35%)",
background: "black",
color: "white",
border: "2pt solid #ccc",
padding: "0",
cursor: "pointer",
outline: "inherit",
borderRadius: "8pt",
width: "16pt",
height: "16pt",
fontFamily: "Verdana",
fontSize: "8pt",
});
export const MenuButton = style({
display: "block",
width: "100%",
@ -58,25 +53,3 @@ globalStyle(`${MenuButton}> h4`, {
color: "#e7ba71",
});
export const BrandedButton = style({
backgroundColor: vars.colors.brand,
fontSize: vars.fonts.sizes.Subheadline,
fontWeight: "bold",
color: vars.colors.text.normal,
padding: vars.spacing.small,
borderRadius: vars.trim.smallBorderRadius,
":hover": {
backgroundColor: vars.colors.brandHover,
},
":active": {
backgroundColor: vars.colors.brandActive,
},
":disabled": {
backgroundColor: vars.colors.brandDimmed,
color: vars.colors.text.dimmed,
},
});

View File

@ -4,54 +4,6 @@ import {
createTheme,
} from "@vanilla-extract/css";
/**
* Colors are all the same across the themes, this is just to set up a contract
* Colors can be decided later. I am just the architect.
* Tried to pull things from the original app.
*
* Lots of these arent used yet, but once they are defined and useable then they can be set.
*/
const colors = createThemeContract({
brand: null,
brandDimmed: null,
brandHover: null,
brandActive: null,
brandAccent: null,
brandAccentDimmed: null,
brandAccentActive: null,
secondary: null,
secondaryDimmed: null,
secondaryHover: null,
secondaryActive: null,
secondaryAccent: null,
secondaryAccentDimmed: null,
secondaryAccentActive: null,
background: null,
backgroundAccent: null,
backgroundAlt: null,
backgroundAltAccent: null,
backgroundDark: null,
backgroundDarkAccent: null,
text: {
normal: null,
dimmed: null,
secondary: null,
secondaryDimmed: null,
accent: null,
accentDimmed: null,
},
link: null,
warning: null,
error: null,
success: null,
});
const app = createGlobalTheme(":root", {
spacing: {
none: "0",
@ -79,92 +31,57 @@ const app = createGlobalTheme(":root", {
Overline: ".5em",
},
},
colors,
});
// colors,
export const darkTheme = createTheme(colors, {
brand: "#5000b9", // purple
brandDimmed: "#433852", // muted purple
brandHover: "#5d00d6", // bringhter purple
brandActive: "#5d00d6", // bringhter purple
brandAccent: "#28004e", // darker purple
brandAccentDimmed: "#28004e", // darker purple
brandAccentActive: "#28004e", // darker purple
// 60 degree color difference
// step downs
brandHue: '265', // purple
secondaryHue: '225', // deep blue
tertiaryHue: '145', // grass green
secondary: "#0b8334", // green
secondaryDimmed: "#0b8334", // green
secondaryHover: "#0b8334", // green
secondaryActive: "#0b8334", // green
secondaryAccent: "#0b8334", // green
secondaryAccentDimmed: "#0b8334", // green
secondaryAccentActive: "#0b8334", // green
// step ups
errorHue: '0',
warningHue: '25', // orange
successHue: '85', // green
background: "#202124", // dark grey
backgroundAccent: " #383838", // lighter grey
backgroundAlt: "#2c2d30", // med grey
backgroundAltAccent: "#383838", // lighter grey
backgroundDark: "#121213", // darker grey
backgroundDarkAccent: "#383838", // lighter grey
text: {
normal: "#ffffff", // white
dimmed: "#d1d5db", // off white
secondary: "#ffffff", // white
secondaryDimmed: "#d1d5db", // off white
accent: "#e7ba71", // orange
accentDimmed: "#7d6641", // muted orange
colorMod: {
saturation: {
bright: "100%",
normal: "60%",
dimmed: "50%",
dim: "30%",
},
lightness: {
normal: "45%",
bright: "60%",
dim: "40%",
},
},
link: "#0066cc", // blue
warning: "#f0ad4e",
error: "#d9534f",
success: "#5cb85c",
// is the secondary hue
backgroundMain: 'hsl(225, 6%, 13%)',
backgroundLight: 'hsl(225, 4%, 18%)',
backgroundDark: 'hsl(225, 3%, 7%)',
backgroundAccentMain: 'hsl(225, 6%, 30%)',
backgroundAccentHue: '225',
backgroundAccentSaturation: '26%',
backgroundAccentLightness: '70%',
// this is depricated
colors: {
text: {
normal: "#ffffff", // white
dimmed: "#d1d5db", // off white
secondary: "#ffffff", // white
secondaryDimmed: "#d1d5db", // off white
accent: "#e7ba71", // orange
accentDimmed: "#7d6641", // muted orange
},
link: "#0066cc", // blue
}
});
// Generated by co-pilot
export const lightTheme = createTheme(colors, {
brand: "#1E40AF",
brandDimmed: "#1E40AF",
brandHover: "#1E40AF",
brandActive: "#1E40AF",
brandAccent: "#1E40AF",
brandAccentDimmed: "#1E40AF",
brandAccentActive: "#1E40AF",
secondary: "#DB2777",
secondaryDimmed: "#DB2777",
secondaryHover: "#DB2777",
secondaryActive: "#DB2777",
secondaryAccent: "#DB2777",
secondaryAccentDimmed: "#DB2777",
secondaryAccentActive: "#DB2777",
background: "#EFF6FF",
backgroundAccent: "#EFF6FF",
backgroundAlt: "#EFF6FF",
backgroundAltAccent: "#EFF6FF",
backgroundDark: "#EFF6FF",
backgroundDarkAccent: "#EFF6FF",
text: {
normal: "#1F2937",
dimmed: "#6B7280",
secondary: "#1F2937",
secondaryDimmed: "#6B7280",
accent: "#1F2937",
accentDimmed: "#6B7280",
},
link: "#0066cc", // blue
warning: "yellow",
error: "red",
success: "green",
});
export const vars = { ...app, colors };
export const vars = { ...app };

View File

@ -0,0 +1,36 @@
// vite.config.ts
import { defineConfig } from "vite";
import eslint from "vite-plugin-eslint";
import react from "@vitejs/plugin-react";
import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin";
import path from "path";
var __vite_injected_original_dirname = "C:\\Users\\KC\\stable-diffusion-ui-react\\ui\\frontend\\build_src";
var vite_config_default = defineConfig({
resolve: {
alias: {
"@stores": path.resolve(__vite_injected_original_dirname, "./src/stores")
}
},
plugins: [
eslint(),
react(),
vanillaExtractPlugin({})
],
server: {
port: 9001
},
build: {
outDir: "../dist",
rollupOptions: {
output: {
entryFileNames: `[name].js`,
chunkFileNames: `[name].js`,
assetFileNames: `[name].[ext]`
}
}
}
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFxLQ1xcXFxzdGFibGUtZGlmZnVzaW9uLXVpLXJlYWN0XFxcXHVpXFxcXGZyb250ZW5kXFxcXGJ1aWxkX3NyY1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiQzpcXFxcVXNlcnNcXFxcS0NcXFxcc3RhYmxlLWRpZmZ1c2lvbi11aS1yZWFjdFxcXFx1aVxcXFxmcm9udGVuZFxcXFxidWlsZF9zcmNcXFxcdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0M6L1VzZXJzL0tDL3N0YWJsZS1kaWZmdXNpb24tdWktcmVhY3QvdWkvZnJvbnRlbmQvYnVpbGRfc3JjL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCBlc2xpbnQgZnJvbSBcInZpdGUtcGx1Z2luLWVzbGludFwiO1xuaW1wb3J0IHJlYWN0IGZyb20gXCJAdml0ZWpzL3BsdWdpbi1yZWFjdFwiO1xuaW1wb3J0IHsgdmFuaWxsYUV4dHJhY3RQbHVnaW4gfSBmcm9tIFwiQHZhbmlsbGEtZXh0cmFjdC92aXRlLXBsdWdpblwiO1xuXG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgLy8gVE9ETyBmaWd1cmUgb3V0IHdoeSB2cyBjb2RlIGNvbXBsYWlucyBhYm91dCB0aGlzIGV2ZW4gdGhvdWdoIGl0IHdvcmtzXG4gICAgICBcIkBzdG9yZXNcIjogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgXCIuL3NyYy9zdG9yZXNcIiksXG4gICAgICAvLyBUT0RPIC0gYWRkIG1vcmUgYWxpYXNlc1xuICAgIH0sXG4gIH0sXG5cbiAgcGx1Z2luczogW1xuICAgIGVzbGludCgpLFxuICAgIHJlYWN0KCksXG4gICAgdmFuaWxsYUV4dHJhY3RQbHVnaW4oe1xuICAgICAgLy8gY29uZmlndXJhdGlvblxuICAgIH0pLFxuICBdLFxuXG4gIHNlcnZlcjoge1xuICAgIHBvcnQ6IDkwMDEsXG4gIH0sXG5cbiAgYnVpbGQ6IHtcbiAgICAvLyBtYWtlIHN1cmUgZXZlcnl0aGlnbiBpcyBpbiB0aGUgc2FtZSBkaXJlY3RvcnlcbiAgICBvdXREaXI6IFwiLi4vZGlzdFwiLFxuICAgIHJvbGx1cE9wdGlvbnM6IHtcbiAgICAgIG91dHB1dDoge1xuICAgICAgICAvLyBkb250IGhhc2ggdGhlIGZpbGUgbmFtZXNcbiAgICAgICAgLy8gbWF5YmUgb25jZSB3ZSB1cGRhdGUgdGhlIHB5dGhvbiBzZXJ2ZXI/XG4gICAgICAgIGVudHJ5RmlsZU5hbWVzOiBgW25hbWVdLmpzYCxcbiAgICAgICAgY2h1bmtGaWxlTmFtZXM6IGBbbmFtZV0uanNgLFxuICAgICAgICBhc3NldEZpbGVOYW1lczogYFtuYW1lXS5bZXh0XWAsXG4gICAgICB9LFxuICAgIH0sXG4gIH0sXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBaVgsU0FBUyxvQkFBb0I7QUFDOVksT0FBTyxZQUFZO0FBQ25CLE9BQU8sV0FBVztBQUNsQixTQUFTLDRCQUE0QjtBQUVyQyxPQUFPLFVBQVU7QUFMakIsSUFBTSxtQ0FBbUM7QUFPekMsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsU0FBUztBQUFBLElBQ1AsT0FBTztBQUFBLE1BRUwsV0FBVyxLQUFLLFFBQVEsa0NBQVcsY0FBYztBQUFBLElBRW5EO0FBQUEsRUFDRjtBQUFBLEVBRUEsU0FBUztBQUFBLElBQ1AsT0FBTztBQUFBLElBQ1AsTUFBTTtBQUFBLElBQ04scUJBQXFCLENBRXJCLENBQUM7QUFBQSxFQUNIO0FBQUEsRUFFQSxRQUFRO0FBQUEsSUFDTixNQUFNO0FBQUEsRUFDUjtBQUFBLEVBRUEsT0FBTztBQUFBLElBRUwsUUFBUTtBQUFBLElBQ1IsZUFBZTtBQUFBLE1BQ2IsUUFBUTtBQUFBLFFBR04sZ0JBQWdCO0FBQUEsUUFDaEIsZ0JBQWdCO0FBQUEsUUFDaEIsZ0JBQWdCO0FBQUEsTUFDbEI7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long