🔧 chore: merge
parent
71970fec59
commit
47cb06cf8b
|
|
@ -4,5 +4,4 @@
|
|||
git add .
|
||||
npx --no-install lint-staged
|
||||
npm run test
|
||||
npm run build
|
||||
git add .
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,55 +1,16 @@
|
|||
import { memo, useCallback, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import TagList, { PromptType, TagItem } from './TagList';
|
||||
import { useStyles } from './style';
|
||||
import { formatPrompt } from './utils';
|
||||
|
||||
/******************************************************
|
||||
*********************** Style *************************
|
||||
******************************************************/
|
||||
|
||||
const View = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
`;
|
||||
|
||||
const ButtonGroup = styled.div`
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
`;
|
||||
|
||||
const Button = styled.button`
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--input-text-size);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
|
||||
background: var(--button-secondary-background-fill);
|
||||
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
`;
|
||||
|
||||
/******************************************************
|
||||
************************* Dom *************************
|
||||
******************************************************/
|
||||
|
||||
interface PromptProps {
|
||||
type: PromptType;
|
||||
}
|
||||
|
||||
const Prompt = memo<PromptProps>(({ type }) => {
|
||||
const [tags, setTags] = useState<TagItem[]>([]);
|
||||
const { styles } = useStyles();
|
||||
|
||||
const id =
|
||||
type === 'positive' ? "[id$='2img_prompt'] textarea" : "[id$='2img_neg_prompt'] textarea";
|
||||
|
|
@ -84,17 +45,27 @@ const Prompt = memo<PromptProps>(({ type }) => {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<div className={styles.promptView}>
|
||||
<TagList setTags={setTags} setValue={setCurrentValue} tags={tags} type={type} />
|
||||
<ButtonGroup>
|
||||
<Button onClick={getValue} title="Load Prompt">
|
||||
<div className={styles.buttonGroup}>
|
||||
<button
|
||||
className="lg secondary gradio-button tool svelte-1ipelgc"
|
||||
onClick={getValue}
|
||||
title="Load Prompt"
|
||||
type="button"
|
||||
>
|
||||
🔄
|
||||
</Button>
|
||||
<Button onClick={setValue} title="Set Prompt">
|
||||
</button>
|
||||
<button
|
||||
className="lg secondary gradio-button tool svelte-1ipelgc"
|
||||
onClick={setValue}
|
||||
title="Set Prompt"
|
||||
type="button"
|
||||
>
|
||||
➡️
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</View>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,232 +0,0 @@
|
|||
import { type FC, memo, useCallback, useMemo } from 'react';
|
||||
import { WithContext, ReactTagsProps as WithContextProps } from 'react-tag-input';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { genTagType, suggestions } from './utils';
|
||||
|
||||
export interface TagItem {
|
||||
className?: string;
|
||||
id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export type PromptType = 'positive' | 'negative';
|
||||
|
||||
interface ReactTagsProps extends WithContextProps {
|
||||
editable?: boolean;
|
||||
onTagUpdate?: (editIndex: number, tag: TagItem) => void;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const ReactTags: FC<ReactTagsProps> = WithContext;
|
||||
|
||||
const View = styled.div<{ type: PromptType }>`
|
||||
/* Styles for the input */
|
||||
.ReactTags__editTagInput,
|
||||
.ReactTags__tagInput {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
input,
|
||||
input:focus {
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--input-text-size);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
color: var(--body-text-color);
|
||||
|
||||
background: var(--input-background-fill);
|
||||
border: var(--input-border-width) solid var(--input-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for selected tags */
|
||||
.ReactTags__tags.react-tags-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ReactTags__selected {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
|
||||
span.ReactTags__tag {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
color: ${({ type }) => (type === 'positive' ? 'var(--green-9)' : 'var(--magenta-9)')};
|
||||
|
||||
background: var(--button-secondary-background-fill);
|
||||
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
|
||||
&:hover {
|
||||
color: ${({ type }) => (type === 'positive' ? 'var(--green-10)' : 'var(--magenta-10)')};
|
||||
}
|
||||
}
|
||||
|
||||
a.ReactTags__remove {
|
||||
cursor: pointer;
|
||||
margin-left: 5px;
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for suggestions */
|
||||
.ReactTags__suggestions {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
ul {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
width: 248px;
|
||||
max-height: 480px;
|
||||
padding: 0;
|
||||
|
||||
list-style-type: none;
|
||||
|
||||
background: var(--color-bg-container);
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
|
||||
&.ReactTags__activeSuggestion {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
mark {
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
background: var(--color-primary-hover);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ReactTags__remove {
|
||||
cursor: pointer;
|
||||
color: var(--color-text);
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ReactTags__lora {
|
||||
background: var(--cyan-2) !important;
|
||||
border-color: var(--cyan-3) !important;
|
||||
}
|
||||
|
||||
.ReactTags__hypernet {
|
||||
background: var(--purple-2) !important;
|
||||
border-color: var(--purple-3) !important;
|
||||
}
|
||||
|
||||
.ReactTags__embedding {
|
||||
background: var(--orange-2) !important;
|
||||
border-color: var(--orange-3) !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const KeyCodes = {
|
||||
comma: 188,
|
||||
enter: 13,
|
||||
};
|
||||
|
||||
const delimiters = [KeyCodes.comma, KeyCodes.enter];
|
||||
|
||||
interface TagListProps {
|
||||
setTags: (tags: TagItem[]) => void;
|
||||
setValue: (tags: TagItem[]) => void;
|
||||
tags: TagItem[];
|
||||
type: PromptType;
|
||||
}
|
||||
|
||||
const TagList = memo<TagListProps>(({ tags, setTags, type, setValue }) => {
|
||||
const handleDelete = useCallback(
|
||||
(index_: number) => {
|
||||
const newTags = tags.filter((tag, index) => index !== index_);
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleAddition = useCallback(
|
||||
(tag: TagItem) => {
|
||||
const newTags = [...tags, genTagType(tag)];
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleDrag = useCallback(
|
||||
(tag: TagItem, currentPos: number, newPos: number) => {
|
||||
const newTags = [...tags];
|
||||
newTags.splice(currentPos, 1);
|
||||
newTags.splice(newPos, 0, genTagType(tag));
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleTagUpdate = useCallback(
|
||||
(index: number, tag: TagItem) => {
|
||||
const newTags = [...tags];
|
||||
newTags[index] = genTagType(tag);
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const suggestionData = useMemo(() => suggestions[type], [type]);
|
||||
|
||||
return (
|
||||
<View type={type}>
|
||||
<ReactTags
|
||||
autocomplete
|
||||
delimiters={delimiters}
|
||||
editable
|
||||
handleAddition={handleAddition}
|
||||
handleDelete={handleDelete}
|
||||
handleDrag={handleDrag}
|
||||
inline
|
||||
inputFieldPosition="bottom"
|
||||
onTagUpdate={handleTagUpdate}
|
||||
suggestions={suggestionData}
|
||||
tags={tags}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
export default TagList;
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import { type FC, memo, useCallback, useMemo } from 'react';
|
||||
import { WithContext, ReactTagsProps as WithContextProps } from 'react-tag-input';
|
||||
|
||||
import { genTagType, suggestions } from '../utils';
|
||||
import { useStyles } from './style';
|
||||
|
||||
export interface TagItem {
|
||||
className?: string;
|
||||
id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export type PromptType = 'positive' | 'negative';
|
||||
|
||||
interface ReactTagsProps extends WithContextProps {
|
||||
editable?: boolean;
|
||||
onTagUpdate?: (editIndex: number, tag: TagItem) => void;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const ReactTags: FC<ReactTagsProps> = WithContext;
|
||||
|
||||
const KeyCodes = {
|
||||
comma: 188,
|
||||
enter: 13,
|
||||
};
|
||||
|
||||
const delimiters = [KeyCodes.comma, KeyCodes.enter];
|
||||
|
||||
interface TagListProps {
|
||||
setTags: (tags: TagItem[]) => void;
|
||||
setValue: (tags: TagItem[]) => void;
|
||||
tags: TagItem[];
|
||||
type: PromptType;
|
||||
}
|
||||
|
||||
const TagList = memo<TagListProps>(({ tags, setTags, type, setValue }) => {
|
||||
const { styles } = useStyles(type);
|
||||
const handleDelete = useCallback(
|
||||
(index_: number) => {
|
||||
const newTags = tags.filter((tag, index) => index !== index_);
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleAddition = useCallback(
|
||||
(tag: TagItem) => {
|
||||
const newTags = [...tags, genTagType(tag)];
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleDrag = useCallback(
|
||||
(tag: TagItem, currentPos: number, newPos: number) => {
|
||||
const newTags = [...tags];
|
||||
newTags.splice(currentPos, 1);
|
||||
newTags.splice(newPos, 0, genTagType(tag));
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const handleTagUpdate = useCallback(
|
||||
(index: number, tag: TagItem) => {
|
||||
const newTags = [...tags];
|
||||
newTags[index] = genTagType(tag);
|
||||
setTags(newTags);
|
||||
setValue(newTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
const suggestionData = useMemo(() => suggestions[type], [type]);
|
||||
|
||||
return (
|
||||
<div className={styles}>
|
||||
<ReactTags
|
||||
autocomplete
|
||||
delimiters={delimiters}
|
||||
editable
|
||||
handleAddition={handleAddition}
|
||||
handleDelete={handleDelete}
|
||||
handleDrag={handleDrag}
|
||||
inline
|
||||
inputFieldPosition="bottom"
|
||||
onTagUpdate={handleTagUpdate}
|
||||
suggestions={suggestionData}
|
||||
tags={tags}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default TagList;
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(
|
||||
({ css }, type: 'positive' | 'negative') => css`
|
||||
/* Styles for the input */
|
||||
.ReactTags__editTagInput,
|
||||
.ReactTags__tagInput {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
input,
|
||||
input:focus {
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--input-text-size);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
color: var(--body-text-color);
|
||||
|
||||
background: var(--input-background-fill);
|
||||
border: var(--input-border-width) solid var(--input-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for selected tags */
|
||||
.ReactTags__tags.react-tags-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ReactTags__selected {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
|
||||
span.ReactTags__tag {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
color: ${type === 'positive' ? 'var(--green-9)' : 'var(--magenta-9)'};
|
||||
|
||||
background: var(--button-secondary-background-fill);
|
||||
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
|
||||
&:hover {
|
||||
color: ${type === 'positive' ? 'var(--green-10)' : 'var(--magenta-10)'};
|
||||
}
|
||||
}
|
||||
|
||||
a.ReactTags__remove {
|
||||
cursor: pointer;
|
||||
margin-left: 5px;
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for suggestions */
|
||||
.ReactTags__suggestions {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
ul {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
width: 248px;
|
||||
max-height: 480px;
|
||||
padding: 0;
|
||||
|
||||
list-style-type: none;
|
||||
|
||||
background: var(--color-bg-container);
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
|
||||
&.ReactTags__activeSuggestion {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
mark {
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
background: var(--color-primary-hover);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ReactTags__remove {
|
||||
cursor: pointer;
|
||||
color: var(--color-text);
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ReactTags__lora {
|
||||
background: var(--cyan-2) !important;
|
||||
border-color: var(--cyan-3) !important;
|
||||
}
|
||||
|
||||
.ReactTags__hypernet {
|
||||
background: var(--purple-2) !important;
|
||||
border-color: var(--purple-3) !important;
|
||||
}
|
||||
|
||||
.ReactTags__embedding {
|
||||
background: var(--orange-2) !important;
|
||||
border-color: var(--orange-3) !important;
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
|
@ -1,48 +1,18 @@
|
|||
import { memo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { useStyles } from '@/slots/PromptEditor/style';
|
||||
|
||||
import Prompt from './Prompt';
|
||||
|
||||
/******************************************************
|
||||
*********************** Style *************************
|
||||
******************************************************/
|
||||
|
||||
const View = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
margin-bottom: 1em;
|
||||
`;
|
||||
|
||||
const Desc = styled.div`
|
||||
position: relative;
|
||||
z-index: var(--layer-4);
|
||||
|
||||
margin-bottom: -10px;
|
||||
padding: var(--block-title-padding);
|
||||
|
||||
font-size: var(--block-title-text-size);
|
||||
font-weight: var(--block-title-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
color: var(--block-title-text-color);
|
||||
|
||||
background: var(--block-title-background-fill);
|
||||
border: solid var(--block-title-border-width) var(--block-title-border-color);
|
||||
border-radius: var(--block-title-radius);
|
||||
`;
|
||||
|
||||
/******************************************************
|
||||
************************* Dom *************************
|
||||
******************************************************/
|
||||
|
||||
const PromptEditor = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
return (
|
||||
<View>
|
||||
<Desc>Positive</Desc>
|
||||
<div className={styles.view}>
|
||||
<span style={{ marginBottom: -10 }}>Positive</span>
|
||||
<Prompt type="positive" />
|
||||
<Desc>Negative</Desc>
|
||||
<span style={{ marginBottom: -10 }}>Negative</span>
|
||||
<Prompt type="negative" />
|
||||
</View>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css }) => ({
|
||||
button: css`
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
padding: var(--input-padding);
|
||||
|
||||
font-size: var(--input-text-size);
|
||||
font-weight: var(--input-text-weight);
|
||||
line-height: var(--line-sm);
|
||||
|
||||
background: var(--button-secondary-background-fill);
|
||||
border: var(--button-border-width) solid var(--button-secondary-border-color);
|
||||
border-radius: var(--input-radius);
|
||||
`,
|
||||
buttonGroup: css`
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
`,
|
||||
promptView: css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
`,
|
||||
view: css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
margin-bottom: 1em;
|
||||
`,
|
||||
}));
|
||||
|
|
@ -66,13 +66,13 @@ const SettingForm = memo(() => {
|
|||
|
||||
const onReset = useCallback(() => {
|
||||
onSetSetting(defaultSetting);
|
||||
(gradioApp().querySelector('#settings_restart_gradio') as HTMLButtonElement)?.click();
|
||||
location.reload();
|
||||
}, []);
|
||||
|
||||
const onFinish = useCallback(
|
||||
(value: WebuiSetting) => {
|
||||
onSetSetting({ ...value, neutralColor, primaryColor });
|
||||
(gradioApp().querySelector('#settings_restart_gradio') as HTMLButtonElement)?.click();
|
||||
location.reload();
|
||||
},
|
||||
[primaryColor, neutralColor],
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue