feat(settings): add remove animation settings to save cpu usage [#171,#161]

pull/240/head
canisminor1990 2023-06-29 01:24:14 +08:00
parent 163f445e0c
commit 61a5077b44
16 changed files with 567 additions and 449 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,25 +1,18 @@
import { createStyles } from 'antd-style';
import { rgba } from 'polished';
export const useStyles = createStyles(({ css, token, stylish, cx }) => ({
export const useStyles = createStyles(({ css, token }) => ({
body: css`
overflow-x: hidden;
overflow-y: auto;
flex: 1;
padding: 16px;
`,
container: cx(
stylish.blur,
css`
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
background: ${rgba(token.colorBgLayout, 0.8)};
`,
),
container: css`
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
`,
footer: css`
display: flex;
flex: 0;

View File

@ -1,3 +1,4 @@
import { useResponsive } from 'antd-style';
import isEqual from 'fast-deep-equal';
import { memo, useEffect, useRef } from 'react';
@ -11,10 +12,17 @@ import { useStyles } from './style';
const Content = memo<DivProps>(({ className, ...props }) => {
const mainReference = useRef<HTMLDivElement>(null);
const setting = useAppStore((st) => st.setting, isEqual);
const { mobile } = useResponsive();
const { cx, styles } = useStyles({
isPromptResizable: setting.promptTextarea === 'resizable',
isPromptResizable: setting.promptTextareaType === 'resizable',
layoutSplitPreview: setting.layoutSplitPreview,
});
const previewStyle = usePreviewStyles({ isPrimaryColor: Boolean(setting.primaryColor) });
const previewStyle = usePreviewStyles({
isPrimaryColor: Boolean(setting.primaryColor),
liteAnimation: setting.liteAnimation,
});
const useDragablePanel = !setting.layoutSplitPreview && mobile === false;
useEffect(() => {
// Content
@ -23,14 +31,29 @@ const Content = memo<DivProps>(({ className, ...props }) => {
mainReference.current?.append(main);
}
// remove prompt scroll-hide
for (const textarea of gradioApp().querySelectorAll(`[id$="_prompt_container"] textarea`)) {
textarea.classList.remove('scroll-hide');
const textares = gradioApp().querySelectorAll(
`[id$="_prompt_container"] textarea`,
) as NodeListOf<HTMLTextAreaElement>;
if (textares) {
for (const textarea of textares) {
textarea.classList.remove('scroll-hide');
textarea.style.height = 'auto';
}
}
// textarea
const interrogate = gradioApp().querySelector(
'#img2img_toprow .interrogate-col',
) as HTMLDivElement;
const actions = gradioApp().querySelector('#img2img_actions_column') as HTMLDivElement;
if (interrogate && actions) {
actions.append(interrogate);
}
}, []);
useEffect(() => {
if (!setting.layoutSplitPreview) draggablePanel();
}, [setting.layoutSplitPreview]);
if (useDragablePanel) draggablePanel();
}, [useDragablePanel]);
return (
<div
@ -40,7 +63,7 @@ const Content = memo<DivProps>(({ className, ...props }) => {
styles.text2img,
styles.autocompleteResults,
setting.layoutSplitPreview ? styles.splitView : styles.draggableContainer,
!setting.layoutSplitPreview && previewStyle.styles.preview,
useDragablePanel && previewStyle.styles.preview,
className,
)}
ref={mainReference}

View File

@ -1,9 +1,15 @@
import { createStyles } from 'antd-style';
const MIN_HEIGHT = 88;
const TEXT2IMG_PROMPT_HEIGHT = 74;
const IMG2IMG_PROMPT_HEIGHT = 98;
export const useStyles = createStyles(
({ css, token, stylish, isDarkMode }, { isPromptResizable }: { isPromptResizable: boolean }) => {
(
{ css, token, stylish, isDarkMode },
{
isPromptResizable,
layoutSplitPreview,
}: { isPromptResizable: boolean; layoutSplitPreview: boolean },
) => {
return {
autocompleteResults: css`
.autocompleteResults {
@ -30,7 +36,7 @@ export const useStyles = createStyles(
container: css`
position: relative;
flex: 1;
min-width: 200px;
min-width: ${layoutSplitPreview ? '200px' : '0'};
.app {
padding: 0 !important;
@ -111,6 +117,11 @@ export const useStyles = createStyles(
max-height: 44px !important;
}
#img2img_toprow .interrogate-col {
flex-flow: row wrap;
min-width: 100% !important;
}
[id$='img_settings'],
.gradio-column.compact {
display: flex !important;
@ -179,6 +190,8 @@ export const useStyles = createStyles(
#tab_txt2img,
#tab_img2img {
[id$='_settings'] {
min-width: 0 !important;
div.svelte-15lo0d8 > *,
div.svelte-15lo0d8 > .form > * {
flex: 1;
@ -216,17 +229,33 @@ export const useStyles = createStyles(
}
`,
textares: css`
#text2img_prompt,
#text2img_neg_prompt {
textarea {
min-height: ${TEXT2IMG_PROMPT_HEIGHT}px;
max-height: ${isPromptResizable ? 'unset' : `${TEXT2IMG_PROMPT_HEIGHT}px`};
}
}
#img2img_prompt,
#img2img_neg_prompt {
textarea {
min-height: ${IMG2IMG_PROMPT_HEIGHT}px;
max-height: ${isPromptResizable ? 'unset' : `${IMG2IMG_PROMPT_HEIGHT}px`};
}
}
[id$='2img_prompt'],
[id$='2img_neg_prompt'] {
textarea {
resize: vertical;
resize: ${isPromptResizable ? 'vertical' : 'none'};
overflow-y: auto;
min-height: ${isPromptResizable ? 'unset' : `${MIN_HEIGHT}px`};
padding: 8px;
font-family: ${token.fontFamilyCode};
font-size: 13px;
text-overflow: ellipsis;
vertical-align: bottom;
@ -251,12 +280,15 @@ export const useStyles = createStyles(
}
.block.token-counter {
right: 4px;
scale: 0.8;
background: ${token.colorBgContainer} !important;
> .translucent {
display: none;
}
span {
${stylish.blur};
display: inline-block;
font-family: ${token.fontFamilyCode};
}

View File

@ -19,7 +19,7 @@ const ExtraNetworkSidebar = memo<ExtraNetworkSidebarProps>(({ headerHeight }) =>
const setting = useAppStore((st) => st.setting, isEqual);
const [expand, setExpand] = useState<boolean>(mobile ? false : setting.extraNetworkSidebarExpand);
const [pin, setPin] = useState<boolean>(setting.extraNetworkFixedMode === 'fixed');
const { styles } = useStyles({ headerHeight });
const { styles, theme } = useStyles({ headerHeight });
useEffect(() => {
const index2indexExtraNetworkButton = gradioApp().querySelector(
@ -41,18 +41,23 @@ const ExtraNetworkSidebar = memo<ExtraNetworkSidebarProps>(({ headerHeight }) =>
if (mobile) setExpand(false);
}, [mobile]);
const mode = mobile ? 'fixed' : pin ? 'fixed' : 'float';
return (
<DraggablePanel
defaultSize={{ width: setting.extraNetworkSidebarWidth }}
expand={expand}
minWidth={260}
mode={mobile ? 'fixed' : pin ? 'fixed' : 'float'}
mode={mode}
onExpandChange={setExpand}
pin={pin}
placement="right"
>
<LayoutSidebarInner>
<SidebarContainer className={styles.container}>
<SidebarContainer
className={styles.container}
style={mode === 'float' ? { background: theme.colorBgContainer } : {}}
>
<SidebarHeader
pin={pin}
position="right"

View File

@ -15,7 +15,11 @@ export interface PreviewProps extends DivProps {
const Preview = memo<PreviewProps>(({ headerHeight }) => {
const currentTab = useAppStore((st) => st.currentTab, shallow);
const setting = useAppStore((st) => st.setting, isEqual);
const { cx, styles } = useStyles({ headerHeight, isPrimaryColor: Boolean(setting.primaryColor) });
const { cx, styles } = useStyles({
headerHeight,
isPrimaryColor: Boolean(setting.primaryColor),
liteAnimation: setting.liteAnimation,
});
const txt2imgReference = useRef<HTMLDivElement>(null);
const img2imgReference = useRef<HTMLDivElement>(null);
const extras2imgReference = useRef<HTMLDivElement>(null);

View File

@ -4,7 +4,11 @@ import { adjustHue, rgba } from 'polished';
export const useStyles = createStyles(
(
{ css, token, stylish },
{ headerHeight = 64, isPrimaryColor }: { headerHeight?: number; isPrimaryColor?: boolean },
{
headerHeight = 64,
isPrimaryColor,
liteAnimation,
}: { headerHeight?: number; isPrimaryColor?: boolean; liteAnimation?: boolean },
) => {
const primaryGradient =
isPrimaryColor &&
@ -50,28 +54,11 @@ export const useStyles = createStyles(
&.svelte-1p4r00v {
padding: 0;
}
&[id$='_generate'] {
overflow: unset !important;
&::before {
${stylish.gradientAnimation};
${primaryGradient};
position: absolute;
z-index: -1;
inset: 0;
content: '';
filter: blur(8px);
opacity: 0.5;
}
}
}
.progressDiv > .progress {
${stylish.gradientAnimation};
${primaryGradient};
${!liteAnimation && stylish.gradientAnimation};
${!liteAnimation && primaryGradient};
}
[id$='_results'] {

View File

@ -18,18 +18,20 @@ const QuickSettingSidebar = memo<QuickSettingSidebarProps>(({ headerHeight }) =>
const setting = useAppStore((st) => st.setting, isEqual);
const [expand, setExpand] = useState<boolean>(mobile ? false : setting.sidebarExpand);
const [pin, setPin] = useState<boolean>(setting.sidebarFixedMode === 'fixed');
const { styles } = useStyles({ headerHeight });
const { styles, theme } = useStyles({ headerHeight });
useEffect(() => {
if (mobile) setExpand(false);
}, [mobile]);
const mode = mobile ? 'fixed' : pin ? 'fixed' : 'float';
return (
<DraggablePanel
defaultSize={{ width: setting.sidebarWidth }}
expand={expand}
minWidth={200}
mode={mobile ? 'fixed' : pin ? 'fixed' : 'float'}
mode={mode}
onExpandChange={setExpand}
pin={pin}
placement="left"
@ -39,7 +41,10 @@ const QuickSettingSidebar = memo<QuickSettingSidebarProps>(({ headerHeight }) =>
}}
>
<LayoutSidebarInner>
<SidebarContainer className={styles.container}>
<SidebarContainer
className={styles.container}
style={mode === 'float' ? { background: theme.colorBgContainer } : {}}
>
<SidebarHeader
pin={pin}
position="left"

View File

@ -1,71 +1,68 @@
import { createStyles } from 'antd-style';
export const useStyles = createStyles(
({ css, cx, stylish }, { headerHeight = 64 }: { headerHeight?: number }) => ({
container: cx(
stylish.blur,
css`
height: calc(100vh - ${headerHeight}px);
({ css }, { headerHeight = 64 }: { headerHeight?: number }) => ({
container: css`
height: calc(100vh - ${headerHeight}px);
ul.options {
li {
max-width: 240px !important;
}
ul.options {
li {
max-width: 240px !important;
}
}
#quicksettings {
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: stretch;
width: 100%;
> * {
flex: 1;
width: 100% !important;
min-width: unset !important;
max-width: unset !important;
margin: 0;
padding: 0;
}
#quicksettings {
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: stretch;
.head > label {
min-width: unset;
max-width: 60%;
margin-right: 12px;
}
input[type='color'] {
width: 100%;
> * {
flex: 1;
width: 100% !important;
min-width: unset !important;
max-width: unset !important;
margin: 0;
padding: 0;
}
.head > label {
min-width: unset;
max-width: 60%;
margin-right: 12px;
}
input[type='color'] {
width: 100%;
}
input[type='number'],
textarea {
resize: none;
box-sizing: border-box;
height: 28px !important;
padding: 4px !important;
}
textarea {
width: 100%;
}
span {
overflow: hidden;
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
}
.dropdown-arrow {
min-width: 16px;
min-height: 16px;
}
}
`,
),
input[type='number'],
textarea {
resize: none;
box-sizing: border-box;
height: 28px !important;
padding: 4px !important;
}
textarea {
width: 100%;
}
span {
overflow: hidden;
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
}
.dropdown-arrow {
min-width: 16px;
min-height: 16px;
}
}
`,
}),
);

View File

@ -36,7 +36,7 @@ const Index = memo(() => {
<Header />
</LayoutHeader>
<LayoutMain>
<div className={styles.background} />
{!setting.liteAnimation && <div className={styles.background} />}
<LayoutSidebar className={styles.sidebar} headerHeight={HEADER_HEIGHT} style={{ flex: 0 }}>
<QuickSettingSidebar headerHeight={HEADER_HEIGHT} />
</LayoutSidebar>

View File

@ -10,11 +10,14 @@ import { useStyles } from './style';
const Loading = memo(() => {
const setting = useAppStore((st) => st.setting, isEqual);
const { styles } = useStyles(Boolean(setting.primaryColor));
const { styles } = useStyles({
isPrimaryColor: Boolean(setting.primaryColor),
liteAnimation: setting.liteAnimation,
});
return (
<section className={styles.container}>
<div className={styles.canvas} />
{!setting.liteAnimation && <div className={styles.canvas} />}
<div className={styles.inner}>
<Logo size={48} />
<Icon className={styles.icon} icon={Loader2} size={{ fontSize: 32 }} spin />

View File

@ -1,62 +1,67 @@
import { createStyles } from 'antd-style';
import { adjustHue, rgba } from 'polished';
export const useStyles = createStyles(({ css, stylish, cx, token }, isPrimaryColor?: boolean) => ({
canvas: cx(
stylish.gradientAnimation,
isPrimaryColor &&
export const useStyles = createStyles(
(
{ css, stylish, cx, token },
{ isPrimaryColor, liteAnimation }: { isPrimaryColor?: boolean; liteAnimation?: boolean },
) => ({
canvas: cx(
stylish.gradientAnimation,
isPrimaryColor &&
css`
background-image: linear-gradient(
-45deg,
${token.colorPrimary},
${adjustHue(45, token.colorPrimary)},
${token.colorPrimary},
${adjustHue(-45, token.colorPrimary)}
);
`,
css`
background-image: linear-gradient(
-45deg,
${token.colorPrimary},
${adjustHue(45, token.colorPrimary)},
${token.colorPrimary},
${adjustHue(-45, token.colorPrimary)}
);
pointer-events: none;
position: absolute;
z-index: 10;
top: -250px;
left: 50%;
transform: translateX(-50%) scale(1.5);
width: 75vw;
height: 400px;
opacity: 0.2;
filter: blur(100px);
`,
css`
pointer-events: none;
),
container: cx(
!liteAnimation && stylish.blur,
css`
position: fixed;
z-index: 9999;
inset: 0;
position: absolute;
z-index: 10;
top: -250px;
left: 50%;
transform: translateX(-50%) scale(1.5);
display: flex;
align-items: center;
justify-content: center;
width: 75vw;
height: 400px;
width: 100vw;
height: 100vh;
opacity: 0.2;
filter: blur(100px);
background: ${liteAnimation ? token.colorBgLayout : rgba(token.colorBgLayout, 0.5)};
`,
),
icon: css`
color: ${token.colorPrimary};
`,
),
container: cx(
stylish.blur,
css`
position: fixed;
z-index: 9999;
inset: 0;
inner: css`
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
background: ${rgba(token.colorBgLayout, 0.5)};
width: min(50%, 580px);
`,
),
icon: css`
color: ${token.colorPrimary};
`,
inner: css`
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
justify-content: center;
width: min(50%, 580px);
`,
}));
}),
);

View File

@ -0,0 +1,20 @@
import { memo } from 'react';
import { useStyles } from './style';
export interface FormTitleProps {
desc: string;
title: string;
}
const FormTitle = memo<FormTitleProps>(({ title, desc }) => {
const { styles } = useStyles();
return (
<div className={styles.formTitle}>
<div>{title}</div>
<small>{desc}</small>
</div>
);
});
export default FormTitle;

View File

@ -9,6 +9,7 @@ import { CustomLogo } from '@/components';
import { NeutralColor, PrimaryColor, WebuiSetting, defaultSetting, useAppStore } from '@/store';
import { neutralColorScales } from '@/styles/neutralColors';
import FormTitle from './FormTitle';
import { useStyles } from './style';
const { Item } = Form;
@ -80,6 +81,7 @@ const SettingForm = memo(() => {
return (
<Form
className={styles.form}
colon={false}
initialValues={setting}
layout="horizontal"
onFinish={onFinish}
@ -90,13 +92,17 @@ const SettingForm = memo(() => {
<Icon icon={TextCursorInput} />
Promot Textarea
</div>
<Item className={styles.item} label="Display mode" name="promotTextarea">
<Item
className={styles.item}
label={<FormTitle desc="Fixed height / Auto height" title="Display mode" />}
name="promotTextarea"
>
<Segmented options={['scroll', 'resizable']} />
</Item>
<Divider style={{ margin: 0 }} />
<Item
className={styles.item}
label="Prompt editor"
label={<FormTitle desc="Top in left sidebar" title="Prompt editor" />}
name="promptEditor"
valuePropName="checked"
>
@ -188,6 +194,15 @@ const SettingForm = memo(() => {
<Icon icon={Palette} />
Theme
</div>
<Item
className={styles.item}
label={<FormTitle desc="Save cpu usage" title="Remove animation" />}
name="liteAnimation"
valuePropName="checked"
>
<Switch />
</Item>
<Divider style={{ margin: 0 }} />
<Item className={styles.item} label="Primary color">
<Swatches
activeColor={primaryColor ? colors[primaryColor] : undefined}

View File

@ -15,6 +15,18 @@ export const useStyles = createStyles(({ css, token }) => ({
margin: 0 !important;
}
`,
formTitle: css`
text-align: left;
> div {
line-height: 1;
}
> small {
line-height: 1;
color: ${token.colorTextDescription};
}
`,
group: css`
overflow: hidden;
background: ${token.colorFillQuaternary};

View File

@ -27,13 +27,14 @@ export interface WebuiSetting {
extraNetworkSidebarWidth: number;
layoutHideFooter: boolean;
layoutSplitPreview: boolean;
liteAnimation: boolean;
logoCustomTitle: string | undefined;
logoCustomUrl: string | undefined;
logoType: 'lobe' | 'kitchen' | 'custom';
neutralColor: NeutralColor | undefined;
primaryColor: PrimaryColor | undefined;
promptEditor: boolean;
promptTextarea: 'scroll' | 'resizable';
promptTextareaType: 'scroll' | 'resizable';
sidebarExpand: boolean;
sidebarFixedMode: 'fixed' | 'float';
sidebarWidth: number;
@ -48,13 +49,14 @@ export const defaultSetting: WebuiSetting = {
extraNetworkSidebarWidth: 340,
layoutHideFooter: false,
layoutSplitPreview: false,
liteAnimation: false,
logoCustomTitle: '',
logoCustomUrl: '',
logoType: 'lobe',
neutralColor: undefined,
primaryColor: undefined,
promptEditor: true,
promptTextarea: 'scroll',
promptTextareaType: 'resizable',
sidebarExpand: true,
sidebarFixedMode: 'fixed',
sidebarWidth: 280,