👷 ci(lint): update lint config and code style
parent
56cf8f327b
commit
e9e51e66b2
|
|
@ -1,13 +1,16 @@
|
||||||
# http://editorconfig.org
|
# http://editorconfig.org
|
||||||
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
max_line_length = 100
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
|
||||||
13
.eslintrc.js
13
.eslintrc.js
|
|
@ -1 +1,12 @@
|
||||||
module.exports = require('@lobehub/lint').eslint;
|
module.exports = {
|
||||||
|
...require('@lobehub/lint').eslint,
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*.ts', '*.tsx'],
|
||||||
|
rules: {
|
||||||
|
'no-undef': 0,
|
||||||
|
'unicorn/prefer-add-event-listener': 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,11 @@ module.exports = {
|
||||||
rules: {
|
rules: {
|
||||||
'selector-class-pattern': null,
|
'selector-class-pattern': null,
|
||||||
'selector-id-pattern': null,
|
'selector-id-pattern': null,
|
||||||
|
'no-descending-specificity': [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,9 +1,9 @@
|
||||||
import { FloatButton } from 'antd';
|
import {FloatButton} from 'antd';
|
||||||
import { type ReactNode, memo, useRef } from 'react';
|
import {type ReactNode, memo, useRef} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { shallow } from 'zustand/shallow';
|
import {shallow} from 'zustand/shallow';
|
||||||
|
|
||||||
import { useAppStore } from '@/store';
|
import {useAppStore} from '@/store';
|
||||||
|
|
||||||
const ContentView = styled.div<{ isPromptResizable: boolean }>`
|
const ContentView = styled.div<{ isPromptResizable: boolean }>`
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
@ -11,11 +11,11 @@ const ContentView = styled.div<{ isPromptResizable: boolean }>`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
[id$='2img_prompt'] textarea {
|
[id$='2img_prompt'] textarea {
|
||||||
max-height: ${({ isPromptResizable }) => (isPromptResizable ? 'unset' : '84px')};
|
max-height: ${({isPromptResizable}) => (isPromptResizable ? 'unset' : '84px')};
|
||||||
}
|
}
|
||||||
|
|
||||||
[id$='2img_neg_prompt'] textarea {
|
[id$='2img_neg_prompt'] textarea {
|
||||||
max-height: ${({ isPromptResizable }) => (isPromptResizable ? 'unset' : '84px')};
|
max-height: ${({isPromptResizable}) => (isPromptResizable ? 'unset' : '84px')};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -24,16 +24,16 @@ interface ContentProps {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Content = memo<ContentProps>(({ children }) => {
|
const Content = memo<ContentProps>(({children}) => {
|
||||||
const ref: any = useRef(null);
|
const reference: any = useRef(null);
|
||||||
const [setting] = useAppStore((st) => [st.setting], shallow);
|
const [setting] = useAppStore((st) => [st.setting], shallow);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentView isPromptResizable={setting.promotTextarea === 'resizable'} ref={ref}>
|
<ContentView isPromptResizable={setting.promotTextarea === 'resizable'} ref={reference}>
|
||||||
{children}
|
{children}
|
||||||
<FloatButton.BackTop target={() => ref.current} />
|
<FloatButton.BackTop target={() => reference.current} />
|
||||||
</ContentView>
|
</ContentView>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Content;
|
export default Content;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import { useHover } from 'ahooks';
|
import {useHover} from 'ahooks';
|
||||||
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from 'lucide-react';
|
import {ChevronDown, ChevronLeft, ChevronRight, ChevronUp} from 'lucide-react';
|
||||||
import type { Enable, NumberSize, Size } from 're-resizable';
|
import type {Enable, NumberSize, Size} from 're-resizable';
|
||||||
import { HandleClassName, Resizable } from 're-resizable';
|
import {HandleClassName, Resizable} from 're-resizable';
|
||||||
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
import {memo, useEffect, useMemo, useRef, useState} from 'react';
|
||||||
import { Center } from 'react-layout-kit';
|
import {Center} from 'react-layout-kit';
|
||||||
import type { Props as RndProps } from 'react-rnd';
|
import type {Props as RndProps} from 'react-rnd';
|
||||||
import useControlledState from 'use-merge-value';
|
import useControlledState from 'use-merge-value';
|
||||||
|
|
||||||
import type { DivProps } from '@/types';
|
import type {DivProps} from '@/types';
|
||||||
|
|
||||||
import { useStyle } from './style';
|
import {useStyle} from './style';
|
||||||
import { revesePlacement } from './utils';
|
import {revesePlacement} from './utils';
|
||||||
|
|
||||||
const DEFAULT_HEIGHT = 180;
|
const DEFAULT_HEIGHT = 180;
|
||||||
const DEFAULT_WIDTH = 280;
|
const DEFAULT_WIDTH = 280;
|
||||||
|
|
@ -38,186 +38,191 @@ export interface DraggablePanelProps extends DivProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DraggablePanel = memo<DraggablePanelProps>(
|
const DraggablePanel = memo<DraggablePanelProps>(
|
||||||
({
|
({
|
||||||
pin = 'true',
|
pin = 'true',
|
||||||
mode = 'fixed',
|
mode = 'fixed',
|
||||||
children,
|
children,
|
||||||
placement = 'right',
|
placement = 'right',
|
||||||
resize,
|
resize,
|
||||||
style,
|
style,
|
||||||
size,
|
size,
|
||||||
defaultSize: customizeDefaultSize,
|
defaultSize: customizeDefaultSize,
|
||||||
minWidth,
|
minWidth,
|
||||||
minHeight,
|
minHeight,
|
||||||
onSizeChange,
|
onSizeChange,
|
||||||
onSizeDragging,
|
onSizeDragging,
|
||||||
expandable = true,
|
expandable = true,
|
||||||
expand,
|
expand,
|
||||||
defaultExpand = true,
|
defaultExpand = true,
|
||||||
onExpandChange,
|
onExpandChange,
|
||||||
className,
|
className,
|
||||||
showHandlerWhenUnexpand,
|
showHandlerWhenUnexpand,
|
||||||
destroyOnClose,
|
destroyOnClose,
|
||||||
hanlderStyle,
|
hanlderStyle,
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useRef(null);
|
const reference = useRef(null);
|
||||||
const isHovering = useHover(ref);
|
const isHovering = useHover(reference);
|
||||||
const isVertical = placement === 'top' || placement === 'bottom';
|
const isVertical = placement === 'top' || placement === 'bottom';
|
||||||
|
|
||||||
const { styles, cx } = useStyle('draggable-panel');
|
const {styles, cx} = useStyle('draggable-panel');
|
||||||
|
|
||||||
const [isExpand, setIsExpand] = useControlledState(defaultExpand, {
|
const [isExpand, setIsExpand] = useControlledState(defaultExpand, {
|
||||||
value: expand,
|
onChange: onExpandChange,
|
||||||
onChange: onExpandChange,
|
value: expand,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pin) return;
|
if (pin) return;
|
||||||
if (isHovering && !isExpand) {
|
if (isHovering && !isExpand) {
|
||||||
setIsExpand(true);
|
setIsExpand(true);
|
||||||
} else if (!isHovering && isExpand) {
|
} else if (!isHovering && isExpand) {
|
||||||
setIsExpand(false);
|
setIsExpand(false);
|
||||||
}
|
}
|
||||||
}, [pin, isHovering, isExpand]);
|
}, [pin, isHovering, isExpand]);
|
||||||
|
|
||||||
const [showExpand, setShowExpand] = useState(true);
|
const [showExpand, setShowExpand] = useState(true);
|
||||||
|
|
||||||
const canResizing = resize !== false && isExpand;
|
const canResizing = resize !== false && isExpand;
|
||||||
|
|
||||||
const resizeHandleClassNames: HandleClassName = useMemo(() => {
|
const resizeHandleClassNames: HandleClassName = useMemo(() => {
|
||||||
if (!canResizing) return {};
|
if (!canResizing) return {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[revesePlacement(placement)]: styles[`${revesePlacement(placement)}Handle`],
|
[revesePlacement(placement)]: styles[`${revesePlacement(placement)}Handle`],
|
||||||
};
|
};
|
||||||
}, [canResizing, placement]);
|
}, [canResizing, placement]);
|
||||||
|
|
||||||
const resizing = {
|
const resizing = {
|
||||||
top: false,
|
bottom: false,
|
||||||
bottom: false,
|
bottomLeft: false,
|
||||||
right: false,
|
bottomRight: false,
|
||||||
left: false,
|
left: false,
|
||||||
topRight: false,
|
right: false,
|
||||||
bottomRight: false,
|
top: false,
|
||||||
bottomLeft: false,
|
topLeft: false,
|
||||||
topLeft: false,
|
topRight: false,
|
||||||
[revesePlacement(placement)]: true,
|
[revesePlacement(placement)]: true,
|
||||||
...(resize as Enable),
|
...(resize as Enable),
|
||||||
};
|
|
||||||
|
|
||||||
const defaultSize: Size = useMemo(() => {
|
|
||||||
if (isVertical)
|
|
||||||
return {
|
|
||||||
width: '100%',
|
|
||||||
height: DEFAULT_HEIGHT,
|
|
||||||
...customizeDefaultSize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
const defaultSize: Size = useMemo(() => {
|
||||||
width: DEFAULT_WIDTH,
|
if (isVertical) {
|
||||||
height: '100%',
|
return {
|
||||||
...customizeDefaultSize,
|
height: DEFAULT_HEIGHT,
|
||||||
};
|
width: '100%',
|
||||||
}, [isVertical]);
|
...customizeDefaultSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const sizeProps = isExpand
|
return {
|
||||||
? {
|
height: '100%',
|
||||||
minWidth: typeof minWidth === 'number' ? Math.max(minWidth, 0) : 280,
|
width: DEFAULT_WIDTH,
|
||||||
minHeight: typeof minHeight === 'number' ? Math.max(minHeight, 0) : undefined,
|
...customizeDefaultSize,
|
||||||
defaultSize,
|
};
|
||||||
size: size as Size,
|
}, [isVertical]);
|
||||||
}
|
|
||||||
: isVertical
|
|
||||||
? {
|
|
||||||
minHeight: 0,
|
|
||||||
size: { height: 0 },
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
minWidth: 0,
|
|
||||||
size: { width: 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
const { Arrow, className: arrowPlacement } = useMemo(() => {
|
const sizeProps = isExpand ?
|
||||||
switch (placement) {
|
{
|
||||||
case 'top':
|
defaultSize,
|
||||||
return { className: 'Bottom', Arrow: ChevronDown };
|
minHeight: typeof minHeight === 'number' ? Math.max(minHeight, 0) : undefined,
|
||||||
case 'bottom':
|
minWidth: typeof minWidth === 'number' ? Math.max(minWidth, 0) : 280,
|
||||||
return { className: 'Top', Arrow: ChevronUp };
|
size: size as Size,
|
||||||
case 'right':
|
} :
|
||||||
return { className: 'Left', Arrow: ChevronLeft };
|
isVertical ?
|
||||||
case 'left':
|
{
|
||||||
return { className: 'Right', Arrow: ChevronRight };
|
minHeight: 0,
|
||||||
}
|
size: {height: 0},
|
||||||
}, [styles, placement]);
|
} :
|
||||||
|
{
|
||||||
|
minWidth: 0,
|
||||||
|
size: {width: 0},
|
||||||
|
};
|
||||||
|
|
||||||
const handler = (
|
const {Arrow, className: arrowPlacement} = useMemo(() => {
|
||||||
// @ts-ignore
|
switch (placement) {
|
||||||
<Center
|
case 'top': {
|
||||||
// @ts-ignore
|
return {Arrow: ChevronDown, className: 'Bottom'};
|
||||||
className={cx(styles[`toggle${arrowPlacement}`])}
|
}
|
||||||
style={{ opacity: isExpand ? (!pin ? 0 : undefined) : showHandlerWhenUnexpand ? 1 : 0 }}
|
case 'bottom': {
|
||||||
>
|
return {Arrow: ChevronUp, className: 'Top'};
|
||||||
<Center
|
}
|
||||||
onClick={() => {
|
case 'right': {
|
||||||
setIsExpand(!isExpand);
|
return {Arrow: ChevronLeft, className: 'Left'};
|
||||||
}}
|
}
|
||||||
style={hanlderStyle}
|
case 'left': {
|
||||||
>
|
return {Arrow: ChevronRight, className: 'Right'};
|
||||||
<div
|
}
|
||||||
className={styles.handlerIcon}
|
}
|
||||||
style={{ transform: `rotate(${isExpand ? 180 : 0}deg)` }}
|
}, [styles, placement]);
|
||||||
>
|
|
||||||
<Arrow size={16} strokeWidth={1.5} />
|
|
||||||
</div>
|
|
||||||
</Center>
|
|
||||||
</Center>
|
|
||||||
);
|
|
||||||
|
|
||||||
const inner = (
|
const handler = (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
<Resizable
|
<Center
|
||||||
{...sizeProps}
|
// @ts-ignore
|
||||||
className={styles.panel}
|
className={cx(styles[`toggle${arrowPlacement}`])}
|
||||||
enable={canResizing ? (resizing as Enable) : undefined}
|
style={{opacity: isExpand ? (pin ? undefined : 0) : showHandlerWhenUnexpand ? 1 : 0}}
|
||||||
handleClasses={resizeHandleClassNames}
|
>
|
||||||
onResize={(_, direction, ref, delta) => {
|
<Center
|
||||||
onSizeDragging?.(delta, {
|
onClick={() => {
|
||||||
width: ref.style.width,
|
setIsExpand(!isExpand);
|
||||||
height: ref.style.height,
|
}}
|
||||||
});
|
style={hanlderStyle}
|
||||||
}}
|
>
|
||||||
onResizeStart={() => {
|
<div
|
||||||
setShowExpand(false);
|
className={styles.handlerIcon}
|
||||||
}}
|
style={{transform: `rotate(${isExpand ? 180 : 0}deg)`}}
|
||||||
onResizeStop={(e, direction, ref, delta) => {
|
>
|
||||||
setShowExpand(true);
|
<Arrow size={16} strokeWidth={1.5} />
|
||||||
onSizeChange?.(delta, {
|
</div>
|
||||||
width: ref.style.width,
|
</Center>
|
||||||
height: ref.style.height,
|
</Center>
|
||||||
});
|
);
|
||||||
}}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Resizable>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
const inner = (
|
||||||
<div
|
// @ts-ignore
|
||||||
className={cx(
|
<Resizable
|
||||||
styles.container,
|
{...sizeProps}
|
||||||
// @ts-ignore
|
className={styles.panel}
|
||||||
styles[mode === 'fixed' ? 'fixed' : `${placement}Float`],
|
enable={canResizing ? (resizing as Enable) : undefined}
|
||||||
className,
|
handleClasses={resizeHandleClassNames}
|
||||||
)}
|
onResize={(_, direction, reference_, delta) => {
|
||||||
ref={ref}
|
onSizeDragging?.(delta, {
|
||||||
style={{ [`border${arrowPlacement}Width`]: 1 }}
|
height: reference_.style.height,
|
||||||
>
|
width: reference_.style.width,
|
||||||
{expandable && showExpand && handler}
|
});
|
||||||
{destroyOnClose ? isExpand && inner : inner}
|
}}
|
||||||
</div>
|
onResizeStart={() => {
|
||||||
);
|
setShowExpand(false);
|
||||||
},
|
}}
|
||||||
|
onResizeStop={(e, direction, reference_, delta) => {
|
||||||
|
setShowExpand(true);
|
||||||
|
onSizeChange?.(delta, {
|
||||||
|
height: reference_.style.height,
|
||||||
|
width: reference_.style.width,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Resizable>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
styles.container,
|
||||||
|
// @ts-ignore
|
||||||
|
styles[mode === 'fixed' ? 'fixed' : `${placement}Float`],
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
ref={reference}
|
||||||
|
style={{[`border${arrowPlacement}Width`]: 1}}
|
||||||
|
>
|
||||||
|
{expandable && showExpand && handler}
|
||||||
|
{destroyOnClose ? isExpand && inner : inner}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export default DraggablePanel;
|
export default DraggablePanel;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { createStyles, css, cx } from 'antd-style';
|
import {createStyles, css, cx} from 'antd-style';
|
||||||
|
|
||||||
const offset = 17;
|
const offset = 17;
|
||||||
const toggleLength = 40;
|
const toggleLength = 40;
|
||||||
const toggleShort = 16;
|
const toggleShort = 16;
|
||||||
|
|
||||||
export const useStyle = createStyles(({ token }, prefix: string) => {
|
export const useStyle = createStyles(({token}, prefix: string) => {
|
||||||
const commonHandle = css`
|
const commonHandle = css`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
|
@ -23,7 +23,7 @@ export const useStyle = createStyles(({ token }, prefix: string) => {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const commonToggle = css`
|
const commonToggle = css`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -64,15 +64,36 @@ export const useStyle = createStyles(({ token }, prefix: string) => {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const float = css`
|
const float = css`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
container: cx(
|
bottomFloat: cx(
|
||||||
prefix,
|
float,
|
||||||
css`
|
css`
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
bottomHandle: cx(
|
||||||
|
`${prefix}-bottom-handle`,
|
||||||
|
css`
|
||||||
|
${commonHandle};
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
bottom: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
container: cx(
|
||||||
|
prefix,
|
||||||
|
css`
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border: 0 solid ${token.colorBorderSecondary};
|
border: 0 solid ${token.colorBorderSecondary};
|
||||||
|
|
||||||
|
|
@ -82,111 +103,70 @@ export const useStyle = createStyles(({ token }, prefix: string) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
),
|
),
|
||||||
fixed: css`
|
fixed: css`
|
||||||
position: relative;
|
position: relative;
|
||||||
`,
|
`,
|
||||||
leftFloat: cx(
|
handlerIcon: css`
|
||||||
float,
|
display: flex;
|
||||||
css`
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s ${token.motionEaseOut};
|
||||||
|
`,
|
||||||
|
leftFloat: cx(
|
||||||
|
float,
|
||||||
|
css`
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
`,
|
`,
|
||||||
),
|
),
|
||||||
rightFloat: cx(
|
leftHandle: cx(
|
||||||
float,
|
css`
|
||||||
css`
|
${commonHandle};
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
height: 100%;
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
topFloat: cx(
|
|
||||||
float,
|
|
||||||
css`
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
bottomFloat: cx(
|
|
||||||
float,
|
|
||||||
css`
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
toggleLeft: cx(
|
|
||||||
`${prefix}-toggle`,
|
|
||||||
`${prefix}-toggle-left`,
|
|
||||||
commonToggle,
|
|
||||||
css`
|
|
||||||
left: -${offset}px;
|
|
||||||
width: ${toggleShort}px;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
> div {
|
&::before {
|
||||||
top: 50%;
|
|
||||||
|
|
||||||
width: ${toggleShort}px;
|
|
||||||
height: ${toggleLength}px;
|
|
||||||
margin-top: -20px;
|
|
||||||
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
toggleRight: cx(
|
|
||||||
`${prefix}-toggle`,
|
|
||||||
`${prefix}-toggle-right`,
|
|
||||||
commonToggle,
|
|
||||||
css`
|
|
||||||
right: -${offset}px;
|
|
||||||
width: ${toggleShort}px;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
top: 50%;
|
|
||||||
|
|
||||||
width: ${toggleShort}px;
|
|
||||||
height: ${toggleLength}px;
|
|
||||||
margin-top: -20px;
|
|
||||||
|
|
||||||
border-radius: 0 4px 4px 0;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
toggleTop: cx(
|
|
||||||
`${prefix}-toggle`,
|
|
||||||
`${prefix}-toggle-top`,
|
|
||||||
commonToggle,
|
|
||||||
css`
|
|
||||||
top: -${offset}px;
|
|
||||||
width: 100%;
|
|
||||||
height: ${toggleShort}px;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
width: 2px;
|
||||||
width: ${toggleLength}px;
|
height: 100%;
|
||||||
height: ${toggleShort}px;
|
|
||||||
margin-left: -20px;
|
|
||||||
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
),
|
`${prefix}-left-handle`,
|
||||||
toggleBottom: cx(
|
),
|
||||||
`${prefix}-toggle`,
|
panel: cx(
|
||||||
`${prefix}-toggle-bottom`,
|
`${prefix}-fixed`,
|
||||||
commonToggle,
|
css`
|
||||||
css`
|
overflow: hidden;
|
||||||
|
background: ${token.colorBgContainer};
|
||||||
|
transition: all 0.2s ${token.motionEaseOut};
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
rightFloat: cx(
|
||||||
|
float,
|
||||||
|
css`
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
rightHandle: cx(
|
||||||
|
css`
|
||||||
|
${commonHandle};
|
||||||
|
&::before {
|
||||||
|
right: 50%;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
`${prefix}-right-handle`,
|
||||||
|
),
|
||||||
|
toggleBottom: cx(
|
||||||
|
`${prefix}-toggle`,
|
||||||
|
`${prefix}-toggle-bottom`,
|
||||||
|
commonToggle,
|
||||||
|
css`
|
||||||
bottom: -${offset}px;
|
bottom: -${offset}px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: ${toggleShort}px;
|
height: ${toggleShort}px;
|
||||||
|
|
@ -201,47 +181,79 @@ export const useStyle = createStyles(({ token }, prefix: string) => {
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
),
|
),
|
||||||
panel: cx(
|
toggleLeft: cx(
|
||||||
`${prefix}-fixed`,
|
`${prefix}-toggle`,
|
||||||
css`
|
`${prefix}-toggle-left`,
|
||||||
overflow: hidden;
|
commonToggle,
|
||||||
background: ${token.colorBgContainer};
|
css`
|
||||||
transition: all 0.2s ${token.motionEaseOut};
|
left: -${offset}px;
|
||||||
`,
|
width: ${toggleShort}px;
|
||||||
),
|
height: 100%;
|
||||||
handlerIcon: css`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.2s ${token.motionEaseOut};
|
|
||||||
`,
|
|
||||||
leftHandle: cx(
|
|
||||||
css`
|
|
||||||
${commonHandle};
|
|
||||||
|
|
||||||
&::before {
|
> div {
|
||||||
|
top: 50%;
|
||||||
|
|
||||||
|
width: ${toggleShort}px;
|
||||||
|
height: ${toggleLength}px;
|
||||||
|
margin-top: -20px;
|
||||||
|
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
toggleRight: cx(
|
||||||
|
`${prefix}-toggle`,
|
||||||
|
`${prefix}-toggle-right`,
|
||||||
|
commonToggle,
|
||||||
|
css`
|
||||||
|
right: -${offset}px;
|
||||||
|
width: ${toggleShort}px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
top: 50%;
|
||||||
|
|
||||||
|
width: ${toggleShort}px;
|
||||||
|
height: ${toggleLength}px;
|
||||||
|
margin-top: -20px;
|
||||||
|
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
toggleTop: cx(
|
||||||
|
`${prefix}-toggle`,
|
||||||
|
`${prefix}-toggle-top`,
|
||||||
|
commonToggle,
|
||||||
|
css`
|
||||||
|
top: -${offset}px;
|
||||||
|
width: 100%;
|
||||||
|
height: ${toggleShort}px;
|
||||||
|
|
||||||
|
> div {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
width: 2px;
|
|
||||||
height: 100%;
|
width: ${toggleLength}px;
|
||||||
|
height: ${toggleShort}px;
|
||||||
|
margin-left: -20px;
|
||||||
|
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
`${prefix}-left-handle`,
|
),
|
||||||
),
|
topFloat: cx(
|
||||||
rightHandle: cx(
|
float,
|
||||||
css`
|
css`
|
||||||
${commonHandle};
|
top: 0;
|
||||||
&::before {
|
right: 0;
|
||||||
right: 50%;
|
left: 0;
|
||||||
width: 2px;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
`${prefix}-right-handle`,
|
),
|
||||||
),
|
topHandle: cx(
|
||||||
topHandle: cx(
|
`${prefix}-top-handle`,
|
||||||
`${prefix}-top-handle`,
|
css`
|
||||||
css`
|
|
||||||
${commonHandle};
|
${commonHandle};
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
|
@ -250,18 +262,6 @@ export const useStyle = createStyles(({ token }, prefix: string) => {
|
||||||
height: 2px;
|
height: 2px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
),
|
),
|
||||||
bottomHandle: cx(
|
};
|
||||||
`${prefix}-bottom-handle`,
|
|
||||||
css`
|
|
||||||
${commonHandle};
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
bottom: 50%;
|
|
||||||
width: 100%;
|
|
||||||
height: 2px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
import { placementType } from './index';
|
import {placementType} from './index';
|
||||||
|
|
||||||
export const revesePlacement = (placement: placementType) => {
|
export const revesePlacement = (placement: placementType) => {
|
||||||
switch (placement) {
|
switch (placement) {
|
||||||
case 'bottom':
|
case 'bottom': {
|
||||||
return 'top';
|
return 'top';
|
||||||
case 'top':
|
}
|
||||||
return 'bottom';
|
case 'top': {
|
||||||
case 'right':
|
return 'bottom';
|
||||||
return 'left';
|
}
|
||||||
case 'left':
|
case 'right': {
|
||||||
return 'right';
|
return 'left';
|
||||||
}
|
}
|
||||||
|
case 'left': {
|
||||||
|
return 'right';
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
import { memo, useEffect } from 'react';
|
import {memo, useEffect} from 'react';
|
||||||
|
|
||||||
interface GiscusProps {
|
interface GiscusProps {
|
||||||
themeMode: 'light' | 'dark';
|
themeMode: 'light' | 'dark';
|
||||||
}
|
}
|
||||||
const Giscus = memo<GiscusProps>(({ themeMode }) => {
|
const Giscus = memo<GiscusProps>(({themeMode}) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// giscus
|
// giscus
|
||||||
const giscus: HTMLScriptElement = document.createElement('script');
|
const giscus: HTMLScriptElement = document.createElement('script');
|
||||||
giscus.src = 'https://giscus.app/client.js';
|
giscus.src = 'https://giscus.app/client.js';
|
||||||
giscus.setAttribute('data-repo', 'canisminor1990/sd-webui-kitchen-theme');
|
giscus.dataset.repo = 'canisminor1990/sd-webui-kitchen-theme';
|
||||||
giscus.setAttribute('data-repo-id', 'R_kgDOJCPcNg');
|
giscus.dataset.repoId = 'R_kgDOJCPcNg';
|
||||||
giscus.setAttribute('data-mapping', 'number');
|
giscus.dataset.mapping = 'number';
|
||||||
giscus.setAttribute('data-term', '53');
|
giscus.dataset.term = '53';
|
||||||
giscus.setAttribute('data-reactions-enabled', '1');
|
giscus.dataset.reactionsEnabled = '1';
|
||||||
giscus.setAttribute('data-emit-metadata', '0');
|
giscus.dataset.emitMetadata = '0';
|
||||||
giscus.setAttribute('data-input-position', 'bottom');
|
giscus.dataset.inputPosition = 'bottom';
|
||||||
giscus.setAttribute('data-theme', themeMode);
|
giscus.dataset.theme = themeMode;
|
||||||
giscus.setAttribute('data-lang', 'en');
|
giscus.dataset.lang = 'en';
|
||||||
giscus.crossOrigin = 'anonymous';
|
giscus.crossOrigin = 'anonymous';
|
||||||
giscus.async = true;
|
giscus.async = true;
|
||||||
document.getElementsByTagName('head')[0].appendChild(giscus);
|
document.querySelectorAll('head')[0].append(giscus);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <div className="giscus" id="giscus" />;
|
return <div className="giscus" id="giscus" />;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Giscus;
|
export default Giscus;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { MenuProps } from 'antd';
|
import type {MenuProps} from 'antd';
|
||||||
import { Menu } from 'antd';
|
import {Menu} from 'antd';
|
||||||
import { memo, useEffect, useState } from 'react';
|
import {memo, useEffect, useState} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
|
|
@ -38,40 +38,40 @@ const NavBar = styled(Menu)`
|
||||||
************************* Dom *************************
|
************************* Dom *************************
|
||||||
******************************************************/
|
******************************************************/
|
||||||
|
|
||||||
const Nav = memo(() => {
|
const onClick: MenuProps['onClick'] = (e: any) => {
|
||||||
const [items, setItems] = useState<MenuProps['items']>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onUiLoaded(() => {
|
|
||||||
const buttons = gradioApp().querySelectorAll('#tabs > .tab-nav:first-child button');
|
|
||||||
const list: MenuProps['items'] | any = [];
|
|
||||||
buttons.forEach((button: HTMLButtonElement | any, index) => {
|
|
||||||
button.id = `kitchen-nav-${index}`;
|
|
||||||
list.push({
|
|
||||||
label: button.textContent,
|
|
||||||
key: String(index),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
setItems(list);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onClick: MenuProps['onClick'] = (e: any) => {
|
|
||||||
const buttons: HTMLButtonElement[] | any = gradioApp().querySelectorAll(
|
const buttons: HTMLButtonElement[] | any = gradioApp().querySelectorAll(
|
||||||
'#tabs > .tab-nav:first-child button',
|
'#tabs > .tab-nav:first-child button',
|
||||||
);
|
);
|
||||||
buttons[Number(e.key)]?.click();
|
buttons[Number(e.key)]?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const Nav = memo(() => {
|
||||||
<NavBar
|
const [items, setItems] = useState<MenuProps['items']>([]);
|
||||||
defaultActiveFirst
|
|
||||||
defaultSelectedKeys={['0']}
|
useEffect(() => {
|
||||||
items={items}
|
onUiLoaded(() => {
|
||||||
mode="horizontal"
|
const buttons = gradioApp().querySelectorAll('#tabs > .tab-nav:first-child button');
|
||||||
onClick={onClick}
|
const list: MenuProps['items'] | any = [];
|
||||||
/>
|
buttons.forEach((button: HTMLButtonElement | any, index) => {
|
||||||
);
|
button.id = `kitchen-nav-${index}`;
|
||||||
|
list.push({
|
||||||
|
key: String(index),
|
||||||
|
label: button.textContent,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setItems(list);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavBar
|
||||||
|
defaultActiveFirst
|
||||||
|
defaultSelectedKeys={['0']}
|
||||||
|
items={items}
|
||||||
|
mode="horizontal"
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Nav;
|
export default Nav;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { SettingOutlined } from '@ant-design/icons';
|
import {SettingOutlined} from '@ant-design/icons';
|
||||||
import { Button, Divider, Form, InputNumber, Popover, Segmented, Space, Switch } from 'antd';
|
import {Button, Divider, Form, InputNumber, Popover, Segmented, Space, Switch} from 'antd';
|
||||||
import { memo, useCallback } from 'react';
|
import {memo, useCallback} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { shallow } from 'zustand/shallow';
|
import {shallow} from 'zustand/shallow';
|
||||||
|
|
||||||
import { WebuiSetting, defaultSetting, useAppStore } from '@/store';
|
import {WebuiSetting, defaultSetting, useAppStore} from '@/store';
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
*********************** Style *************************
|
*********************** Style *************************
|
||||||
|
|
@ -39,85 +39,85 @@ const SubTitle = styled.div`
|
||||||
******************************************************/
|
******************************************************/
|
||||||
|
|
||||||
const Setting = memo(() => {
|
const Setting = memo(() => {
|
||||||
const [setting, onSetSetting] = useAppStore((st) => [st.setting, st.onSetSetting], shallow);
|
const [setting, onSetSetting] = useAppStore((st) => [st.setting, st.onSetSetting], shallow);
|
||||||
|
|
||||||
const onReset = useCallback(() => {
|
const onReset = useCallback(() => {
|
||||||
onSetSetting(defaultSetting);
|
onSetSetting(defaultSetting);
|
||||||
gradioApp().getElementById('settings_restart_gradio')?.click();
|
gradioApp().querySelector('#settings_restart_gradio')?.click();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onFinish = useCallback((value: WebuiSetting) => {
|
const onFinish = useCallback((value: WebuiSetting) => {
|
||||||
onSetSetting(value);
|
onSetSetting(value);
|
||||||
gradioApp().getElementById('settings_restart_gradio')?.click();
|
gradioApp().querySelector('#settings_restart_gradio')?.click();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
content={
|
content={
|
||||||
<Form
|
<Form
|
||||||
initialValues={setting}
|
initialValues={setting}
|
||||||
layout="horizontal"
|
layout="horizontal"
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
size="small"
|
size="small"
|
||||||
style={{ maxWidth: 260 }}
|
style={{maxWidth: 260}}
|
||||||
>
|
>
|
||||||
<Divider style={{ margin: '4px 0 8px' }} />
|
<Divider style={{margin: '4px 0 8px'}} />
|
||||||
<SubTitle>Promot Textarea</SubTitle>
|
<SubTitle>Promot Textarea</SubTitle>
|
||||||
<FormItem label="Display mode" name="promotTextarea">
|
<FormItem label="Display mode" name="promotTextarea">
|
||||||
<Segmented options={['scroll', 'resizable']} />
|
<Segmented options={['scroll', 'resizable']} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<Divider style={{ margin: '4px 0 8px' }} />
|
<Divider style={{margin: '4px 0 8px'}} />
|
||||||
<SubTitle>Sidebar</SubTitle>
|
<SubTitle>Sidebar</SubTitle>
|
||||||
<FormItem label="Default expand" name="sidebarExpand" valuePropName="checked">
|
<FormItem label="Default expand" name="sidebarExpand" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Display mode" name="sidebarFixedMode">
|
<FormItem label="Display mode" name="sidebarFixedMode">
|
||||||
<Segmented options={['fixed', 'float']} />
|
<Segmented options={['fixed', 'float']} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Default width" name="sidebarWidth">
|
<FormItem label="Default width" name="sidebarWidth">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<Divider style={{ margin: '4px 0 8px' }} />
|
<Divider style={{margin: '4px 0 8px'}} />
|
||||||
<SubTitle>ExtraNetwork Sidebar</SubTitle>
|
<SubTitle>ExtraNetwork Sidebar</SubTitle>
|
||||||
<FormItem label="Enable" name="enableExtraNetworkSidebar" valuePropName="checked">
|
<FormItem label="Enable" name="enableExtraNetworkSidebar" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Display mode" name="extraNetworkFixedMode" valuePropName="checked">
|
<FormItem label="Display mode" name="extraNetworkFixedMode" valuePropName="checked">
|
||||||
<Segmented options={['fixed', 'float']} />
|
<Segmented options={['fixed', 'float']} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Default expand" name="extraNetworkSidebarExpand" valuePropName="checked">
|
<FormItem label="Default expand" name="extraNetworkSidebarExpand" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Default width" name="extraNetworkSidebarWidth">
|
<FormItem label="Default width" name="extraNetworkSidebarWidth">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Default card size" name="extraNetworkCardSize">
|
<FormItem label="Default card size" name="extraNetworkCardSize">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<Divider style={{ margin: '4px 0 8px' }} />
|
<Divider style={{margin: '4px 0 8px'}} />
|
||||||
<SubTitle>Other</SubTitle>
|
<SubTitle>Other</SubTitle>
|
||||||
<FormItem label="Use svg icons" name="svgIcon" valuePropName="checked">
|
<FormItem label="Use svg icons" name="svgIcon" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<Divider style={{ margin: '4px 0 16px' }} />
|
<Divider style={{margin: '4px 0 16px'}} />
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<Space>
|
<Space>
|
||||||
<Button htmlType="button" onClick={onReset} style={{ borderRadius: 4 }}>
|
<Button htmlType="button" onClick={onReset} style={{borderRadius: 4}}>
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
<Button htmlType="submit" style={{ borderRadius: 4 }} type="primary">
|
<Button htmlType="submit" style={{borderRadius: 4}} type="primary">
|
||||||
Apply and restart UI
|
Apply and restart UI
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</Form>
|
</Form>
|
||||||
}
|
}
|
||||||
title={<Title>⚙ Setting</Title>}
|
title={<Title>⚙ Setting</Title>}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
>
|
>
|
||||||
<Button icon={<SettingOutlined />} title="Setting" />
|
<Button icon={<SettingOutlined />} title="Setting" />
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Setting;
|
export default Setting;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import { BoldOutlined, GithubOutlined } from '@ant-design/icons';
|
import {BoldOutlined, GithubOutlined} from '@ant-design/icons';
|
||||||
import { Button, Modal, Space } from 'antd';
|
import {Button, Modal, Space} from 'antd';
|
||||||
import { useResponsive } from 'antd-style';
|
import {useResponsive} from 'antd-style';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
import { type ReactNode, memo, useCallback, useEffect, useState } from 'react';
|
import {type ReactNode, memo, useCallback, useEffect, useState} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { shallow } from 'zustand/shallow';
|
import {shallow} from 'zustand/shallow';
|
||||||
|
|
||||||
import { DraggablePanel } from '@/components';
|
import {DraggablePanel} from '@/components';
|
||||||
import { useAppStore } from '@/store';
|
import {useAppStore} from '@/store';
|
||||||
|
|
||||||
import Giscus from './Giscus';
|
import Giscus from './Giscus';
|
||||||
import Logo from './Logo';
|
import Logo from './Logo';
|
||||||
import Nav from './Nav';
|
import Nav from './Nav';
|
||||||
import Setting from './Setting';
|
import Setting from './Setting';
|
||||||
import { civitaiLogo, themeIcon } from './style';
|
import {civitaiLogo, themeIcon} from './style';
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
*********************** Style *************************
|
*********************** Style *************************
|
||||||
|
|
@ -38,86 +38,86 @@ interface HeaderProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Header = memo<HeaderProps>(({ children }) => {
|
const Header = memo<HeaderProps>(({children}) => {
|
||||||
const [themeMode] = useAppStore((st) => [st.themeMode], shallow);
|
const [themeMode] = useAppStore((st) => [st.themeMode], shallow);
|
||||||
const { mobile } = useResponsive();
|
const {mobile} = useResponsive();
|
||||||
const [expand, setExpand] = useState<boolean>(true);
|
const [expand, setExpand] = useState<boolean>(true);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mobile) setExpand(false);
|
if (mobile) setExpand(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSetTheme = useCallback(() => {
|
const handleSetTheme = useCallback(() => {
|
||||||
const theme = themeMode === 'light' ? 'dark' : 'light';
|
const theme = themeMode === 'light' ? 'dark' : 'light';
|
||||||
const gradioURL = qs.parseUrl(window.location.href);
|
const gradioURL = qs.parseUrl(window.location.href);
|
||||||
gradioURL.query.__theme = theme;
|
gradioURL.query.__theme = theme;
|
||||||
window.location.replace(qs.stringifyUrl(gradioURL));
|
window.location.replace(qs.stringifyUrl(gradioURL));
|
||||||
}, [themeMode]);
|
}, [themeMode]);
|
||||||
|
|
||||||
const showModal = () => setIsModalOpen(true);
|
const showModal = () => setIsModalOpen(true);
|
||||||
|
|
||||||
const handleCancel = () => setIsModalOpen(false);
|
const handleCancel = () => setIsModalOpen(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DraggablePanel
|
<DraggablePanel
|
||||||
defaultSize={{ height: 'auto' }}
|
defaultSize={{height: 'auto'}}
|
||||||
expand={expand}
|
expand={expand}
|
||||||
minHeight={64}
|
minHeight={64}
|
||||||
onExpandChange={setExpand}
|
onExpandChange={setExpand}
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
|
||||||
<HeaderView id="header" style={{ flexDirection: mobile ? 'column' : 'row' }}>
|
|
||||||
<a
|
|
||||||
href="https://github.com/canisminor1990/sd-webui-kitchen-theme"
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<Logo themeMode={themeMode} />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<Nav />
|
|
||||||
{children}
|
|
||||||
|
|
||||||
<Space.Compact>
|
|
||||||
<a href="https://civitai.com/" rel="noreferrer" target="_blank">
|
|
||||||
<Button icon={civitaiLogo} title="Civitai" />
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://www.birme.net/?target_width=512&target_height=512"
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
>
|
||||||
<Button icon={<BoldOutlined />} title="Birme" />
|
<HeaderView id="header" style={{flexDirection: mobile ? 'column' : 'row'}}>
|
||||||
</a>
|
<a
|
||||||
<Button icon={<GithubOutlined />} onClick={showModal} title="Feedback" />
|
href="https://github.com/canisminor1990/sd-webui-kitchen-theme"
|
||||||
<Setting />
|
rel="noreferrer"
|
||||||
<Button icon={themeIcon[themeMode]} onClick={handleSetTheme} title="Switch Theme" />
|
target="_blank"
|
||||||
</Space.Compact>
|
>
|
||||||
</HeaderView>
|
<Logo themeMode={themeMode} />
|
||||||
</DraggablePanel>
|
</a>
|
||||||
<Modal
|
|
||||||
footer={null}
|
<Nav />
|
||||||
onCancel={handleCancel}
|
{children}
|
||||||
open={isModalOpen}
|
|
||||||
title={
|
<Space.Compact>
|
||||||
<a
|
<a href="https://civitai.com/" rel="noreferrer" target="_blank">
|
||||||
href="https://github.com/canisminor1990/sd-webui-kitchen-theme"
|
<Button icon={civitaiLogo} title="Civitai" />
|
||||||
rel="noreferrer"
|
</a>
|
||||||
target="_blank"
|
<a
|
||||||
>
|
href="https://www.birme.net/?target_width=512&target_height=512"
|
||||||
<Space>
|
rel="noreferrer"
|
||||||
<GithubOutlined />
|
target="_blank"
|
||||||
{'canisminor1990/sd-webui-kitchen-theme'}
|
>
|
||||||
</Space>
|
<Button icon={<BoldOutlined />} title="Birme" />
|
||||||
</a>
|
</a>
|
||||||
}
|
<Button icon={<GithubOutlined />} onClick={showModal} title="Feedback" />
|
||||||
>
|
<Setting />
|
||||||
<Giscus themeMode={themeMode} />
|
<Button icon={themeIcon[themeMode]} onClick={handleSetTheme} title="Switch Theme" />
|
||||||
</Modal>
|
</Space.Compact>
|
||||||
</>
|
</HeaderView>
|
||||||
);
|
</DraggablePanel>
|
||||||
|
<Modal
|
||||||
|
footer={false}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
open={isModalOpen}
|
||||||
|
title={
|
||||||
|
<a
|
||||||
|
href="https://github.com/canisminor1990/sd-webui-kitchen-theme"
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
<GithubOutlined />
|
||||||
|
{'canisminor1990/sd-webui-kitchen-theme'}
|
||||||
|
</Space>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Giscus themeMode={themeMode} />
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
export const themeIcon = {
|
export const themeIcon = {
|
||||||
light: (
|
dark: (
|
||||||
<span className="anticon anticon-github" role="img">
|
<span className="anticon anticon-github" role="img">
|
||||||
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
||||||
<path d="M8 13a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0v-1a1 1 0 0 1 1-1ZM8 3a1 1 0 0 1-1-1V1a1 1 0 1 1 2 0v1a1 1 0 0 1-1 1Zm7 4a1 1 0 1 1 0 2h-1a1 1 0 1 1 0-2h1ZM3 8a1 1 0 0 1-1 1H1a1 1 0 1 1 0-2h1a1 1 0 0 1 1 1Zm9.95 3.536.707.707a1 1 0 0 1-1.414 1.414l-.707-.707a1 1 0 0 1 1.414-1.414Zm-9.9-7.072-.707-.707a1 1 0 0 1 1.414-1.414l.707.707A1 1 0 0 1 3.05 4.464Zm9.9 0a1 1 0 0 1-1.414-1.414l.707-.707a1 1 0 0 1 1.414 1.414l-.707.707Zm-9.9 7.072a1 1 0 0 1 1.414 1.414l-.707.707a1 1 0 0 1-1.414-1.414l.707-.707ZM8 4a4 4 0 1 0 0 8 4 4 0 0 0 0-8Zm0 6.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5Z"></path>
|
<path d="M8.218 1.455c3.527.109 6.327 3.018 6.327 6.545 0 3.6-2.945 6.545-6.545 6.545a6.562 6.562 0 0 1-6.036-4h.218c3.6 0 6.545-2.945 6.545-6.545 0-.91-.182-1.745-.509-2.545m0-1.455c-.473 0-.909.218-1.2.618-.29.4-.327.946-.145 1.382.254.655.4 1.31.4 2 0 2.8-2.291 5.09-5.091 5.09h-.218c-.473 0-.91.22-1.2.62-.291.4-.328.945-.146 1.38C1.891 14.074 4.764 16 8 16c4.4 0 8-3.6 8-8a7.972 7.972 0 0 0-7.745-8h-.037Z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
dark: (
|
light: (
|
||||||
<span className="anticon anticon-github" role="img">
|
<span className="anticon anticon-github" role="img">
|
||||||
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
||||||
<path d="M8.218 1.455c3.527.109 6.327 3.018 6.327 6.545 0 3.6-2.945 6.545-6.545 6.545a6.562 6.562 0 0 1-6.036-4h.218c3.6 0 6.545-2.945 6.545-6.545 0-.91-.182-1.745-.509-2.545m0-1.455c-.473 0-.909.218-1.2.618-.29.4-.327.946-.145 1.382.254.655.4 1.31.4 2 0 2.8-2.291 5.09-5.091 5.09h-.218c-.473 0-.91.22-1.2.62-.291.4-.328.945-.146 1.38C1.891 14.074 4.764 16 8 16c4.4 0 8-3.6 8-8a7.972 7.972 0 0 0-7.745-8h-.037Z"></path>
|
<path d="M8 13a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0v-1a1 1 0 0 1 1-1ZM8 3a1 1 0 0 1-1-1V1a1 1 0 1 1 2 0v1a1 1 0 0 1-1 1Zm7 4a1 1 0 1 1 0 2h-1a1 1 0 1 1 0-2h1ZM3 8a1 1 0 0 1-1 1H1a1 1 0 1 1 0-2h1a1 1 0 0 1 1 1Zm9.95 3.536.707.707a1 1 0 0 1-1.414 1.414l-.707-.707a1 1 0 0 1 1.414-1.414Zm-9.9-7.072-.707-.707a1 1 0 0 1 1.414-1.414l.707.707A1 1 0 0 1 3.05 4.464Zm9.9 0a1 1 0 0 1-1.414-1.414l.707-.707a1 1 0 0 1 1.414 1.414l-.707.707Zm-9.9 7.072a1 1 0 0 1 1.414 1.414l-.707.707a1 1 0 0 1-1.414-1.414l.707-.707ZM8 4a4 4 0 1 0 0 8 4 4 0 0 0 0-8Zm0 6.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5Z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const darkLogo =
|
export const darkLogo =
|
||||||
|
|
@ -21,9 +21,9 @@ export const lightLogo =
|
||||||
'https://gw.alipayobjects.com/zos/bmw-prod/e146116d-c65a-4306-a3d2-bb8d05e1c49b.svg';
|
'https://gw.alipayobjects.com/zos/bmw-prod/e146116d-c65a-4306-a3d2-bb8d05e1c49b.svg';
|
||||||
|
|
||||||
export const civitaiLogo = (
|
export const civitaiLogo = (
|
||||||
<span className="anticon civitai" role="img">
|
<span className="anticon civitai" role="img">
|
||||||
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
<svg fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em">
|
||||||
<path d="M2 4.5L8 1l6 3.5v7L8 15l-6-3.5v-7zm6-1.194L3.976 5.653v4.694L8 12.694l4.024-2.347V5.653L8 3.306zm0 1.589l2.662 1.552v.824H9.25L8 6.54l-1.25.73v1.458L8 9.46l1.25-.73h1.412v.824L8 11.105 5.338 9.553V6.447L8 4.895z" />
|
<path d="M2 4.5L8 1l6 3.5v7L8 15l-6-3.5v-7zm6-1.194L3.976 5.653v4.694L8 12.694l4.024-2.347V5.653L8 3.306zm0 1.589l2.662 1.552v.824H9.25L8 6.54l-1.25.73v1.458L8 9.46l1.25-.73h1.412v.824L8 11.105 5.338 9.553V6.447L8 4.895z" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { memo, useCallback, useState } from 'react';
|
import {memo, useCallback, useState} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import TagList, { PromptType, TagItem } from './TagList';
|
import TagList, {PromptType, TagItem} from './TagList';
|
||||||
import { formatPrompt } from './utils';
|
import {formatPrompt} from './utils';
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
*********************** Style *************************
|
*********************** Style *************************
|
||||||
|
|
@ -14,12 +14,12 @@ const View = styled.div`
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const BtnGroup = styled.div`
|
const ButtonGroup = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Btn = styled.button`
|
const Button = styled.button`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -48,48 +48,54 @@ interface PromptProps {
|
||||||
type: PromptType;
|
type: PromptType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Prompt = memo<PromptProps>(({ type }) => {
|
const Prompt = memo<PromptProps>(({type}) => {
|
||||||
const [tags, setTags] = useState<TagItem[]>([]);
|
const [tags, setTags] = useState<TagItem[]>([]);
|
||||||
|
|
||||||
const id =
|
const id =
|
||||||
type === 'positive' ? "[id$='2img_prompt'] textarea" : "[id$='2img_neg_prompt'] textarea";
|
type === 'positive' ? "[id$='2img_prompt'] textarea" : "[id$='2img_neg_prompt'] textarea";
|
||||||
|
|
||||||
const getValue = useCallback(() => {
|
const getValue = useCallback(() => {
|
||||||
try {
|
try {
|
||||||
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
||||||
if (textarea) setTags(formatPrompt(textarea.value));
|
if (textarea) setTags(formatPrompt(textarea.value));
|
||||||
} catch {}
|
} catch (error) {
|
||||||
}, []);
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const setValue = useCallback(() => {
|
const setValue = useCallback(() => {
|
||||||
try {
|
try {
|
||||||
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
||||||
if (textarea) textarea.value = tags.map((t) => t.text).join(', ');
|
if (textarea) textarea.value = tags.map((t) => t.text).join(', ');
|
||||||
updateInput(textarea);
|
updateInput(textarea);
|
||||||
} catch {}
|
} catch (error) {
|
||||||
}, [tags]);
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, [tags]);
|
||||||
|
|
||||||
const setCurrentValue = useCallback((currentTags: TagItem[]) => {
|
const setCurrentValue = useCallback((currentTags: TagItem[]) => {
|
||||||
try {
|
try {
|
||||||
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
const textarea: HTMLTextAreaElement | any = get_uiCurrentTabContent().querySelector(id);
|
||||||
if (textarea) textarea.value = currentTags.map((t) => t.text).join(', ');
|
if (textarea) textarea.value = currentTags.map((t) => t.text).join(', ');
|
||||||
updateInput(textarea);
|
updateInput(textarea);
|
||||||
} catch {}
|
} catch (error) {
|
||||||
}, []);
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<TagList setTags={setTags} setValue={setCurrentValue} tags={tags} type={type} />
|
<TagList setTags={setTags} setValue={setCurrentValue} tags={tags} type={type} />
|
||||||
<BtnGroup>
|
<ButtonGroup>
|
||||||
<Btn onClick={getValue} title="Load Prompt">
|
<Button onClick={getValue} title="Load Prompt">
|
||||||
🔄
|
🔄
|
||||||
</Btn>
|
</Button>
|
||||||
<Btn onClick={setValue} title="Set Prompt">
|
<Button onClick={setValue} title="Set Prompt">
|
||||||
➡️
|
➡️
|
||||||
</Btn>
|
</Button>
|
||||||
</BtnGroup>
|
</ButtonGroup>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Prompt;
|
export default Prompt;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { type FC, memo, useCallback, useMemo } from 'react';
|
import {type FC, memo, useCallback, useMemo} from 'react';
|
||||||
import { WithContext, ReactTagsProps as WithContextProps } from 'react-tag-input';
|
import {WithContext, ReactTagsProps as WithContextProps} from 'react-tag-input';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { genTagType, suggestions } from './utils';
|
import {genTagType, suggestions} from './utils';
|
||||||
|
|
||||||
export interface TagItem {
|
export interface TagItem {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|
@ -73,14 +73,14 @@ const View = styled.div<{ type: PromptType }>`
|
||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
font-weight: var(--input-text-weight);
|
font-weight: var(--input-text-weight);
|
||||||
line-height: var(--line-sm);
|
line-height: var(--line-sm);
|
||||||
color: ${({ type }) => (type === 'positive' ? 'var(--green-9)' : 'var(--magenta-9)')};
|
color: ${({type}) => (type === 'positive' ? 'var(--green-9)' : 'var(--magenta-9)')};
|
||||||
|
|
||||||
background: var(--button-secondary-background-fill);
|
background: var(--button-secondary-background-fill);
|
||||||
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
||||||
border-radius: var(--input-radius);
|
border-radius: var(--input-radius);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${({ type }) => (type === 'positive' ? 'var(--green-10)' : 'var(--magenta-10)')};
|
color: ${({type}) => (type === 'positive' ? 'var(--green-10)' : 'var(--magenta-10)')};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,8 +155,8 @@ const View = styled.div<{ type: PromptType }>`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const KeyCodes = {
|
const KeyCodes = {
|
||||||
comma: 188,
|
comma: 188,
|
||||||
enter: 13,
|
enter: 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
const delimiters = [KeyCodes.comma, KeyCodes.enter];
|
const delimiters = [KeyCodes.comma, KeyCodes.enter];
|
||||||
|
|
@ -168,65 +168,65 @@ interface TagListProps {
|
||||||
type: PromptType;
|
type: PromptType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagList = memo<TagListProps>(({ tags, setTags, type, setValue }) => {
|
const TagList = memo<TagListProps>(({tags, setTags, type, setValue}) => {
|
||||||
const handleDelete = useCallback(
|
const handleDelete = useCallback(
|
||||||
(i: number) => {
|
(index_: number) => {
|
||||||
const newTags = tags.filter((tag, index) => index !== i);
|
const newTags = tags.filter((tag, index) => index !== index_);
|
||||||
setTags(newTags);
|
setTags(newTags);
|
||||||
setValue(newTags);
|
setValue(newTags);
|
||||||
},
|
},
|
||||||
[tags],
|
[tags],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleAddition = useCallback(
|
const handleAddition = useCallback(
|
||||||
(tag: TagItem) => {
|
(tag: TagItem) => {
|
||||||
const newTags = [...tags, genTagType(tag)];
|
const newTags = [...tags, genTagType(tag)];
|
||||||
setTags(newTags);
|
setTags(newTags);
|
||||||
setValue(newTags);
|
setValue(newTags);
|
||||||
},
|
},
|
||||||
[tags],
|
[tags],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDrag = useCallback(
|
const handleDrag = useCallback(
|
||||||
(tag: TagItem, currPos: number, newPos: number) => {
|
(tag: TagItem, currentPos: number, newPos: number) => {
|
||||||
const newTags = tags.slice();
|
const newTags = [...tags];
|
||||||
newTags.splice(currPos, 1);
|
newTags.splice(currentPos, 1);
|
||||||
newTags.splice(newPos, 0, genTagType(tag));
|
newTags.splice(newPos, 0, genTagType(tag));
|
||||||
setTags(newTags);
|
setTags(newTags);
|
||||||
setValue(newTags);
|
setValue(newTags);
|
||||||
},
|
},
|
||||||
[tags],
|
[tags],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTagUpdate = useCallback(
|
const handleTagUpdate = useCallback(
|
||||||
(i: number, tag: TagItem) => {
|
(index: number, tag: TagItem) => {
|
||||||
const newTags = [...tags];
|
const newTags = [...tags];
|
||||||
newTags[i] = genTagType(tag);
|
newTags[index] = genTagType(tag);
|
||||||
setTags(newTags);
|
setTags(newTags);
|
||||||
setValue(newTags);
|
setValue(newTags);
|
||||||
},
|
},
|
||||||
[tags],
|
[tags],
|
||||||
);
|
);
|
||||||
|
|
||||||
const suggestionData = useMemo(() => suggestions[type], [type]);
|
const suggestionData = useMemo(() => suggestions[type], [type]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View type={type}>
|
<View type={type}>
|
||||||
<ReactTags
|
<ReactTags
|
||||||
autocomplete
|
autocomplete
|
||||||
delimiters={delimiters}
|
delimiters={delimiters}
|
||||||
editable
|
editable
|
||||||
handleAddition={handleAddition}
|
handleAddition={handleAddition}
|
||||||
handleDelete={handleDelete}
|
handleDelete={handleDelete}
|
||||||
handleDrag={handleDrag}
|
handleDrag={handleDrag}
|
||||||
inline
|
inline
|
||||||
inputFieldPosition="bottom"
|
inputFieldPosition="bottom"
|
||||||
onTagUpdate={handleTagUpdate}
|
onTagUpdate={handleTagUpdate}
|
||||||
suggestions={suggestionData}
|
suggestions={suggestionData}
|
||||||
tags={tags}
|
tags={tags}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default TagList;
|
export default TagList;
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
import negativeData from '@/data/negative.json';
|
import negativeData from '@/data/negative.json';
|
||||||
import positiveData from '@/data/positive.json';
|
import positiveData from '@/data/positive.json';
|
||||||
import { Converter } from '@/script/formatPrompt';
|
import {Converter} from '@/script/formatPrompt';
|
||||||
|
|
||||||
import { TagItem } from './TagList';
|
import {TagItem} from './TagList';
|
||||||
|
|
||||||
export const genTagType = (tag: TagItem): TagItem => {
|
export const genTagType = (tag: TagItem): TagItem => {
|
||||||
const newTag = tag;
|
const newTag = tag;
|
||||||
if (newTag.text.includes('<lora')) {
|
if (newTag.text.includes('<lora')) {
|
||||||
newTag.className = 'ReactTags__lora';
|
newTag.className = 'ReactTags__lora';
|
||||||
} else if (newTag.text.includes('<hypernet')) {
|
} else if (newTag.text.includes('<hypernet')) {
|
||||||
newTag.className = 'ReactTags__hypernet';
|
newTag.className = 'ReactTags__hypernet';
|
||||||
} else if (newTag.text.includes('<embedding')) {
|
} else if (newTag.text.includes('<embedding')) {
|
||||||
newTag.className = 'ReactTags__embedding';
|
newTag.className = 'ReactTags__embedding';
|
||||||
} else {
|
} else {
|
||||||
newTag.className = undefined;
|
newTag.className = undefined;
|
||||||
}
|
}
|
||||||
return newTag;
|
return newTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatPrompt = (value: string) => {
|
export const formatPrompt = (value: string) => {
|
||||||
const text = Converter.convertStr(value);
|
const text = Converter.convertStr(value);
|
||||||
const textArray = Converter.convertStr2Array(text).map((item) => {
|
const textArray = Converter.convertStr2Array(text).map((item) => {
|
||||||
if (item.includes('<')) return item;
|
if (item.includes('<')) return item;
|
||||||
const newItem = item
|
const newItem = item
|
||||||
.replace(/\s+/g, ' ')
|
.replaceAll(/\s+/g, ' ')
|
||||||
.replace(/,|\.\|。/g, ',')
|
.replaceAll(/,|\.\|。/g, ',')
|
||||||
.replace(/“|‘|”|"|\/'/g, '')
|
.replaceAll(/“|‘|”|"|\/'/g, '')
|
||||||
.replace(/, /g, ',')
|
.replaceAll(', ', ',')
|
||||||
.replace(/,,/g, ',')
|
.replaceAll(',,', ',')
|
||||||
.replace(/,/g, ', ');
|
.replaceAll(',', ', ');
|
||||||
return Converter.convertStr2Array(newItem).join(', ');
|
return Converter.convertStr2Array(newItem).join(', ');
|
||||||
});
|
});
|
||||||
return textArray.map((tag) => genTagType({ id: tag, text: tag }));
|
return textArray.map((tag) => genTagType({id: tag, text: tag}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const genSuggestions = (array: string[]) =>
|
const genSuggestions = (array: string[]) =>
|
||||||
array.map((text) => {
|
array.map((text) => {
|
||||||
return {
|
return {
|
||||||
id: text,
|
id: text,
|
||||||
text,
|
text,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const suggestions = {
|
export const suggestions = {
|
||||||
positive: genSuggestions(positiveData),
|
negative: genSuggestions(negativeData),
|
||||||
negative: genSuggestions(negativeData),
|
positive: genSuggestions(positiveData),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
import { useEffect, useState } from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
|
|
||||||
function checkIsDarkMode() {
|
function checkIsDarkMode() {
|
||||||
try {
|
try {
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
} catch (err) {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useIsDarkMode() {
|
export function useIsDarkMode() {
|
||||||
const [isDarkMode, setIsDarkMode] = useState(checkIsDarkMode());
|
const [isDarkMode, setIsDarkMode] = useState(checkIsDarkMode());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mqList = window.matchMedia('(prefers-color-scheme: dark)');
|
const mqList = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
const listener = (event: any) => {
|
const listener = (event: any) => {
|
||||||
setIsDarkMode(event.matches);
|
setIsDarkMode(event.matches);
|
||||||
};
|
};
|
||||||
|
|
||||||
mqList.addEventListener('change', listener);
|
mqList.addEventListener('change', listener);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
mqList.removeEventListener('change', listener);
|
mqList.removeEventListener('change', listener);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return isDarkMode;
|
return isDarkMode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { Spin } from 'antd';
|
import {Spin} from 'antd';
|
||||||
import { useResponsive } from 'antd-style';
|
import {useResponsive} from 'antd-style';
|
||||||
import { memo, useEffect, useRef, useState } from 'react';
|
import {memo, useEffect, useRef, useState} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { shallow } from 'zustand/shallow';
|
import {shallow} from 'zustand/shallow';
|
||||||
|
|
||||||
import { Content, ExtraNetworkSidebar, Header, Sidebar } from '@/components';
|
import {Content, ExtraNetworkSidebar, Header, Sidebar} from '@/components';
|
||||||
import civitaiHelperFix from '@/script/civitaiHelperFix';
|
import civitaiHelperFix from '@/script/civitaiHelperFix';
|
||||||
import dragablePanel from '@/script/draggablePanel';
|
import dragablePanel from '@/script/draggablePanel';
|
||||||
import replaceIcon from '@/script/replaceIcon';
|
import replaceIcon from '@/script/replaceIcon';
|
||||||
import { useAppStore } from '@/store';
|
import {useAppStore} from '@/store';
|
||||||
|
|
||||||
const View = styled.div`
|
const View = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -41,124 +41,126 @@ const LoadingBox = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const App = memo(() => {
|
const App = memo(() => {
|
||||||
const [currentTab, setCurrentTab, setting] = useAppStore(
|
const [currentTab, setCurrentTab, setting] = useAppStore(
|
||||||
(st) => [st.currentTab, st.setCurrentTab, st.setting],
|
(st) => [st.currentTab, st.setCurrentTab, st.setting],
|
||||||
shallow,
|
shallow,
|
||||||
);
|
);
|
||||||
const { mobile } = useResponsive();
|
const {mobile} = useResponsive();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [extraLoading, setExtraLoading] = useState(true);
|
const [extraLoading, setExtraLoading] = useState(true);
|
||||||
const sidebarRef: any = useRef<HTMLElement>();
|
const sidebarReference: any = useRef<HTMLElement>();
|
||||||
const mainRef: any = useRef<HTMLElement>();
|
const mainReference: any = useRef<HTMLElement>();
|
||||||
const txt2imgExtraNetworkSidebarRef: any = useRef<HTMLElement>();
|
const txt2imgExtraNetworkSidebarReference: any = useRef<HTMLElement>();
|
||||||
const img2imgExtraNetworkSidebarRef: any = useRef<HTMLElement>();
|
const img2imgExtraNetworkSidebarReference: any = useRef<HTMLElement>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onUiLoaded(() => {
|
onUiLoaded(() => {
|
||||||
// Content
|
// Content
|
||||||
const main = gradioApp().querySelector('.app');
|
const main = gradioApp().querySelector('.app');
|
||||||
if (main) mainRef.current?.appendChild(main);
|
if (main) mainReference.current?.append(main);
|
||||||
if (!mobile) dragablePanel();
|
if (!mobile) dragablePanel();
|
||||||
|
|
||||||
// Sidebar
|
// Sidebar
|
||||||
const sidebar = gradioApp().querySelector('#quicksettings');
|
const sidebar = gradioApp().querySelector('#quicksettings');
|
||||||
if (sidebar) sidebarRef.current?.appendChild(sidebar);
|
if (sidebar) sidebarReference.current?.append(sidebar);
|
||||||
|
|
||||||
// ExtraNetworkSidebar
|
// ExtraNetworkSidebar
|
||||||
if (setting.enableExtraNetworkSidebar) {
|
if (setting.enableExtraNetworkSidebar) {
|
||||||
const txt2imgExtraNetworks = gradioApp().querySelector('div#txt2img_extra_networks');
|
const txt2imgExtraNetworks = gradioApp().querySelector('div#txt2img_extra_networks');
|
||||||
const img2imgExtraNetworks = gradioApp().querySelector('div#img2img_extra_networks');
|
const img2imgExtraNetworks = gradioApp().querySelector('div#img2img_extra_networks');
|
||||||
if (txt2imgExtraNetworks && img2imgExtraNetworks) {
|
if (txt2imgExtraNetworks && img2imgExtraNetworks) {
|
||||||
txt2imgExtraNetworkSidebarRef.current?.appendChild(txt2imgExtraNetworks);
|
txt2imgExtraNetworkSidebarReference.current?.append(txt2imgExtraNetworks);
|
||||||
img2imgExtraNetworkSidebarRef.current?.appendChild(img2imgExtraNetworks);
|
img2imgExtraNetworkSidebarReference.current?.append(img2imgExtraNetworks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
if (setting.svgIcon) replaceIcon();
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
onUiUpdate(() => {
|
||||||
|
setCurrentTab();
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && setting.enableExtraNetworkSidebar) {
|
||||||
|
if (document.querySelector('#txt2img_lora_cards')) {
|
||||||
|
civitaiHelperFix();
|
||||||
|
setExtraLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
const t2indexButton: any = document.querySelector('#txt2img_extra_refresh');
|
||||||
|
const index2indexButton: any = document.querySelector('#img2img_extra_refresh');
|
||||||
|
t2indexButton.click();
|
||||||
|
index2indexButton.click();
|
||||||
|
setExtraLoading(false);
|
||||||
|
try {
|
||||||
|
const civitaiButton = document.querySelectorAll(
|
||||||
|
'button[title="Refresh Civitai Helper\'s additional buttons"]',
|
||||||
|
);
|
||||||
|
if (civitaiButton) {
|
||||||
|
civitaiButton.forEach((button: any) => (button.onclick = civitaiHelperFix));
|
||||||
|
}
|
||||||
|
civitaiHelperFix();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}, [loading]);
|
||||||
|
|
||||||
// Other
|
return (
|
||||||
if (setting.svgIcon) replaceIcon();
|
<MainView>
|
||||||
|
<Header>
|
||||||
setLoading(false);
|
{loading && (
|
||||||
});
|
<LoadingBox>
|
||||||
onUiUpdate(() => {
|
<Spin size="small" />
|
||||||
setCurrentTab();
|
</LoadingBox>
|
||||||
});
|
)}
|
||||||
}, []);
|
</Header>
|
||||||
|
<View>
|
||||||
useEffect(() => {
|
<Sidebar>
|
||||||
if (!loading && setting.enableExtraNetworkSidebar) {
|
{loading && (
|
||||||
if (document.querySelector('#txt2img_lora_cards')) {
|
<LoadingBox>
|
||||||
civitaiHelperFix();
|
<Spin size="small" />
|
||||||
setExtraLoading(false);
|
</LoadingBox>
|
||||||
return;
|
)}
|
||||||
}
|
<div id="sidebar" ref={sidebarReference} style={loading ? {display: 'none'} : {}} />
|
||||||
setTimeout(() => {
|
</Sidebar>
|
||||||
const t2iBtn: any = document.querySelector('#txt2img_extra_refresh');
|
<Content loading={loading}>
|
||||||
const i2iBtn: any = document.querySelector('#img2img_extra_refresh');
|
{loading && (
|
||||||
t2iBtn.click();
|
<LoadingBox>
|
||||||
i2iBtn.click();
|
<Spin size="large" tip="Loading" />
|
||||||
setExtraLoading(false);
|
</LoadingBox>
|
||||||
try {
|
)}
|
||||||
const civitaiBtn = document.querySelectorAll(
|
<div id="content" ref={mainReference} style={loading ? {display: 'none'} : {}} />
|
||||||
'button[title="Refresh Civitai Helper\'s additional buttons"]',
|
</Content>
|
||||||
);
|
{setting?.enableExtraNetworkSidebar && (
|
||||||
if (civitaiBtn) {
|
<ExtraNetworkSidebar>
|
||||||
civitaiBtn.forEach((btn: any) => (btn.onclick = civitaiHelperFix));
|
{extraLoading && (
|
||||||
}
|
<LoadingBox>
|
||||||
civitaiHelperFix();
|
<Spin size="small" />
|
||||||
} catch {}
|
</LoadingBox>
|
||||||
}, 2000);
|
)}
|
||||||
}
|
<div style={extraLoading ? {display: 'none'} : {}}>
|
||||||
}, [loading]);
|
<div
|
||||||
|
id="txt2img-extra-netwrok-sidebar"
|
||||||
return (
|
ref={txt2imgExtraNetworkSidebarReference}
|
||||||
<MainView>
|
style={currentTab === 'tab_img2img' ? {display: 'none'} : {}}
|
||||||
<Header>
|
/>
|
||||||
{loading && (
|
<div
|
||||||
<LoadingBox>
|
id="img2img-extra-netwrok-sidebar"
|
||||||
<Spin size="small" />
|
ref={img2imgExtraNetworkSidebarReference}
|
||||||
</LoadingBox>
|
style={currentTab === 'tab_img2img' ? {} : {display: 'none'}}
|
||||||
)}
|
/>
|
||||||
</Header>
|
</div>
|
||||||
<View>
|
</ExtraNetworkSidebar>
|
||||||
<Sidebar>
|
)}
|
||||||
{loading && (
|
</View>
|
||||||
<LoadingBox>
|
</MainView>
|
||||||
<Spin size="small" />
|
);
|
||||||
</LoadingBox>
|
|
||||||
)}
|
|
||||||
<div id="sidebar" ref={sidebarRef} style={loading ? { display: 'none' } : {}} />
|
|
||||||
</Sidebar>
|
|
||||||
<Content loading={loading}>
|
|
||||||
{loading && (
|
|
||||||
<LoadingBox>
|
|
||||||
<Spin size="large" tip="Loading" />
|
|
||||||
</LoadingBox>
|
|
||||||
)}
|
|
||||||
<div id="content" ref={mainRef} style={loading ? { display: 'none' } : {}} />
|
|
||||||
</Content>
|
|
||||||
{setting?.enableExtraNetworkSidebar && (
|
|
||||||
<ExtraNetworkSidebar>
|
|
||||||
{extraLoading && (
|
|
||||||
<LoadingBox>
|
|
||||||
<Spin size="small" />
|
|
||||||
</LoadingBox>
|
|
||||||
)}
|
|
||||||
<div style={extraLoading ? { display: 'none' } : {}}>
|
|
||||||
<div
|
|
||||||
id="txt2img-extra-netwrok-sidebar"
|
|
||||||
ref={txt2imgExtraNetworkSidebarRef}
|
|
||||||
style={currentTab !== 'tab_img2img' ? {} : { display: 'none' }}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
id="img2img-extra-netwrok-sidebar"
|
|
||||||
ref={img2imgExtraNetworkSidebarRef}
|
|
||||||
style={currentTab === 'tab_img2img' ? {} : { display: 'none' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ExtraNetworkSidebar>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</MainView>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,81 @@
|
||||||
import { ThemeProvider, setupStyled } from 'antd-style';
|
import {ThemeProvider, setupStyled} from 'antd-style';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
import { memo, useEffect, useState } from 'react';
|
import {memo, useEffect, useState} from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import {createRoot} from 'react-dom/client';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import ReactFontLoader from 'react-font-loader';
|
import ReactFontLoader from 'react-font-loader';
|
||||||
import { ThemeContext } from 'styled-components';
|
import {ThemeContext} from 'styled-components';
|
||||||
import { shallow } from 'zustand/shallow';
|
import {shallow} from 'zustand/shallow';
|
||||||
|
|
||||||
import { useIsDarkMode } from '@/components/theme/useIsDarkMode';
|
import {useIsDarkMode} from '@/components/theme/useIsDarkMode';
|
||||||
import formatPrompt from '@/script/formatPrompt';
|
import formatPrompt from '@/script/formatPrompt';
|
||||||
import promptBracketChecker from '@/script/promptBracketChecker';
|
import promptBracketChecker from '@/script/promptBracketChecker';
|
||||||
import setupHead from '@/script/setupHead';
|
import setupHead from '@/script/setupHead';
|
||||||
import { useAppStore } from '@/store';
|
import {useAppStore} from '@/store';
|
||||||
import '@/theme/style.less';
|
import '@/theme/style.less';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import GlobalStyle from './GlobalStyle';
|
import GlobalStyle from './GlobalStyle';
|
||||||
import { baseToken } from './style';
|
import {baseToken} from './style';
|
||||||
|
|
||||||
const Root = memo(() => {
|
const Root = memo(() => {
|
||||||
setupStyled({ ThemeContext });
|
setupStyled({ThemeContext});
|
||||||
const [onSetThemeMode, onInit] = useAppStore((st) => [st.onSetThemeMode, st.onInit], shallow);
|
const [onSetThemeMode, onInit] = useAppStore((st) => [st.onSetThemeMode, st.onInit], shallow);
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
const [appearance, setAppearance] = useState<'light' | 'dark'>('light');
|
const [appearance, setAppearance] = useState<'light' | 'dark'>('light');
|
||||||
const [first, setFirst] = useState(true);
|
const [first, setFirst] = useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onInit();
|
onInit();
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const queryTheme: any = String(qs.parseUrl(window.location.href).query.__theme || '');
|
const queryTheme: any = String(qs.parseUrl(window.location.href).query.__theme || '');
|
||||||
if (queryTheme) {
|
if (queryTheme) {
|
||||||
setAppearance(queryTheme as any);
|
setAppearance(queryTheme as any);
|
||||||
document.body.classList.add(queryTheme);
|
document.body.classList.add(queryTheme);
|
||||||
onSetThemeMode(queryTheme);
|
onSetThemeMode(queryTheme);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setAppearance(isDarkMode ? 'dark' : 'light');
|
setAppearance(isDarkMode ? 'dark' : 'light');
|
||||||
document.body.classList.add(isDarkMode ? 'dark' : 'light');
|
document.body.classList.add(isDarkMode ? 'dark' : 'light');
|
||||||
onSetThemeMode(isDarkMode ? 'dark' : 'light');
|
onSetThemeMode(isDarkMode ? 'dark' : 'light');
|
||||||
}, [isDarkMode]);
|
}, [isDarkMode]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (first) {
|
if (first) {
|
||||||
setFirst(false);
|
setFirst(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, [isDarkMode]);
|
}, [isDarkMode]);
|
||||||
return (
|
return (
|
||||||
<ThemeProvider appearance={appearance} theme={{ token: baseToken }}>
|
<ThemeProvider appearance={appearance} theme={{token: baseToken}}>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<ReactFontLoader url="https://raw.githubusercontent.com/IKKI2000/harmonyos-fonts/main/css/harmonyos_sans.css" />
|
<ReactFontLoader url="https://raw.githubusercontent.com/IKKI2000/harmonyos-fonts/main/css/harmonyos_sans.css" />
|
||||||
<ReactFontLoader url="https://raw.githubusercontent.com/IKKI2000/harmonyos-fonts/main/css/harmonyos_sans_sc.css" />
|
<ReactFontLoader url="https://raw.githubusercontent.com/IKKI2000/harmonyos-fonts/main/css/harmonyos_sans_sc.css" />
|
||||||
<App />
|
<App />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
'DOMContentLoaded',
|
'DOMContentLoaded',
|
||||||
() => {
|
() => {
|
||||||
setupHead();
|
setupHead();
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
root.setAttribute('id', 'root');
|
root.setAttribute('id', 'root');
|
||||||
try {
|
try {
|
||||||
gradioApp()?.append(root);
|
gradioApp()?.append(root);
|
||||||
} catch {
|
} catch {
|
||||||
document.querySelector('gradio-app')?.append(root);
|
document.querySelector('gradio-app')?.append(root);
|
||||||
}
|
}
|
||||||
const client = createRoot(root);
|
const client = createRoot(root);
|
||||||
client.render(<Root />);
|
client.render(<Root />);
|
||||||
},
|
},
|
||||||
{ once: true },
|
{once: true},
|
||||||
);
|
);
|
||||||
|
|
||||||
onUiLoaded(() => {
|
onUiLoaded(() => {
|
||||||
formatPrompt();
|
formatPrompt();
|
||||||
promptBracketChecker();
|
promptBracketChecker();
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => null;
|
export default () => false;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
const TAB_PREFIX_LIST = ['txt2img', 'img2img'];
|
const TAB_PREFIX_LIST = ['txt2img', 'img2img'];
|
||||||
const MODEL_TYPE_LIST: ['textual_inversion', 'hypernetworks', 'checkpoints', 'lora', 'lycoris'] = [
|
const MODEL_TYPE_LIST: ['textual_inversion', 'hypernetworks', 'checkpoints', 'lora', 'lycoris'] = [
|
||||||
'textual_inversion',
|
'textual_inversion',
|
||||||
'hypernetworks',
|
'hypernetworks',
|
||||||
'checkpoints',
|
'checkpoints',
|
||||||
'lora',
|
'lora',
|
||||||
'lycoris',
|
'lycoris',
|
||||||
];
|
];
|
||||||
const MODEL_TYPE = {
|
const MODEL_TYPE = {
|
||||||
textual_inversion: 'ti',
|
checkpoints: 'ckp',
|
||||||
hypernetworks: 'hyper',
|
hypernetworks: 'hyper',
|
||||||
checkpoints: 'ckp',
|
lora: 'lora',
|
||||||
lora: 'lora',
|
lycoris: 'lycoris',
|
||||||
lycoris: 'lycoris',
|
textual_inversion: 'ti',
|
||||||
};
|
};
|
||||||
const CARDID_SUFFIX = 'cards';
|
const CARDID_SUFFIX = 'cards';
|
||||||
|
|
||||||
|
|
@ -23,189 +23,189 @@ const BTN_THUMB_DISPLAY = 'inline';
|
||||||
const BTN_THUMB_POS = 'static';
|
const BTN_THUMB_POS = 'static';
|
||||||
const BTN_THUMB_BACKGROUND_IMAGE = 'none';
|
const BTN_THUMB_BACKGROUND_IMAGE = 'none';
|
||||||
const BTN_THUMB_BACKGROUND = 'rgba(0, 0, 0, 0.8)';
|
const BTN_THUMB_BACKGROUND = 'rgba(0, 0, 0, 0.8)';
|
||||||
const CH_BTN_TXTS = ['🌐', '💡', '🏷️'];
|
const CH_BTN_TXTS = new Set(['🌐', '💡', '🏷️']);
|
||||||
|
|
||||||
const styleBtn = (node: HTMLElement, isThumbMode: boolean) => {
|
const styleButton = (node: HTMLElement, isThumbMode: boolean) => {
|
||||||
if (!isThumbMode) {
|
if (isThumbMode) {
|
||||||
node.style.fontSize = BTN_FONT_SIZE;
|
node.style.display = BTN_THUMB_DISPLAY;
|
||||||
node.style.margin = BTN_MARGIN;
|
node.style.fontSize = BTN_THUMB_FONT_SIZE;
|
||||||
} else {
|
node.style.position = BTN_THUMB_POS;
|
||||||
node.style.display = BTN_THUMB_DISPLAY;
|
node.style.backgroundImage = BTN_THUMB_BACKGROUND_IMAGE;
|
||||||
node.style.fontSize = BTN_THUMB_FONT_SIZE;
|
} else {
|
||||||
node.style.position = BTN_THUMB_POS;
|
node.style.fontSize = BTN_FONT_SIZE;
|
||||||
node.style.backgroundImage = BTN_THUMB_BACKGROUND_IMAGE;
|
node.style.margin = BTN_MARGIN;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateCardForCivitai = () => {
|
const updateCardForCivitai = () => {
|
||||||
if (!gradioApp().querySelector('#tab_civitai_helper')) return;
|
if (!gradioApp().querySelector('#tab_civitai_helper')) return;
|
||||||
|
|
||||||
const replacePreviewText = getTranslation('replace preview') || 'replace preview';
|
const replacePreviewText = getTranslation('replace preview') || 'replace preview';
|
||||||
|
|
||||||
// Get component
|
// Get component
|
||||||
const chAlwaysDisplayCkb = gradioApp().querySelector(
|
const chAlwaysDisplayCkb = gradioApp().querySelector(
|
||||||
'#ch_always_display_ckb input',
|
'#ch_always_display_ckb input',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const chShowBtnOnThumbCkb = gradioApp().querySelector(
|
const chShowButtonOnThumbCkb = gradioApp().querySelector(
|
||||||
'#ch_show_btn_on_thumb_ckb input',
|
'#ch_show_btn_on_thumb_ckb input',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const chAlwaysDisplay = chAlwaysDisplayCkb?.checked || false;
|
const chAlwaysDisplay = chAlwaysDisplayCkb?.checked || false;
|
||||||
const chShowBtnOnThumb = chShowBtnOnThumbCkb?.checked || false;
|
const chShowButtonOnThumb = chShowButtonOnThumbCkb?.checked || false;
|
||||||
|
|
||||||
// Change all "replace preview" into an icon
|
// Change all "replace preview" into an icon
|
||||||
let extraNetworkId = '';
|
let extraNetworkId = '';
|
||||||
let extraNetworkNode: any = null;
|
let extraNetworkNode: any;
|
||||||
let metadataButton: any = null;
|
let metadataButton: any;
|
||||||
let additionalNode: any = null;
|
let additionalNode: any;
|
||||||
let replacePreviewBtn: any = null;
|
let replacePreviewButton: any;
|
||||||
let ulNode: any = null;
|
let ulNode: any;
|
||||||
let searchTermNode: any = null;
|
let searchTermNode: any;
|
||||||
let searchTerm = '';
|
let searchTerm = '';
|
||||||
let modelType = '';
|
let modelType = '';
|
||||||
let cards = null;
|
let cards;
|
||||||
let needToAddButtons = false;
|
let needToAddButtons = false;
|
||||||
let isThumbMode = false;
|
let isThumbMode = false;
|
||||||
|
|
||||||
// Get current tab
|
// Get current tab
|
||||||
TAB_PREFIX_LIST.forEach((activeTabType) => {
|
for (const activeTabType of TAB_PREFIX_LIST) {
|
||||||
MODEL_TYPE_LIST.forEach((jsModelType) => {
|
for (const jsModelType of MODEL_TYPE_LIST) {
|
||||||
modelType = MODEL_TYPE[jsModelType];
|
modelType = MODEL_TYPE[jsModelType];
|
||||||
// Get model_type for python side
|
// Get model_type for python side
|
||||||
|
|
||||||
extraNetworkId = `${activeTabType}_${jsModelType}_${CARDID_SUFFIX}`;
|
extraNetworkId = `${activeTabType}_${jsModelType}_${CARDID_SUFFIX}`;
|
||||||
extraNetworkNode = gradioApp().getElementById(extraNetworkId);
|
extraNetworkNode = gradioApp().querySelector(`#${extraNetworkId}`);
|
||||||
|
|
||||||
// Check if extra network node exists
|
// Check if extra network node exists
|
||||||
if (extraNetworkNode === null) return;
|
if (extraNetworkNode === undefined) continue;
|
||||||
|
|
||||||
// Check if extr network is under thumbnail mode
|
// Check if extr network is under thumbnail mode
|
||||||
isThumbMode = false;
|
isThumbMode = false;
|
||||||
if (extraNetworkNode?.className === 'extra-network-thumbs') isThumbMode = true;
|
if (extraNetworkNode?.className === 'extra-network-thumbs') isThumbMode = true;
|
||||||
|
|
||||||
// Get all card nodes
|
// Get all card nodes
|
||||||
cards = extraNetworkNode.querySelectorAll('.card');
|
cards = extraNetworkNode.querySelectorAll('.card');
|
||||||
for (const card of cards) {
|
for (const card of cards) {
|
||||||
if (card.querySelectorAll('.actions .additional a').length > 2) return;
|
if (card.querySelectorAll('.actions .additional a').length > 2) continue;
|
||||||
// Metadata_buttoncard
|
// Metadata_buttoncard
|
||||||
metadataButton = card.querySelector('.metadata-button');
|
metadataButton = card.querySelector('.metadata-button');
|
||||||
// Additional node
|
// Additional node
|
||||||
additionalNode = card.querySelector('.actions .additional');
|
additionalNode = card.querySelector('.actions .additional');
|
||||||
// Get ul node, which is the parent of all buttons
|
// Get ul node, which is the parent of all buttons
|
||||||
ulNode = card.querySelector('.actions .additional ul');
|
ulNode = card.querySelector('.actions .additional ul');
|
||||||
// Replace preview text button
|
// Replace preview text button
|
||||||
replacePreviewBtn = card.querySelector('.actions .additional a');
|
replacePreviewButton = card.querySelector('.actions .additional a');
|
||||||
|
|
||||||
// Check thumb mode
|
// Check thumb mode
|
||||||
if (isThumbMode && additionalNode) {
|
if (isThumbMode && additionalNode) {
|
||||||
additionalNode.style.display = null;
|
additionalNode.style.display = undefined;
|
||||||
|
|
||||||
if (chShowBtnOnThumb) {
|
if (chShowButtonOnThumb) {
|
||||||
ulNode.style.background = BTN_THUMB_BACKGROUND;
|
ulNode.style.background = BTN_THUMB_BACKGROUND;
|
||||||
} else {
|
} else {
|
||||||
// Reset
|
// Reset
|
||||||
ulNode.style.background = null;
|
ulNode.style.background = undefined;
|
||||||
// Remove existed buttons
|
// Remove existed buttons
|
||||||
if (ulNode) {
|
if (ulNode) {
|
||||||
// Find all .a child nodes
|
// Find all .a child nodes
|
||||||
const atags = ulNode.querySelectorAll('a');
|
const atags = ulNode.querySelectorAll('a');
|
||||||
|
|
||||||
for (const atag of atags) {
|
for (const atag of atags) {
|
||||||
// Reset display
|
// Reset display
|
||||||
atag.style.display = null;
|
atag.style.display = undefined;
|
||||||
// Remove extension's button
|
// Remove extension's button
|
||||||
if (CH_BTN_TXTS.indexOf(atag.innerHTML) >= 0) {
|
if (CH_BTN_TXTS.has(atag.innerHTML)) {
|
||||||
// Need to remove
|
// Need to remove
|
||||||
ulNode.removeChild(atag);
|
atag.remove();
|
||||||
|
} else {
|
||||||
|
// Do not remove, just reset
|
||||||
|
atag.innerHTML = replacePreviewText;
|
||||||
|
atag.style.display = undefined;
|
||||||
|
atag.style.fontSize = undefined;
|
||||||
|
atag.style.position = undefined;
|
||||||
|
atag.style.backgroundImage = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also remove br tag in ul
|
||||||
|
const brtag = ulNode.querySelector('br');
|
||||||
|
if (brtag) brtag.remove();
|
||||||
|
}
|
||||||
|
// Just reset and remove nodes, do nothing else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do not remove, just reset
|
// Full preview mode
|
||||||
atag.innerHTML = replacePreviewText;
|
additionalNode.style.display = chAlwaysDisplay ? 'block' : undefined;
|
||||||
atag.style.display = null;
|
|
||||||
atag.style.fontSize = null;
|
// Remove br tag
|
||||||
atag.style.position = null;
|
const brtag = ulNode.querySelector('br');
|
||||||
atag.style.backgroundImage = null;
|
if (brtag) brtag.remove();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Also remove br tag in ul
|
// Change replace preview text button into icon
|
||||||
const brtag = ulNode.querySelector('br');
|
if (replacePreviewButton?.innerHTML !== '🖼️') {
|
||||||
if (brtag) ulNode.removeChild(brtag);
|
needToAddButtons = true;
|
||||||
|
replacePreviewButton.innerHTML = '🖼️';
|
||||||
|
styleButton(replacePreviewButton, isThumbMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needToAddButtons) continue;
|
||||||
|
// Search_term node
|
||||||
|
// Search_term = subfolder path + model name + ext
|
||||||
|
searchTermNode = card.querySelector('.actions .additional .search_term');
|
||||||
|
if (!searchTermNode) return;
|
||||||
|
// Get search_term
|
||||||
|
searchTerm = searchTermNode.innerHTML;
|
||||||
|
if (!searchTerm) continue;
|
||||||
|
|
||||||
|
// Then we need to add 3 buttons to each ul node:
|
||||||
|
const openUrlNode = document.createElement('a');
|
||||||
|
openUrlNode.href = '#';
|
||||||
|
openUrlNode.innerHTML = '🌐';
|
||||||
|
styleButton(openUrlNode, isThumbMode);
|
||||||
|
openUrlNode.title = "Open this model's civitai url";
|
||||||
|
openUrlNode.setAttribute(
|
||||||
|
'onclick',
|
||||||
|
`open_model_url(event, '${modelType}', '${searchTerm}')`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const addTriggerWordsNode = document.createElement('a');
|
||||||
|
addTriggerWordsNode.href = '#';
|
||||||
|
addTriggerWordsNode.innerHTML = '💡';
|
||||||
|
styleButton(addTriggerWordsNode, isThumbMode);
|
||||||
|
addTriggerWordsNode.title = 'Add trigger words to prompt';
|
||||||
|
addTriggerWordsNode.setAttribute(
|
||||||
|
'onclick',
|
||||||
|
`add_trigger_words(event, '${modelType}', '${searchTerm}')`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const usePreviewPromptNode = document.createElement('a');
|
||||||
|
usePreviewPromptNode.href = '#';
|
||||||
|
usePreviewPromptNode.innerHTML = '🏷️';
|
||||||
|
styleButton(usePreviewPromptNode, isThumbMode);
|
||||||
|
usePreviewPromptNode.title = 'Use prompt from preview image';
|
||||||
|
usePreviewPromptNode.setAttribute(
|
||||||
|
'onclick',
|
||||||
|
`use_preview_prompt(event, '${modelType}', '${searchTerm}')`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add to card
|
||||||
|
ulNode.append(openUrlNode);
|
||||||
|
// Add br if metadata_button exists
|
||||||
|
if (isThumbMode && metadataButton) ulNode.append(document.createElement('br'));
|
||||||
|
ulNode.append(addTriggerWordsNode);
|
||||||
|
ulNode.append(usePreviewPromptNode);
|
||||||
}
|
}
|
||||||
// Just reset and remove nodes, do nothing else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Full preview mode
|
|
||||||
additionalNode.style.display = chAlwaysDisplay ? 'block' : null;
|
|
||||||
|
|
||||||
// Remove br tag
|
|
||||||
const brtag = ulNode.querySelector('br');
|
|
||||||
if (brtag) ulNode.removeChild(brtag);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Change replace preview text button into icon
|
|
||||||
if (replacePreviewBtn?.innerHTML !== '🖼️') {
|
|
||||||
needToAddButtons = true;
|
|
||||||
replacePreviewBtn.innerHTML = '🖼️';
|
|
||||||
styleBtn(replacePreviewBtn, isThumbMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needToAddButtons) return;
|
|
||||||
// Search_term node
|
|
||||||
// Search_term = subfolder path + model name + ext
|
|
||||||
searchTermNode = card.querySelector('.actions .additional .search_term');
|
|
||||||
if (!searchTermNode) return;
|
|
||||||
// Get search_term
|
|
||||||
searchTerm = searchTermNode.innerHTML;
|
|
||||||
if (!searchTerm) return;
|
|
||||||
|
|
||||||
// Then we need to add 3 buttons to each ul node:
|
|
||||||
const openUrlNode = document.createElement('a');
|
|
||||||
openUrlNode.href = '#';
|
|
||||||
openUrlNode.innerHTML = '🌐';
|
|
||||||
styleBtn(openUrlNode, isThumbMode);
|
|
||||||
openUrlNode.title = "Open this model's civitai url";
|
|
||||||
openUrlNode.setAttribute(
|
|
||||||
'onclick',
|
|
||||||
`open_model_url(event, '${modelType}', '${searchTerm}')`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const addTriggerWordsNode = document.createElement('a');
|
|
||||||
addTriggerWordsNode.href = '#';
|
|
||||||
addTriggerWordsNode.innerHTML = '💡';
|
|
||||||
styleBtn(addTriggerWordsNode, isThumbMode);
|
|
||||||
addTriggerWordsNode.title = 'Add trigger words to prompt';
|
|
||||||
addTriggerWordsNode.setAttribute(
|
|
||||||
'onclick',
|
|
||||||
`add_trigger_words(event, '${modelType}', '${searchTerm}')`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const usePreviewPromptNode = document.createElement('a');
|
|
||||||
usePreviewPromptNode.href = '#';
|
|
||||||
usePreviewPromptNode.innerHTML = '🏷️';
|
|
||||||
styleBtn(usePreviewPromptNode, isThumbMode);
|
|
||||||
usePreviewPromptNode.title = 'Use prompt from preview image';
|
|
||||||
usePreviewPromptNode.setAttribute(
|
|
||||||
'onclick',
|
|
||||||
`use_preview_prompt(event, '${modelType}', '${searchTerm}')`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add to card
|
|
||||||
ulNode.appendChild(openUrlNode);
|
|
||||||
// Add br if metadata_button exists
|
|
||||||
if (isThumbMode && metadataButton) ulNode.appendChild(document.createElement('br'));
|
|
||||||
ulNode.appendChild(addTriggerWordsNode);
|
|
||||||
ulNode.appendChild(usePreviewPromptNode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const fixInterval = setInterval(() => {
|
const fixInterval = setInterval(() => {
|
||||||
const checkDom = document.querySelector('#txt2img_lora_cards');
|
const checkDom = document.querySelector('#txt2img_lora_cards');
|
||||||
if (checkDom) {
|
if (checkDom) {
|
||||||
updateCardForCivitai();
|
updateCardForCivitai();
|
||||||
clearInterval(fixInterval);
|
clearInterval(fixInterval);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,67 @@
|
||||||
const MIN_WIDTH = 240;
|
const MIN_WIDTH = 240;
|
||||||
|
|
||||||
const addDraggable = (tabId: string) => {
|
const addDraggable = (tabId: string) => {
|
||||||
const settings = document.getElementById(`${tabId}_settings`);
|
const settings: any = document.querySelector(`#${tabId}_settings`);
|
||||||
const checkDraggableLine = document.querySelector(`#tab_${tabId} .draggable-line`);
|
const checkDraggableLine = document.querySelector(`#tab_${tabId} .draggable-line`);
|
||||||
if (!settings || checkDraggableLine) return;
|
if (!settings || checkDraggableLine) return;
|
||||||
|
|
||||||
settings.style.minWidth = `min(${MIN_WIDTH}px, 100%)`;
|
settings.style.minWidth = `min(${MIN_WIDTH}px, 100%)`;
|
||||||
|
|
||||||
const lineWrapper = document.createElement('div');
|
const lineWrapper = document.createElement('div');
|
||||||
lineWrapper.classList.add('draggable-line');
|
lineWrapper.classList.add('draggable-line');
|
||||||
|
|
||||||
settings.insertAdjacentElement('afterend', lineWrapper);
|
settings.after(lineWrapper);
|
||||||
|
|
||||||
const container: HTMLElement | any = settings.parentElement;
|
const container: HTMLElement | any = settings.parentElement;
|
||||||
container.classList.add('draggable-container');
|
container.classList.add('draggable-container');
|
||||||
|
|
||||||
const results = document.getElementById(`${tabId}_results`);
|
const results: any = document.querySelector(`#${tabId}_results`);
|
||||||
if (!results) return;
|
if (!results) return;
|
||||||
|
|
||||||
results.style.minWidth = `${MIN_WIDTH}px`;
|
results.style.minWidth = `${MIN_WIDTH}px`;
|
||||||
|
|
||||||
let linePosition = 50;
|
|
||||||
settings.style.flexBasis = `${linePosition}%`;
|
|
||||||
results.style.flexBasis = `${100 - linePosition}%`;
|
|
||||||
|
|
||||||
let isDragging = false;
|
|
||||||
|
|
||||||
lineWrapper.addEventListener('mousedown', (e) => {
|
|
||||||
isDragging = true;
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', (event) => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
|
|
||||||
const tab: HTMLElement | any = document.querySelector(`#tab_${tabId}`);
|
|
||||||
if (!tab) return;
|
|
||||||
|
|
||||||
let offsetX = tab.offsetLeft;
|
|
||||||
let parent = tab.offsetParent;
|
|
||||||
|
|
||||||
while (parent) {
|
|
||||||
offsetX += parent.offsetLeft;
|
|
||||||
parent = parent.offsetParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
const containerWidth = container.offsetWidth;
|
|
||||||
const mouseX = event.clientX;
|
|
||||||
const linePosition = ((mouseX - offsetX) / containerWidth) * 100;
|
|
||||||
|
|
||||||
if (linePosition <= (MIN_WIDTH / containerWidth) * 100) return;
|
|
||||||
if (linePosition >= (1 - MIN_WIDTH / containerWidth) * 100) return;
|
|
||||||
|
|
||||||
|
let linePosition = 50;
|
||||||
settings.style.flexBasis = `${linePosition}%`;
|
settings.style.flexBasis = `${linePosition}%`;
|
||||||
results.style.flexBasis = `${100 - linePosition}%`;
|
results.style.flexBasis = `${100 - linePosition}%`;
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('mouseup', () => {
|
let isDragging = false;
|
||||||
isDragging = false;
|
|
||||||
});
|
lineWrapper.addEventListener('mousedown', (e) => {
|
||||||
|
isDragging = true;
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', (event) => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
|
||||||
|
const tab: HTMLElement | any = document.querySelector(`#tab_${tabId}`);
|
||||||
|
if (!tab) return;
|
||||||
|
|
||||||
|
let offsetX = tab.offsetLeft;
|
||||||
|
let parent = tab.offsetParent;
|
||||||
|
|
||||||
|
while (parent) {
|
||||||
|
offsetX += parent.offsetLeft;
|
||||||
|
parent = parent.offsetParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerWidth = container.offsetWidth;
|
||||||
|
const mouseX = event.clientX;
|
||||||
|
const linePosition = ((mouseX - offsetX) / containerWidth) * 100;
|
||||||
|
|
||||||
|
if (linePosition <= (MIN_WIDTH / containerWidth) * 100) return;
|
||||||
|
if (linePosition >= (1 - MIN_WIDTH / containerWidth) * 100) return;
|
||||||
|
|
||||||
|
settings.style.flexBasis = `${linePosition}%`;
|
||||||
|
results.style.flexBasis = `${100 - linePosition}%`;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', () => {
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
addDraggable('txt2img');
|
addDraggable('txt2img');
|
||||||
addDraggable('img2img');
|
addDraggable('img2img');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,280 +1,279 @@
|
||||||
/**
|
/**
|
||||||
* 转换器工具类
|
* 转换器工具类
|
||||||
*/
|
*/
|
||||||
export class Converter {
|
export const Converter = {
|
||||||
/**
|
/**
|
||||||
* 将数字四舍五入到小数点后四位
|
* 添加转换按钮
|
||||||
* @param value 数字
|
* @param type - 组件类型
|
||||||
* @returns 四舍五入后的数字
|
|
||||||
*/
|
*/
|
||||||
static round(value: number): number {
|
addPromptButton(type: string): void {
|
||||||
return Math.round(value * 10000) / 10000;
|
const generateButton: HTMLElement | null = gradioApp().querySelector(`#${type}_generate`);
|
||||||
}
|
const actionsColumn: HTMLElement | null = gradioApp().querySelector(`#${type}_style_create`);
|
||||||
|
const nai2local: HTMLElement | null = gradioApp().querySelector(`#${type}_formatconvert`);
|
||||||
/**
|
if (!generateButton || !actionsColumn || nai2local) return;
|
||||||
* 将字符串中的中文冒号和括号转换成英文冒号和括号
|
const convertButton: HTMLElement = Converter.createButton(`${type}_formatconvert`, '🪄', () =>
|
||||||
* @param srt 字符串
|
Converter.onClickConvert(type));
|
||||||
* @returns 转换后的字符串
|
actionsColumn.parentNode?.append(convertButton);
|
||||||
*/
|
},
|
||||||
static convertStr(srt: string): string {
|
|
||||||
return srt.replace(/:/g, ':').replace(/(/g, '(').replace(/)/g, ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串按照括号分割成数组
|
|
||||||
* @param str 字符串
|
|
||||||
* @returns 分割后的数组
|
|
||||||
*/
|
|
||||||
static convertStr2Array(str: string): string[] {
|
|
||||||
// 匹配各种括号中的内容,包括括号本身
|
|
||||||
const bracketRegex = /([()<>[\]])/g;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将字符串按照各种括号分割成数组
|
|
||||||
* @param str 字符串
|
|
||||||
* @returns 分割后的数组
|
|
||||||
*/
|
|
||||||
const splitByBracket = (str: string): string[] => {
|
|
||||||
const arr: string[] = [];
|
|
||||||
let start = 0;
|
|
||||||
let depth = 0;
|
|
||||||
let match;
|
|
||||||
while ((match = bracketRegex.exec(str)) !== null) {
|
|
||||||
if (depth === 0 && match.index > start) {
|
|
||||||
arr.push(str.substring(start, match.index));
|
|
||||||
start = match.index;
|
|
||||||
}
|
|
||||||
if (match[0] === '(' || match[0] === '<' || match[0] === '[') {
|
|
||||||
depth++;
|
|
||||||
} else if (match[0] === ')' || match[0] === '>' || match[0] === ']') {
|
|
||||||
depth--;
|
|
||||||
}
|
|
||||||
if (depth === 0) {
|
|
||||||
arr.push(str.substring(start, match.index + 1));
|
|
||||||
start = match.index + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < str.length) {
|
|
||||||
arr.push(str.substring(start));
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串按照逗号和各种括号分割成数组
|
|
||||||
* @param str 字符串
|
|
||||||
* @returns 分割后的数组
|
|
||||||
*/
|
|
||||||
const splitByComma = (str: string): string[] => {
|
|
||||||
const arr: string[] = [];
|
|
||||||
let start = 0;
|
|
||||||
let inBracket = false;
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
if (str[i] === ',' && !inBracket) {
|
|
||||||
arr.push(str.substring(start, i).trim());
|
|
||||||
start = i + 1;
|
|
||||||
} else if (str[i].match(bracketRegex)) {
|
|
||||||
inBracket = !inBracket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arr.push(str.substring(start).trim());
|
|
||||||
return arr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清洗字符串并输出数组
|
|
||||||
* @param str 字符串
|
|
||||||
* @returns 清洗后的数组
|
|
||||||
*/
|
|
||||||
const cleanStr = (str: string): string[] => {
|
|
||||||
let arr = splitByBracket(str);
|
|
||||||
arr = arr.flatMap((s) => splitByComma(s));
|
|
||||||
return arr.filter((s) => s !== '');
|
|
||||||
};
|
|
||||||
|
|
||||||
return cleanStr(str)
|
|
||||||
.filter((item) => {
|
|
||||||
const pattern = /^[,\s, ]+$/;
|
|
||||||
return !pattern.test(item);
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
.sort((a, b) => {
|
|
||||||
return a.includes('<') && !b.includes('<')
|
|
||||||
? 1
|
|
||||||
: b.includes('<') && !a.includes('<')
|
|
||||||
? -1
|
|
||||||
: 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将数组转换成字符串
|
|
||||||
* @param array 数组
|
|
||||||
* @returns 转换后的字符串
|
|
||||||
*/
|
|
||||||
static convertArray2Str(array: string[]): string {
|
|
||||||
const newArray = array.map((item) => {
|
|
||||||
if (item.includes('<')) return item;
|
|
||||||
const newItem = item
|
|
||||||
.replace(/\s+/g, ' ')
|
|
||||||
.replace(/,|\.\|。/g, ',')
|
|
||||||
.replace(/“|‘|”|"|\/'/g, '')
|
|
||||||
.replace(/, /g, ',')
|
|
||||||
.replace(/,,/g, ',')
|
|
||||||
.replace(/,/g, ', ');
|
|
||||||
return Converter.convertStr2Array(newItem).join(', ');
|
|
||||||
});
|
|
||||||
return newArray.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将输入的字符串转换成特定格式的字符串
|
* 将输入的字符串转换成特定格式的字符串
|
||||||
* @param input 输入的字符串
|
* @param input 输入的字符串
|
||||||
* @returns 转换后的字符串
|
* @returns 转换后的字符串
|
||||||
*/
|
*/
|
||||||
static convert(input: string): string {
|
convert(input: string): string {
|
||||||
const re_attention = /\{|\[|\}|\]|[^{}[\]]+/gmu;
|
const re_attention = /\{|\[|\}|\]|[^{}[\]]+/gmu;
|
||||||
|
|
||||||
let text = Converter.convertStr(input);
|
let text = Converter.convertStr(input);
|
||||||
const textArray = Converter.convertStr2Array(text);
|
const textArray = Converter.convertStr2Array(text);
|
||||||
text = Converter.convertArray2Str(textArray);
|
text = Converter.convertArray2Str(textArray);
|
||||||
|
|
||||||
let res: [string, number][] = [];
|
let res: [string, number][] = [];
|
||||||
|
|
||||||
const curly_bracket_multiplier = 1.05;
|
const curly_bracket_multiplier = 1.05;
|
||||||
const square_bracket_multiplier = 1 / 1.05;
|
const square_bracket_multiplier = 1 / 1.05;
|
||||||
|
|
||||||
const brackets: Record<string, { multiplier: number; stack: number[] }> = {
|
const brackets: Record<string, { multiplier: number; stack: number[] }> = {
|
||||||
'{': { stack: [], multiplier: curly_bracket_multiplier },
|
'[': {multiplier: square_bracket_multiplier, stack: []},
|
||||||
'[': { stack: [], multiplier: square_bracket_multiplier },
|
'{': {multiplier: curly_bracket_multiplier, stack: []},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将指定范围内的数字乘以指定倍数
|
* 将指定范围内的数字乘以指定倍数
|
||||||
* @param start_position 起始位置
|
* @param start_position 起始位置
|
||||||
* @param multiplier 倍数
|
* @param multiplier 倍数
|
||||||
*/
|
*/
|
||||||
function multiply_range(start_position: number, multiplier: number) {
|
function multiply_range(start_position: number, multiplier: number) {
|
||||||
for (let pos = start_position; pos < res.length; pos++) {
|
for (let pos = start_position; pos < res.length; pos++) {
|
||||||
res[pos][1] = Converter.round(res[pos][1] * multiplier);
|
res[pos][1] = Converter.round(res[pos][1] * multiplier);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const match of text.matchAll(re_attention)) {
|
|
||||||
let word = match[0];
|
|
||||||
|
|
||||||
if (word in brackets) {
|
|
||||||
brackets[word].stack.push(res.length);
|
|
||||||
} else if (word === '}' || word === ']') {
|
|
||||||
const bracket = brackets[word === '}' ? '{' : '['];
|
|
||||||
if (bracket.stack.length > 0) {
|
|
||||||
multiply_range(bracket.stack.pop()!, bracket.multiplier);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
res.push([word, 1.0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(brackets).forEach((bracketType) => {
|
for (const match of text.matchAll(re_attention)) {
|
||||||
brackets[bracketType].stack.forEach((pos) => {
|
let word = match[0];
|
||||||
multiply_range(pos, brackets[bracketType].multiplier);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.length === 0) {
|
if (word in brackets) {
|
||||||
res = [['', 1.0]];
|
brackets[word].stack.push(res.length);
|
||||||
}
|
} else if (word === '}' || word === ']') {
|
||||||
|
const bracket = brackets[word === '}' ? '{' : '['];
|
||||||
|
if (bracket.stack.length > 0) {
|
||||||
|
multiply_range(bracket.stack.pop()!, bracket.multiplier);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.push([word, 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let i = 0;
|
for (const bracketType of Object.keys(brackets)) {
|
||||||
while (i + 1 < res.length) {
|
for (const pos of brackets[bracketType].stack) {
|
||||||
if (res[i][1] === res[i + 1][1]) {
|
multiply_range(pos, brackets[bracketType].multiplier);
|
||||||
res[i][0] += res[i + 1][0];
|
}
|
||||||
res.splice(i + 1, 1);
|
}
|
||||||
} else {
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = '';
|
if (res.length === 0) {
|
||||||
for (const [word, value] of res) {
|
res = [['', 1]];
|
||||||
result += value === 1.0 ? word : `(${word}:${value.toString()})`;
|
}
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
let index = 0;
|
||||||
* 触发 input 事件
|
while (index + 1 < res.length) {
|
||||||
* @param target 目标元素
|
if (res[index][1] === res[index + 1][1]) {
|
||||||
|
res[index][0] += res[index + 1][0];
|
||||||
|
res.splice(index + 1, 1);
|
||||||
|
} else {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
for (const [word, value] of res) {
|
||||||
|
result += value === 1 ? word : `(${word}:${value.toString()})`;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数组转换成字符串
|
||||||
|
* @param array 数组
|
||||||
|
* @returns 转换后的字符串
|
||||||
*/
|
*/
|
||||||
static dispatchInputEvent(target: EventTarget) {
|
convertArray2Str(array: string[]): string {
|
||||||
let inputEvent = new Event('input');
|
const newArray = array.map((item) => {
|
||||||
Object.defineProperty(inputEvent, 'target', { value: target });
|
if (item.includes('<')) return item;
|
||||||
target.dispatchEvent(inputEvent);
|
const newItem = item
|
||||||
}
|
.replaceAll(/\s+/g, ' ')
|
||||||
|
.replaceAll(/,|\.\|。/g, ',')
|
||||||
|
.replaceAll(/“|‘|”|"|\/'/g, '')
|
||||||
|
.replaceAll(', ', ',')
|
||||||
|
.replaceAll(',,', ',')
|
||||||
|
.replaceAll(',', ', ');
|
||||||
|
return Converter.convertStr2Array(newItem).join(', ');
|
||||||
|
});
|
||||||
|
return newArray.join(', ');
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 点击转换按钮的事件处理函数
|
* 将字符串中的中文冒号和括号转换成英文冒号和括号
|
||||||
* @param type 类型
|
* @param srt 字符串
|
||||||
|
* @returns 转换后的字符串
|
||||||
*/
|
*/
|
||||||
static onClickConvert(type: string) {
|
convertStr(srt: string): string {
|
||||||
const default_prompt = '';
|
return srt.replaceAll(':', ':').replaceAll('(', '(').replaceAll(')', ')');
|
||||||
const default_negative = '';
|
},
|
||||||
|
|
||||||
const prompt = gradioApp().querySelector(
|
/**
|
||||||
`#${type}_prompt > label > textarea`,
|
* 将字符串按照括号分割成数组
|
||||||
) as HTMLTextAreaElement;
|
* @param str 字符串
|
||||||
const result = Converter.convert(prompt.value);
|
* @returns 分割后的数组
|
||||||
prompt.value =
|
*/
|
||||||
result.match(/^masterpiece, best quality,/) === null ? default_prompt + result : result;
|
convertStr2Array(string_: string): string[] {
|
||||||
Converter.dispatchInputEvent(prompt);
|
// 匹配各种括号中的内容,包括括号本身
|
||||||
const negprompt = gradioApp().querySelector(
|
const bracketRegex = /([()<>[\]])/g;
|
||||||
`#${type}_neg_prompt > label > textarea`,
|
|
||||||
) as HTMLTextAreaElement;
|
|
||||||
const negResult = Converter.convert(negprompt.value);
|
|
||||||
negprompt.value =
|
|
||||||
negResult.match(/^lowres,/) === null
|
|
||||||
? negResult.length === 0
|
|
||||||
? default_negative
|
|
||||||
: default_negative + negResult
|
|
||||||
: negResult;
|
|
||||||
Converter.dispatchInputEvent(negprompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 将字符串按照各种括号分割成数组
|
||||||
|
* @param str 字符串
|
||||||
|
* @returns 分割后的数组
|
||||||
|
*/
|
||||||
|
const splitByBracket = (string__: string): string[] => {
|
||||||
|
const array: string[] = [];
|
||||||
|
let start = 0;
|
||||||
|
let depth = 0;
|
||||||
|
let match;
|
||||||
|
while ((match = bracketRegex.exec(string__)) !== null) {
|
||||||
|
if (depth === 0 && match.index > start) {
|
||||||
|
array.push(string__.slice(start, match.index));
|
||||||
|
start = match.index;
|
||||||
|
}
|
||||||
|
if (match[0] === '(' || match[0] === '<' || match[0] === '[') {
|
||||||
|
depth++;
|
||||||
|
} else if (match[0] === ')' || match[0] === '>' || match[0] === ']') {
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
if (depth === 0) {
|
||||||
|
array.push(string__.slice(start, match.index + 1));
|
||||||
|
start = match.index + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start < string__.length) {
|
||||||
|
array.push(string__.slice(Math.max(0, start)));
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串按照逗号和各种括号分割成数组
|
||||||
|
* @param str 字符串
|
||||||
|
* @returns 分割后的数组
|
||||||
|
*/
|
||||||
|
const splitByComma = (string__: string): string[] => {
|
||||||
|
const array: string[] = [];
|
||||||
|
let start = 0;
|
||||||
|
let inBracket = false;
|
||||||
|
for (let index = 0; index < string__.length; index++) {
|
||||||
|
if (string__[index] === ',' && !inBracket) {
|
||||||
|
array.push(string__.slice(start, index).trim());
|
||||||
|
start = index + 1;
|
||||||
|
} else if (bracketRegex.test(string__[index])) {
|
||||||
|
inBracket = !inBracket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array.push(string__.slice(Math.max(0, start)).trim());
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清洗字符串并输出数组
|
||||||
|
* @param str 字符串
|
||||||
|
* @returns 清洗后的数组
|
||||||
|
*/
|
||||||
|
const cleanString = (string__: string): string[] => {
|
||||||
|
let array = splitByBracket(string__);
|
||||||
|
array = array.flatMap((s) => splitByComma(s));
|
||||||
|
return array.filter((s) => s !== '');
|
||||||
|
};
|
||||||
|
|
||||||
|
return cleanString(string_)
|
||||||
|
.filter((item) => {
|
||||||
|
const pattern = /^[\s,,]+$/;
|
||||||
|
return !pattern.test(item);
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.includes('<') && !b.includes('<') ?
|
||||||
|
1 :
|
||||||
|
b.includes('<') && !a.includes('<') ?
|
||||||
|
-1 :
|
||||||
|
0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
* 创建转换按钮
|
* 创建转换按钮
|
||||||
* @param id 按钮 id
|
* @param id 按钮 id
|
||||||
* @param innerHTML 按钮文本
|
* @param innerHTML 按钮文本
|
||||||
* @param onClick 点击事件处理函数
|
* @param onClick 点击事件处理函数
|
||||||
* @returns 新建的按钮元素
|
* @returns 新建的按钮元素
|
||||||
*/
|
*/
|
||||||
static createButton(id: string, innerHTML: string, onClick: () => void): HTMLButtonElement {
|
createButton(id: string, innerHTML: string, onClick: () => void): HTMLButtonElement {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.id = id;
|
button.id = id;
|
||||||
button.type = 'button';
|
button.type = 'button';
|
||||||
button.innerHTML = innerHTML;
|
button.innerHTML = innerHTML;
|
||||||
button.title = 'Format prompt~🪄';
|
button.title = 'Format prompt~🪄';
|
||||||
button.className = 'lg secondary gradio-button tool svelte-1ipelgc';
|
button.className = 'lg secondary gradio-button tool svelte-1ipelgc';
|
||||||
button.addEventListener('click', onClick);
|
button.addEventListener('click', onClick);
|
||||||
return button;
|
return button;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加转换按钮
|
* 触发 input 事件
|
||||||
* @param type - 组件类型
|
* @param target 目标元素
|
||||||
*/
|
*/
|
||||||
static addPromptButton(type: string): void {
|
dispatchInputEvent(target: EventTarget) {
|
||||||
const generateBtn: HTMLElement | null = gradioApp().querySelector(`#${type}_generate`);
|
let inputEvent = new Event('input');
|
||||||
const actionsColumn: HTMLElement | null = gradioApp().querySelector(`#${type}_style_create`);
|
Object.defineProperty(inputEvent, 'target', {value: target});
|
||||||
const nai2local: HTMLElement | null = gradioApp().querySelector(`#${type}_formatconvert`);
|
target.dispatchEvent(inputEvent);
|
||||||
if (!generateBtn || !actionsColumn || nai2local) return;
|
},
|
||||||
const convertBtn: HTMLElement = Converter.createButton(`${type}_formatconvert`, '🪄', () =>
|
|
||||||
Converter.onClickConvert(type),
|
/**
|
||||||
);
|
* 点击转换按钮的事件处理函数
|
||||||
actionsColumn.parentNode?.append(convertBtn);
|
* @param type 类型
|
||||||
}
|
*/
|
||||||
}
|
onClickConvert(type: string) {
|
||||||
|
const default_prompt = '';
|
||||||
|
const default_negative = '';
|
||||||
|
|
||||||
|
const prompt = gradioApp().querySelector(
|
||||||
|
`#${type}_prompt > label > textarea`,
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
const result = Converter.convert(prompt.value);
|
||||||
|
prompt.value =
|
||||||
|
result.match(/^masterpiece, best quality,/) === null ? default_prompt + result : result;
|
||||||
|
Converter.dispatchInputEvent(prompt);
|
||||||
|
const negprompt = gradioApp().querySelector(
|
||||||
|
`#${type}_neg_prompt > label > textarea`,
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
|
const negResult = Converter.convert(negprompt.value);
|
||||||
|
negprompt.value =
|
||||||
|
negResult.match(/^lowres,/) === null ?
|
||||||
|
negResult.length === 0 ?
|
||||||
|
default_negative :
|
||||||
|
default_negative + negResult :
|
||||||
|
negResult;
|
||||||
|
Converter.dispatchInputEvent(negprompt);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数字四舍五入到小数点后四位
|
||||||
|
* @param value 数字
|
||||||
|
* @returns 四舍五入后的数字
|
||||||
|
*/
|
||||||
|
round(value: number): number {
|
||||||
|
return Math.round(value * 10_000) / 10_000;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
Converter.addPromptButton('txt2img');
|
Converter.addPromptButton('txt2img');
|
||||||
Converter.addPromptButton('img2img');
|
Converter.addPromptButton('img2img');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,52 +4,52 @@ interface ErrorString {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BracketChecker {
|
class BracketChecker {
|
||||||
private textArea: HTMLTextAreaElement;
|
private textArea: HTMLTextAreaElement;
|
||||||
private counterElt: HTMLElement;
|
private counterElt: HTMLElement;
|
||||||
private errorStrings: ErrorString[];
|
private errorStrings: ErrorString[];
|
||||||
|
|
||||||
constructor(textArea: HTMLTextAreaElement, counterElt: HTMLElement) {
|
constructor(textArea: HTMLTextAreaElement, counterElt: HTMLElement) {
|
||||||
this.textArea = textArea;
|
this.textArea = textArea;
|
||||||
this.counterElt = counterElt;
|
this.counterElt = counterElt;
|
||||||
this.errorStrings = [
|
this.errorStrings = [
|
||||||
{
|
{
|
||||||
regex: '\\(',
|
error: '(...) - Different number of opening and closing parentheses detected.\n',
|
||||||
error: '(...) - Different number of opening and closing parentheses detected.\n',
|
regex: '\\(',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
regex: '\\[',
|
error: '[...] - Different number of opening and closing square brackets detected.\n',
|
||||||
error: '[...] - Different number of opening and closing square brackets detected.\n',
|
regex: '\\[',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
regex: '\\{',
|
error: '{...} - Different number of opening and closing curly brackets detected.\n',
|
||||||
error: '{...} - Different number of opening and closing curly brackets detected.\n',
|
regex: '\\{',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查文本框中的括号是否匹配,并更新计数器元素的标题和样式
|
* 检查文本框中的括号是否匹配,并更新计数器元素的标题和样式
|
||||||
*/
|
*/
|
||||||
public check = (): void => {
|
public check = (): void => {
|
||||||
let title = '';
|
let title = '';
|
||||||
this.errorStrings.forEach(({ regex, error }) => {
|
for (const {regex, error} of this.errorStrings) {
|
||||||
const openMatches = (this.textArea.value.match(new RegExp(regex, 'g')) || []).length;
|
const openMatches = (this.textArea.value.match(new RegExp(regex, 'g')) || []).length;
|
||||||
const closeMatches = (
|
const closeMatches = (
|
||||||
this.textArea.value.match(
|
this.textArea.value.match(
|
||||||
new RegExp(regex.replace(/\(/g, ')').replace(/\[/g, ']').replace(/\{/g, '}'), 'g'),
|
new RegExp(regex.replaceAll('(', ')').replaceAll('[', ']').replaceAll('{', '}'), 'g'),
|
||||||
) || []
|
) || []
|
||||||
).length;
|
).length;
|
||||||
if (openMatches !== closeMatches) {
|
if (openMatches === closeMatches) {
|
||||||
if (!this.counterElt.title.includes(error)) {
|
title = this.counterElt.title.replace(error, '');
|
||||||
title += error;
|
} else {
|
||||||
|
if (!this.counterElt.title.includes(error)) {
|
||||||
|
title += error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
this.counterElt.title = title;
|
||||||
title = this.counterElt.title.replace(error, '');
|
this.counterElt.classList.toggle('error', !!title);
|
||||||
}
|
};
|
||||||
});
|
|
||||||
this.counterElt.title = title;
|
|
||||||
this.counterElt.classList.toggle('error', !!title);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,18 +58,18 @@ class BracketChecker {
|
||||||
* @param id_counter 显示计数器的元素的 ID
|
* @param id_counter 显示计数器的元素的 ID
|
||||||
*/
|
*/
|
||||||
const setupBracketChecking = (idPrompt: string, idCounter: string): void => {
|
const setupBracketChecking = (idPrompt: string, idCounter: string): void => {
|
||||||
const textarea = gradioApp().querySelector(
|
const textarea = gradioApp().querySelector(
|
||||||
`#${idPrompt} > label > textarea`,
|
`#${idPrompt} > label > textarea`,
|
||||||
) as HTMLTextAreaElement;
|
) as HTMLTextAreaElement;
|
||||||
const counter = gradioApp().getElementById(idCounter) as HTMLElement;
|
const counter = gradioApp().querySelector(`#${idCounter}`) as HTMLElement;
|
||||||
const bracketChecker = new BracketChecker(textarea, counter);
|
const bracketChecker = new BracketChecker(textarea, counter);
|
||||||
textarea.addEventListener('input', bracketChecker.check);
|
textarea.addEventListener('input', bracketChecker.check);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const elements = ['txt2img', 'txt2img_neg', 'img2img', 'img2img_neg'];
|
const elements = ['txt2img', 'txt2img_neg', 'img2img', 'img2img_neg'];
|
||||||
elements.forEach((prompt) => {
|
for (const prompt of elements) {
|
||||||
setupBracketChecking(`${prompt}_prompt`, `${prompt}_token_counter`);
|
setupBracketChecking(`${prompt}_prompt`, `${prompt}_token_counter`);
|
||||||
setupBracketChecking(`${prompt}_prompt`, `${prompt}_negative_token_counter`);
|
setupBracketChecking(`${prompt}_prompt`, `${prompt}_negative_token_counter`);
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,73 +1,73 @@
|
||||||
const replaceIcon = (button: HTMLButtonElement, emoji: string[], svg: string) => {
|
const replaceIcon = (button: HTMLButtonElement, emoji: string[], svg: string) => {
|
||||||
if (!button?.textContent) return;
|
if (!button?.textContent) return;
|
||||||
emoji.forEach((e) => {
|
for (const e of emoji) {
|
||||||
if (button?.textContent?.includes(e)) {
|
if (button?.textContent?.includes(e)) {
|
||||||
button.innerHTML = `<span role="img" class="anticon anticon-replace" aria-label={button.textContent}><svg viewBox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true">${svg}</svg></span>`;
|
button.innerHTML = `<span role="img" class="anticon anticon-replace" aria-label={button.textContent}><svg viewBox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor" aria-hidden="true">${svg}</svg></span>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
document.querySelectorAll('button').forEach((button) => {
|
for (const button of document.querySelectorAll('button')) {
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['📂'],
|
['📂'],
|
||||||
'<path d="M880 298.4H521L403.7 186.2a8.15 8.15 0 00-5.5-2.2H144c-17.7 0-32 14.3-32 32v592c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V330.4c0-17.7-14.3-32-32-32zM840 768H184V256h188.5l119.6 114.4H840V768z"></path>',
|
'<path d="M880 298.4H521L403.7 186.2a8.15 8.15 0 00-5.5-2.2H144c-17.7 0-32 14.3-32 32v592c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V330.4c0-17.7-14.3-32-32-32zM840 768H184V256h188.5l119.6 114.4H840V768z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['🔄', '🔁'],
|
['🔄', '🔁'],
|
||||||
'<path d="M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"></path>',
|
'<path d="M909.1 209.3l-56.4 44.1C775.8 155.1 656.2 92 521.9 92 290 92 102.3 279.5 102 511.5 101.7 743.7 289.8 932 521.9 932c181.3 0 335.8-115 394.6-276.1 1.5-4.2-.7-8.9-4.9-10.3l-56.7-19.5a8 8 0 00-10.1 4.8c-1.8 5-3.8 10-5.9 14.9-17.3 41-42.1 77.8-73.7 109.4A344.77 344.77 0 01655.9 829c-42.3 17.9-87.4 27-133.8 27-46.5 0-91.5-9.1-133.8-27A341.5 341.5 0 01279 755.2a342.16 342.16 0 01-73.7-109.4c-17.9-42.4-27-87.4-27-133.9s9.1-91.5 27-133.9c17.3-41 42.1-77.8 73.7-109.4 31.6-31.6 68.4-56.4 109.3-73.8 42.3-17.9 87.4-27 133.8-27 46.5 0 91.5 9.1 133.8 27a341.5 341.5 0 01109.3 73.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.6 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c-.1-6.6-7.8-10.3-13-6.2z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['↙️'],
|
['↙️'],
|
||||||
'<path d="M603.3 327.5l-246 178a7.95 7.95 0 000 12.9l246 178c5.3 3.8 12.7 0 12.7-6.5V643c0-10.2-4.9-19.9-13.2-25.9L457.4 512l145.4-105.2c8.3-6 13.2-15.6 13.2-25.9V334c0-6.5-7.4-10.3-12.7-6.5z"></path><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path>',
|
'<path d="M603.3 327.5l-246 178a7.95 7.95 0 000 12.9l246 178c5.3 3.8 12.7 0 12.7-6.5V643c0-10.2-4.9-19.9-13.2-25.9L457.4 512l145.4-105.2c8.3-6 13.2-15.6 13.2-25.9V334c0-6.5-7.4-10.3-12.7-6.5z"></path><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['🗑️'],
|
['🗑️'],
|
||||||
'<path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path>',
|
'<path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['📋'],
|
['📋'],
|
||||||
'<path d="M832 112H724V72c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v40H500V72c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v40H320c-17.7 0-32 14.3-32 32v120h-96c-17.7 0-32 14.3-32 32v632c0 17.7 14.3 32 32 32h512c17.7 0 32-14.3 32-32v-96h96c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zM664 888H232V336h218v174c0 22.1 17.9 40 40 40h174v338zm0-402H514V336h.2L664 485.8v.2zm128 274h-56V456L544 264H360v-80h68v32c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-32h152v32c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-32h68v576z"></path>',
|
'<path d="M832 112H724V72c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v40H500V72c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v40H320c-17.7 0-32 14.3-32 32v120h-96c-17.7 0-32 14.3-32 32v632c0 17.7 14.3 32 32 32h512c17.7 0 32-14.3 32-32v-96h96c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zM664 888H232V336h218v174c0 22.1 17.9 40 40 40h174v338zm0-402H514V336h.2L664 485.8v.2zm128 274h-56V456L544 264H360v-80h68v32c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-32h152v32c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-32h68v576z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['💾'],
|
['💾'],
|
||||||
'<path d="M893.3 293.3L730.7 130.7c-7.5-7.5-16.7-13-26.7-16V112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V338.5c0-17-6.7-33.2-18.7-45.2zM384 184h256v104H384V184zm456 656H184V184h136v136c0 17.7 14.3 32 32 32h320c17.7 0 32-14.3 32-32V205.8l136 136V840zM512 442c-79.5 0-144 64.5-144 144s64.5 144 144 144 144-64.5 144-144-64.5-144-144-144zm0 224c-44.2 0-80-35.8-80-80s35.8-80 80-80 80 35.8 80 80-35.8 80-80 80z"></path>',
|
'<path d="M893.3 293.3L730.7 130.7c-7.5-7.5-16.7-13-26.7-16V112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V338.5c0-17-6.7-33.2-18.7-45.2zM384 184h256v104H384V184zm456 656H184V184h136v136c0 17.7 14.3 32 32 32h320c17.7 0 32-14.3 32-32V205.8l136 136V840zM512 442c-79.5 0-144 64.5-144 144s64.5 144 144 144 144-64.5 144-144-64.5-144-144-144zm0 224c-44.2 0-80-35.8-80-80s35.8-80 80-80 80 35.8 80 80-35.8 80-80 80z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['🎲️'],
|
['🎲️'],
|
||||||
'<path d="M136 552h63.6c4.4 0 8-3.6 8-8V288.7h528.6v72.6c0 1.9.6 3.7 1.8 5.2a8.3 8.3 0 0011.7 1.4L893 255.4c4.3-5 3.6-10.3 0-13.2L749.7 129.8a8.22 8.22 0 00-5.2-1.8c-4.6 0-8.4 3.8-8.4 8.4V209H199.7c-39.5 0-71.7 32.2-71.7 71.8V544c0 4.4 3.6 8 8 8zm752-80h-63.6c-4.4 0-8 3.6-8 8v255.3H287.8v-72.6c0-1.9-.6-3.7-1.8-5.2a8.3 8.3 0 00-11.7-1.4L131 768.6c-4.3 5-3.6 10.3 0 13.2l143.3 112.4c1.5 1.2 3.3 1.8 5.2 1.8 4.6 0 8.4-3.8 8.4-8.4V815h536.6c39.5 0 71.7-32.2 71.7-71.8V480c-.2-4.4-3.8-8-8.2-8z"></path>',
|
'<path d="M136 552h63.6c4.4 0 8-3.6 8-8V288.7h528.6v72.6c0 1.9.6 3.7 1.8 5.2a8.3 8.3 0 0011.7 1.4L893 255.4c4.3-5 3.6-10.3 0-13.2L749.7 129.8a8.22 8.22 0 00-5.2-1.8c-4.6 0-8.4 3.8-8.4 8.4V209H199.7c-39.5 0-71.7 32.2-71.7 71.8V544c0 4.4 3.6 8 8 8zm752-80h-63.6c-4.4 0-8 3.6-8 8v255.3H287.8v-72.6c0-1.9-.6-3.7-1.8-5.2a8.3 8.3 0 00-11.7-1.4L131 768.6c-4.3 5-3.6 10.3 0 13.2l143.3 112.4c1.5 1.2 3.3 1.8 5.2 1.8 4.6 0 8.4-3.8 8.4-8.4V815h536.6c39.5 0 71.7-32.2 71.7-71.8V480c-.2-4.4-3.8-8-8.2-8z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['♻️'],
|
['♻️'],
|
||||||
'<path d="M793 242H366v-74c0-6.7-7.7-10.4-12.9-6.3l-142 112a8 8 0 000 12.6l142 112c5.2 4.1 12.9.4 12.9-6.3v-74h415v470H175c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h618c35.3 0 64-28.7 64-64V306c0-35.3-28.7-64-64-64z"></path>',
|
'<path d="M793 242H366v-74c0-6.7-7.7-10.4-12.9-6.3l-142 112a8 8 0 000 12.6l142 112c5.2 4.1 12.9.4 12.9-6.3v-74h415v470H175c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h618c35.3 0 64-28.7 64-64V306c0-35.3-28.7-64-64-64z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['🪄'],
|
['🪄'],
|
||||||
'<defs><style></style></defs><path d="M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6a25.95 25.95 0 0025.6 30.4h723c1.5 0 3-.1 4.4-.4a25.88 25.88 0 0021.2-30zM204 390h272V182h72v208h272v104H204V390zm468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z"></path>',
|
'<defs><style></style></defs><path d="M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6a25.95 25.95 0 0025.6 30.4h723c1.5 0 3-.1 4.4-.4a25.88 25.88 0 0021.2-30zM204 390h272V182h72v208h272v104H204V390zm468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['⚙️'],
|
['⚙️'],
|
||||||
'<path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path>',
|
'<path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['➡️'],
|
['➡️'],
|
||||||
'<path d="M666.7 505.5l-246-178A8 8 0 00408 334v46.9c0 10.2 4.9 19.9 13.2 25.9L566.6 512 421.2 617.2c-8.3 6-13.2 15.6-13.2 25.9V690c0 6.5 7.4 10.3 12.7 6.5l246-178c4.4-3.2 4.4-9.8 0-13z"></path><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path>',
|
'<path d="M666.7 505.5l-246-178A8 8 0 00408 334v46.9c0 10.2 4.9 19.9 13.2 25.9L566.6 512 421.2 617.2c-8.3 6-13.2 15.6-13.2 25.9V690c0 6.5 7.4 10.3 12.7 6.5l246-178c4.4-3.2 4.4-9.8 0-13z"></path><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path>',
|
||||||
);
|
);
|
||||||
replaceIcon(
|
replaceIcon(
|
||||||
button,
|
button,
|
||||||
['⇅'],
|
['⇅'],
|
||||||
'<path d="M847.9 592H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h605.2L612.9 851c-4.1 5.2-.4 13 6.3 13h72.5c4.9 0 9.5-2.2 12.6-6.1l168.8-214.1c16.5-21 1.6-51.8-25.2-51.8zM872 356H266.8l144.3-183c4.1-5.2.4-13-6.3-13h-72.5c-4.9 0-9.5 2.2-12.6 6.1L150.9 380.2c-16.5 21-1.6 51.8 25.1 51.8h696c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"></path>',
|
'<path d="M847.9 592H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h605.2L612.9 851c-4.1 5.2-.4 13 6.3 13h72.5c4.9 0 9.5-2.2 12.6-6.1l168.8-214.1c16.5-21 1.6-51.8-25.2-51.8zM872 356H266.8l144.3-183c4.1-5.2.4-13-6.3-13h-72.5c-4.9 0-9.5 2.2-12.6 6.1L150.9 380.2c-16.5 21-1.6 51.8 25.1 51.8h696c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"></path>',
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
export default () => {
|
export default () => {
|
||||||
// favicon
|
// favicon
|
||||||
const favicon: HTMLLinkElement = document.createElement('link');
|
const favicon: HTMLLinkElement = document.createElement('link');
|
||||||
favicon.rel = 'icon';
|
favicon.rel = 'icon';
|
||||||
favicon.type = 'image/svg+xml';
|
favicon.type = 'image/svg+xml';
|
||||||
favicon.href =
|
favicon.href =
|
||||||
'https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg';
|
'https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg';
|
||||||
document.getElementsByTagName('head')[0].appendChild(favicon);
|
document.querySelectorAll('head')[0].append(favicon);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { create } from 'zustand';
|
import {create} from 'zustand';
|
||||||
import { devtools } from 'zustand/middleware';
|
import {devtools} from 'zustand/middleware';
|
||||||
|
|
||||||
const SETTING_KEY = 'SD-KITCHEN-SETTING';
|
const SETTING_KEY = 'SD-KITCHEN-SETTING';
|
||||||
|
|
||||||
|
|
@ -17,16 +17,16 @@ export interface WebuiSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultSetting: WebuiSetting = {
|
export const defaultSetting: WebuiSetting = {
|
||||||
promotTextarea: 'scroll',
|
enableExtraNetworkSidebar: true,
|
||||||
sidebarExpand: true,
|
extraNetworkCardSize: 86,
|
||||||
sidebarFixedMode: 'fixed',
|
extraNetworkFixedMode: 'fixed',
|
||||||
sidebarWidth: 280,
|
extraNetworkSidebarExpand: true,
|
||||||
enableExtraNetworkSidebar: true,
|
extraNetworkSidebarWidth: 340,
|
||||||
extraNetworkSidebarExpand: true,
|
promotTextarea: 'scroll',
|
||||||
extraNetworkFixedMode: 'fixed',
|
sidebarExpand: true,
|
||||||
extraNetworkSidebarWidth: 340,
|
sidebarFixedMode: 'fixed',
|
||||||
extraNetworkCardSize: 86,
|
sidebarWidth: 280,
|
||||||
svgIcon: false,
|
svgIcon: false,
|
||||||
};
|
};
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
currentTab: string;
|
currentTab: string;
|
||||||
|
|
@ -39,33 +39,33 @@ export interface AppState {
|
||||||
themeMode: 'light' | 'dark';
|
themeMode: 'light' | 'dark';
|
||||||
}
|
}
|
||||||
export const useAppStore = create<AppState>()(
|
export const useAppStore = create<AppState>()(
|
||||||
devtools((set, get) => ({
|
devtools((set, get) => ({
|
||||||
themeMode: 'light',
|
currentTab: 'tab_txt2img',
|
||||||
setting: defaultSetting,
|
onInit: () => {
|
||||||
currentTab: 'tab_txt2img',
|
get().onLoadSetting();
|
||||||
setCurrentTab: () => {
|
},
|
||||||
const currentTab = get_uiCurrentTabContent().id;
|
onLoadSetting: () => {
|
||||||
if (currentTab !== get().currentTab) set({ currentTab }, false, 'setCurrentTab');
|
let setting: any = localStorage.getItem(SETTING_KEY);
|
||||||
},
|
if (setting) {
|
||||||
onSetThemeMode: (themeMode) => {
|
setting = JSON.parse(setting);
|
||||||
set(() => ({ themeMode }), false, 'onSetThemeMode');
|
} else {
|
||||||
},
|
setting = defaultSetting;
|
||||||
onLoadSetting: () => {
|
localStorage.setItem(SETTING_KEY, JSON.stringify(defaultSetting));
|
||||||
let setting: any = localStorage.getItem(SETTING_KEY);
|
}
|
||||||
if (setting) {
|
set(() => ({setting: {...defaultSetting, ...setting}}), false, 'onLoadSetting');
|
||||||
setting = JSON.parse(setting);
|
},
|
||||||
} else {
|
onSetSetting: (setting) => {
|
||||||
setting = defaultSetting;
|
localStorage.setItem(SETTING_KEY, JSON.stringify(setting));
|
||||||
localStorage.setItem(SETTING_KEY, JSON.stringify(defaultSetting));
|
set(() => ({setting}), false, 'onSetSetting');
|
||||||
}
|
},
|
||||||
set(() => ({ setting: { ...defaultSetting, ...setting } }), false, 'onLoadSetting');
|
onSetThemeMode: (themeMode) => {
|
||||||
},
|
set(() => ({themeMode}), false, 'onSetThemeMode');
|
||||||
onSetSetting: (setting) => {
|
},
|
||||||
localStorage.setItem(SETTING_KEY, JSON.stringify(setting));
|
setCurrentTab: () => {
|
||||||
set(() => ({ setting }), false, 'onSetSetting');
|
const currentTab = get_uiCurrentTabContent().id;
|
||||||
},
|
if (currentTab !== get().currentTab) set({currentTab}, false, 'setCurrentTab');
|
||||||
onInit: () => {
|
},
|
||||||
get().onLoadSetting();
|
setting: defaultSetting,
|
||||||
},
|
themeMode: 'light',
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
> label {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.wrap.svelte-1p9xokt.svelte-1p9xokt.svelte-1p9xokt {
|
.wrap.svelte-1p9xokt.svelte-1p9xokt.svelte-1p9xokt {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
|
|
||||||
|
|
@ -35,9 +41,9 @@
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[id$='_results'],
|
||||||
#tab_image_browser,
|
#tab_image_browser,
|
||||||
#tab_dreambooth_interface,
|
#tab_dreambooth_interface {
|
||||||
[id$='_results'] {
|
|
||||||
.block.gradio-accordion.svelte-mppz8v.padded {
|
.block.gradio-accordion.svelte-mppz8v.padded {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -76,9 +82,3 @@
|
||||||
div.svelte-1oo81b7 > *:not(.absolute) {
|
div.svelte-1oo81b7 > *:not(.absolute) {
|
||||||
border-radius: var(--border-radius) !important;
|
border-radius: var(--border-radius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.head {
|
|
||||||
> label {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,14 @@
|
||||||
#txt2img_extra_networks,
|
.extra-network-thumbs {
|
||||||
#img2img_extra_networks {
|
.name {
|
||||||
.tabitem.gradio-tabitem.svelte-19hvt5v {
|
overflow: hidden;
|
||||||
padding: 0;
|
display: block;
|
||||||
|
|
||||||
|
font-size: 12px !important;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: var(--fill-available);
|
|
||||||
max-width: var(--fill-available);
|
|
||||||
max-height: 36px !important;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
height: 32px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-networks {
|
.extra-networks {
|
||||||
|
|
@ -140,15 +133,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-network-thumbs {
|
#txt2img_extra_networks,
|
||||||
.name {
|
#img2img_extra_networks {
|
||||||
overflow: hidden;
|
.tabitem.gradio-tabitem.svelte-19hvt5v {
|
||||||
display: block;
|
padding: 0;
|
||||||
|
|
||||||
font-size: 12px !important;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: var(--fill-available);
|
||||||
|
max-width: var(--fill-available);
|
||||||
|
max-height: 36px !important;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 32px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
#tab_txt2img,
|
#tab_txt2img,
|
||||||
#tab_img2img {
|
#tab_img2img {
|
||||||
|
[id$='_settings'] {
|
||||||
|
div.svelte-15lo0d8 > *,
|
||||||
|
div.svelte-15lo0d8 > .form > * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#txt2img_settings,
|
#txt2img_settings,
|
||||||
#img2img_settings {
|
#img2img_settings {
|
||||||
.block.gradio-checkbox {
|
.block.gradio-checkbox {
|
||||||
|
|
@ -34,6 +41,10 @@
|
||||||
border-radius: var(--border-radius) !important;
|
border-radius: var(--border-radius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-buttons button {
|
||||||
|
min-width: min(160px, 100%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
[id$='2img_tools'] > div {
|
[id$='2img_tools'] > div {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -43,10 +54,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-buttons button {
|
|
||||||
min-width: min(160px, 100%) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#img2img_label_copy_to_img2img {
|
#img2img_label_copy_to_img2img {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -58,13 +65,6 @@
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[id$='_settings'] {
|
|
||||||
div.svelte-15lo0d8 > *,
|
|
||||||
div.svelte-15lo0d8 > .form > * {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#script_list {
|
#script_list {
|
||||||
margin-top: 0 !important;
|
margin-top: 0 !important;
|
||||||
margin-bottom: var(--size-ms) !important;
|
margin-bottom: var(--size-ms) !important;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import {Theme as AntdStyleTheme} from 'antd-style';
|
||||||
|
|
||||||
|
declare module 'styled-components' {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
export interface DefaultTheme extends AntdStyleTheme {}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import React from 'react';
|
import {type HTMLAttributes} from 'react';
|
||||||
|
|
||||||
export type DivProps = React.DetailedHTMLProps<
|
export type DivProps = HTMLAttributes<HTMLDivElement>;
|
||||||
React.HTMLAttributes<HTMLDivElement>,
|
|
||||||
HTMLDivElement
|
export type SvgProps = HTMLAttributes<SVGSVGElement>;
|
||||||
>;
|
|
||||||
|
export type ImgProps = HTMLAttributes<HTMLImageElement>;
|
||||||
|
|
||||||
|
export type InputProps = HTMLAttributes<HTMLInputElement>;
|
||||||
|
|
||||||
|
export type TextAreaProps = HTMLAttributes<HTMLTextAreaElement>;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ declare const all_gallery_buttons: () => Element[];
|
||||||
declare const selected_gallery_button: () => Element | null;
|
declare const selected_gallery_button: () => Element | null;
|
||||||
declare const selected_gallery_index: () => number;
|
declare const selected_gallery_index: () => number;
|
||||||
declare const extract_image_from_gallery: (gallery: Element[]) => Element[];
|
declare const extract_image_from_gallery: (gallery: Element[]) => Element[];
|
||||||
declare const args_to_array: (args: IArguments) => any[];
|
declare const arguments_to_array: (arguments_: IArguments) => any[];
|
||||||
declare const switch_to_txt2img: () => any[];
|
declare const switch_to_txt2img: () => any[];
|
||||||
declare const switch_to_img2img_tab: (no: number) => void;
|
declare const switch_to_img2img_tab: (no: number) => void;
|
||||||
declare const switch_to_img2img: () => any[];
|
declare const switch_to_img2img: () => any[];
|
||||||
|
|
@ -14,15 +14,15 @@ declare const switch_to_inpaint_sketch: () => any[];
|
||||||
declare const switch_to_inpaint: () => any[];
|
declare const switch_to_inpaint: () => any[];
|
||||||
declare const switch_to_extras: () => any[];
|
declare const switch_to_extras: () => any[];
|
||||||
declare const get_tab_index: (tabId: string) => number;
|
declare const get_tab_index: (tabId: string) => number;
|
||||||
declare const create_tab_index_args: (tabId: string, args: any[]) => any[];
|
declare const create_tab_index_arguments: (tabId: string, arguments_: any[]) => any[];
|
||||||
declare const get_img2img_tab_index: () => any[];
|
declare const get_img2img_tab_index: () => any[];
|
||||||
declare const create_submit_args: (args: any[]) => any[];
|
declare const create_submit_arguments: (arguments_: any[]) => any[];
|
||||||
declare const showSubmitButtons: (tabname: string, show: boolean) => void;
|
declare const showSubmitButtons: (tabname: string, show: boolean) => void;
|
||||||
declare const submit: () => any[];
|
declare const submit: () => any[];
|
||||||
declare const submit_img2img: () => any[];
|
declare const submit_img2img: () => any[];
|
||||||
declare const modelmerger: () => any[];
|
declare const modelmerger: () => any[];
|
||||||
declare const ask_for_style_name: (
|
declare const ask_for_style_name: (
|
||||||
arg0: any,
|
argument0: any,
|
||||||
prompt_text: string,
|
prompt_text: string,
|
||||||
negative_prompt_text: string,
|
negative_prompt_text: string,
|
||||||
) => [string, string, string];
|
) => [string, string, string];
|
||||||
|
|
@ -30,8 +30,8 @@ declare const confirm_clear_prompt: (prompt: string, negative_prompt: string) =>
|
||||||
declare const recalculatePromptTokens: (name: string) => void;
|
declare const recalculatePromptTokens: (name: string) => void;
|
||||||
declare const recalculate_prompts_txt2img: () => any[];
|
declare const recalculate_prompts_txt2img: () => any[];
|
||||||
declare const recalculate_prompts_img2img: () => any[];
|
declare const recalculate_prompts_img2img: () => any[];
|
||||||
declare const update_txt2img_tokens: (...args: any[]) => any;
|
declare const update_txt2img_tokens: (...arguments_: any[]) => any;
|
||||||
declare const update_img2img_tokens: (...args: any[]) => any;
|
declare const update_img2img_tokens: (...arguments_: any[]) => any;
|
||||||
declare const restart_reload: () => any[];
|
declare const restart_reload: () => any[];
|
||||||
declare const updateInput: (target: Element) => void;
|
declare const updateInput: (target: Element) => void;
|
||||||
declare const selectCheckpoint: (name: string) => void;
|
declare const selectCheckpoint: (name: string) => void;
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,19 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"baseUrl": ".",
|
||||||
"useDefineForClassFields": true,
|
"declaration": true,
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
"downlevelIteration": true,
|
||||||
"allowJs": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"jsx": "react-jsx",
|
||||||
"esModuleInterop": false,
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"strict": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"incremental": true,
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
},
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true
|
||||||
},
|
},
|
||||||
"exclude": ["javascript"],
|
"exclude": ["javascript"],
|
||||||
"extends": "./src/.umi/tsconfig.json",
|
"extends": "./src/.umi/tsconfig.json",
|
||||||
"include": ["src"]
|
"include": ["src", "typings.d.ts", "*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue