mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2024-11-22 00:03:20 +01:00
Merge pull request #275 from caranicas/react-base-tag-upgrade
React base Big Update
This commit is contained in:
commit
e0c0935d3a
11
ui/frontend/build_src/package-lock.json
generated
11
ui/frontend/build_src/package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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;
|
||||
};
|
140
ui/frontend/build_src/src/components/_recipes/button.css.ts
Normal file
140
ui/frontend/build_src/src/components/_recipes/button.css.ts
Normal 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",
|
||||
},
|
||||
|
||||
});
|
51
ui/frontend/build_src/src/components/_recipes/card.css.ts
Normal file
51
ui/frontend/build_src/src/components/_recipes/card.css.ts
Normal 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,
|
||||
},
|
||||
});
|
||||
|
||||
|
24
ui/frontend/build_src/src/components/_recipes/index.css.ts
Normal file
24
ui/frontend/build_src/src/components/_recipes/index.css.ts
Normal 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,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
}]);
|
||||
|
||||
|
@ -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({
|
||||
});
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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",
|
||||
});
|
||||
|
@ -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',
|
||||
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
@ -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',
|
||||
// });
|
@ -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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
);
|
||||
}
|
@ -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>
|
@ -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>
|
||||
);
|
||||
}
|
@ -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",
|
||||
});
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
@ -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',
|
||||
}]);
|
@ -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>}
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>;
|
||||
}
|
@ -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,
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
});
|
||||
|
@ -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 && (
|
||||
<>
|
||||
|
@ -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 >
|
||||
);
|
||||
}
|
||||
|
@ -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 && (
|
||||
<>
|
||||
|
@ -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 && (
|
||||
<>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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'
|
||||
});
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
}]);
|
@ -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',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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 >
|
||||
);
|
||||
}
|
@ -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,
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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",
|
||||
});
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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({
|
@ -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",
|
||||
|
@ -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`, {
|
||||
|
@ -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} />
|
||||
|
@ -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 };
|
@ -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}>
|
||||
|
@ -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%',
|
@ -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>
|
@ -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>
|
||||
);
|
||||
}
|
@ -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',
|
||||
},
|
||||
])
|
@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import { currentInfoMain } from "./currentInfo.css";
|
||||
export default function CurrentInfo() {
|
||||
return <div className={
|
||||
currentInfoMain
|
||||
}> current info</div>;
|
||||
}
|
@ -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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
);
|
||||
}
|
@ -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',
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
|
@ -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})`,
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
@ -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,
|
||||
});
|
@ -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>
|
||||
);
|
||||
}
|
@ -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",
|
||||
});
|
@ -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({
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Settings({ className }: { className: any }) {
|
||||
export default function Settings() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Settings</h1>
|
||||
|
@ -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);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
@ -27,7 +27,6 @@ interface ImageFetchingState {
|
||||
setStartTime: () => void;
|
||||
setNowTime: () => void;
|
||||
resetForFetching: () => void;
|
||||
|
||||
}
|
||||
|
||||
export const useImageFetching = create<ImageFetchingState>((set) => ({
|
||||
|
@ -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 = [];
|
||||
})
|
||||
);
|
||||
},
|
||||
}));
|
160
ui/frontend/build_src/src/stores/requestQueueStore.ts
Normal file
160
ui/frontend/build_src/src/stores/requestQueueStore.ts
Normal 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 = [];
|
||||
})
|
||||
);
|
||||
},
|
||||
}));
|
@ -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",
|
||||
});
|
@ -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' },
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
@ -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 };
|
||||
|
@ -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==
|
2
ui/frontend/dist/index.css
vendored
2
ui/frontend/dist/index.css
vendored
File diff suppressed because one or more lines are too long
44
ui/frontend/dist/index.js
vendored
44
ui/frontend/dist/index.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user