🚀 chore: update stuff

main
canisminor1990 2023-04-08 23:57:52 +08:00
parent 6a196928e4
commit 9616d906ea
37 changed files with 10122 additions and 483 deletions

3
.changelogrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
displayTypes: ['feat', 'fix', 'styles', 'pref'],
}

16
.editorconfig Normal file
View File

@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
displayTypes: ['feat', 'fix', 'styles', 'pref'],
};

7
.eslintrc.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
extends: require.resolve('@umijs/lint/dist/config/eslint'),
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-param-reassign': 1,
},
}

14
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,14 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: 'npm' # See documentation for possible values
directory: '/' # Location of package manifests
open-pull-requests-limit: 20
schedule:
interval: 'daily'
time: '19:00'
timezone: 'Asia/Shanghai'

32
.github/workflows/auto-merge.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Dependabot Auto Merge
on:
pull_request_target:
types: [labeled, edited]
jobs:
merge:
if: contains(github.event.pull_request.labels.*.name, 'dependencies')
name: Dependabot Auto Merge
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install deps
run: pnpm install
- name: Merge
uses: ahmadnassri/action-dependabot-auto-merge@v2
with:
command: merge
target: minor
github-token: ${{ secrets.GH_TOKEN }}

57
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: Build and Release
on:
push:
branches:
- master
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install deps
run: pnpm install
- name: Test
run: pnpm run test
build:
needs: test
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install deps
run: pnpm install
- name: Build
run: pnpm run build
- name: Release
id: release
run: pnpm run release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}

24
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: Test CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install deps
run: pnpm install
- name: lint
run: pnpm run test

View File

@ -1,5 +0,0 @@
{
"hooks": {
"pre-commit" : "lint-staged",
}
}

View File

@ -1,3 +1,26 @@
**/*.svg
**/*.ejs
**/*.html
.umi
.umi-production
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.jpg
*.webp
*.toml
*.py
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.idea
.husky
.npmrc
.env
.env.local

View File

@ -1,7 +1,7 @@
{
"trailingComma": "all",
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"arrowParens": "always",
"singleQuote": true
}
"semi": false,
"singleQuote": true,
"printWidth": 120
}

7
.prettierrc.json Normal file
View File

@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"printWidth": 120
}

4
.releaserc.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
extends: ['semantic-release-config-gitmoji'],
branches: ['master'],
}

1
.stylelintrc.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('@umijs/lint/dist/config/stylelint')

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 CanisMinor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,72 @@
# Kitchen Theme for stable-diffusion-web-ui
<p align="center">
<img width="160" src="https://gw.alipayobjects.com/mdn/rms_7d1485/afts/img/A*XDYxSJXBjjwAAAAAAAAAAAAAARQnAQ">
</p>
<h1 align="center">Kitchen Stable Diffusion WebUI</h1>
> ⚠️⚠️⚠️ Warning: minimum requirements gradio-3.23.0 & sd-webui [4c1ad74](https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/4c1ad743e3baf1246db0711aa0107debf036a12b)
<div align="center">
Kitchen Theme for <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui" target="_blank">AUTOMATIC1111/stable-diffusion-web-ui</a>
<br/>
<br/>
<!-- SHIELD GROUP -->
[![release][release-shield]][release-url]
[![releaseDate][release-date-shield]][release-date-url]
[![ciTest][ci-test-shield]][ci-test-url]
[![ciRelease][ci-release-shield]][ci-release-url]
[![contributors][contributors-shield]][contributors-url]
[![forks][forks-shield]][forks-url]
[![stargazers][stargazers-shield]][stargazers-url]
[![issues][issues-shield]][issues-url]
<!-- SHIELD LINK GROUP -->
<!-- release -->
[release-shield]: https://img.shields.io/github/v/release/canisminor1990/sd-web-ui-kitchen-theme?style=flat&sort=semver&logo=github
[release-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/releases
<!-- releaseDate -->
[release-date-shield]: https://img.shields.io/github/release-date/canisminor1990/sd-web-ui-kitchen-theme?style=flat
[release-date-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/releases
<!-- ciTest -->
[ci-test-shield]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/workflows/Test%20CI/badge.svg
[ci-test-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/actions/workflows/test.yml
<!-- ciRelease -->
[ci-release-shield]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/workflows/Build%20and%20Release/badge.svg
[ci-release-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/actions/workflows/release.yml
<!-- contributors -->
[contributors-shield]: https://img.shields.io/github/contributors/canisminor1990/sd-web-ui-kitchen-theme.svg?style=flat
[contributors-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/graphs/contributors
<!-- forks -->
[forks-shield]: https://img.shields.io/github/forks/canisminor1990/sd-web-ui-kitchen-theme.svg?style=flat
[forks-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/network/members
<!-- stargazers -->
[stargazers-shield]: https://img.shields.io/github/stars/canisminor1990/sd-web-ui-kitchen-theme.svg?style=flat
[stargazers-url]: https://github.com/canisminor1990/sd-web-ui-kitchen-theme/stargazers
<!-- issues -->
[issues-shield]: https://img.shields.io/github/issues/canisminor1990/sd-web-ui-kitchen-theme.svg?style=flat
[issues-url]: https://img.shields.io/github/issues/canisminor1990/sd-web-ui-kitchen-theme.svg?style=flat
</div>
<br/>
> ⚠️⚠️⚠️ Warning: minimum requirements gradio-3.23.0 & sd-webui [4c1ad74](https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/4c1ad743e3baf1246db0711aa0107debf036a12b)
Launch your WebUI with argument --theme=dark. For example, on Windows your webui-user.bat should include:
@ -8,11 +74,11 @@ Launch your WebUI with argument --theme=dark. For example, on Windows your webui
set COMMANDLINE_ARGS= --theme=dark
```
## Screenshots
## 👀 Screenshots
![](https://github.com/canisminor1990/sd-web-ui-kitchen-theme/blob/main/assets/screenshot.png?raw=true)
## Installation
## 📦 Installation
As an extension (recommended)
Either clone the repo into your extensions folder:

3
commitlint.config.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: ['gitmoji'],
}

View File

@ -1,10 +1,19 @@
const gulp = require('gulp');
const less = require('gulp-less');
const gulp = require('gulp')
const less = require('gulp-less')
const ts = require('gulp-typescript')
gulp.task('less', function () {
return gulp.src('src/theme/*.less').pipe(less()).pipe(gulp.dest('./'));
});
const tsProject = ts.createProject('tsconfig.json')
gulp.task('compile', () => {
return gulp.src('src/script/**/*.ts').pipe(tsProject()).pipe(gulp.dest('javascript'))
})
gulp.task('watch', function () {
gulp.watch('src/theme/**/*', gulp.parallel('less'));
});
gulp.task('less', () => {
return gulp.src('src/theme/*.less').pipe(less()).pipe(gulp.dest('./'))
})
gulp.task('build', gulp.parallel('compile', 'less'))
gulp.task('watch', () => {
gulp.watch('src/theme/**/*', gulp.parallel('less'))
gulp.watch('src/script/**/*', gulp.parallel('compile'))
})

View File

@ -1,14 +1,19 @@
'use strict'
/**
* 处理网站的 favicon 图标
*/
class FaviconHandler {
/**
* 设置网站的 favicon 图标
*/
static setFavicon() {
const link = document.createElement('link');
link.rel = 'icon';
link.type = 'image/svg+xml';
link.href =
'https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg';
document.getElementsByTagName('head')[0].appendChild(link);
const link = document.createElement('link')
link.rel = 'icon'
link.type = 'image/svg+xml'
link.href = 'https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg'
document.getElementsByTagName('head')[0].appendChild(link)
}
}
document.addEventListener('DOMContentLoaded', () => {
FaviconHandler.setFavicon();
});
FaviconHandler.setFavicon()
})

View File

@ -1,220 +1,249 @@
'use strict'
/**
* 转换器工具类
*/
class Converter {
/**
* 将数字四舍五入到小数点后四位
* @param value 数字
* @returns 四舍五入后的数字
*/
static round(value) {
return Math.round(value * 10000) / 10000;
return Math.round(value * 10000) / 10000
}
/**
* 将字符串中的中文冒号和括号转换成英文冒号和括号
* @param srt 字符串
* @returns 转换后的字符串
*/
static convertStr(srt) {
return srt.replace(//g, ':').replace(//g, '(').replace(//g, ')');
return srt.replace(//g, ':').replace(//g, '(').replace(//g, ')')
}
/**
* 将字符串按照括号分割成数组
* @param str 字符串
* @returns 分割后的数组
*/
static convertStr2Array(str) {
// 匹配各种括号中的内容,包括括号本身
const bracketRegex = /(\(|\)|<|>|\[|\])/g;
// 将字符串按照各种括号分割成数组
const bracketRegex = /(\(|\)|<|>|\[|\])/g
/**
* 将字符串按照各种括号分割成数组
* @param str 字符串
* @returns 分割后的数组
*/
const splitByBracket = (str) => {
const arr = [];
let start = 0;
let depth = 0;
let match;
const arr = []
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;
arr.push(str.substring(start, match.index))
start = match.index
}
if (match[0] === '(' || match[0] === '<' || match[0] === '[') {
depth++;
depth++
} else if (match[0] === ')' || match[0] === '>' || match[0] === ']') {
depth--;
depth--
}
if (depth === 0) {
arr.push(str.substring(start, match.index + 1));
start = match.index + 1;
arr.push(str.substring(start, match.index + 1))
start = match.index + 1
}
}
if (start < str.length) {
arr.push(str.substring(start));
arr.push(str.substring(start))
}
return arr;
};
// 将字符串按照逗号和各种括号分割成数组
return arr
}
/**
* 将字符串按照逗号和各种括号分割成数组
* @param str 字符串
* @returns 分割后的数组
*/
const splitByComma = (str) => {
const arr = [];
let start = 0;
let inBracket = false;
const arr = []
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;
arr.push(str.substring(start, i).trim())
start = i + 1
} else if (str[i].match(bracketRegex)) {
inBracket = !inBracket;
inBracket = !inBracket
}
}
arr.push(str.substring(start).trim());
return arr;
};
// 清洗字符串并输出数组
arr.push(str.substring(start).trim())
return arr
}
/**
* 清洗字符串并输出数组
* @param str 字符串
* @returns 清洗后的数组
*/
const cleanStr = (str) => {
let arr = splitByBracket(str);
arr = arr.flatMap((s) => splitByComma(s));
return arr.filter((s) => s !== '');
};
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);
const pattern = /^[,\s ]+$/
return !pattern.test(item)
})
.filter(Boolean)
.sort((a, b) => {
return a.includes('<') && !b.includes('<')
? 1
: b.includes('<') && !a.includes('<')
? -1
: 0;
});
return a.includes('<') && !b.includes('<') ? 1 : b.includes('<') && !a.includes('<') ? -1 : 0
})
}
/**
* 将数组转换成字符串
* @param array 数组
* @returns 转换后的字符串
*/
static convertArray2Str(array) {
const newArray = array.map((item) => {
if (item.includes('<')) return item;
if (item.includes('<')) return item
const newItem = item
.replace(/\s+/g, ' ')
.replace([/\|\.|\。/g, ','])
.replace([/\“|\|\”|\"|\\|\//g, ''])
.replace(/\|\.|\。/g, ',')
.replace(/\“|\|\”|\"|\\|\//g, '')
.replace(/\, /g, ',')
.replace(/\,\,/g, ',')
.replace(/\,/g, ', ');
return Converter.convertStr2Array(newItem).join(', ');
});
return newArray.join(', ');
.replace(/\,/g, ', ')
return Converter.convertStr2Array(newItem).join(', ')
})
return newArray.join(', ')
}
/**
* 将输入的字符串转换成特定格式的字符串
* @param input 输入的字符串
* @returns 转换后的字符串
*/
static convert(input) {
const re_attention = /\{|\[|\}|\]|[^\{\}\[\]]+/gmu;
let text = Converter.convertStr(input);
text = Converter.convertStr2Array(text);
text = Converter.convertArray2Str(text);
let res = [];
const curly_bracket_multiplier = 1.05;
const square_bracket_multiplier = 1 / 1.05;
const re_attention = /\{|\[|\}|\]|[^\{\}\[\]]+/gmu
let text = Converter.convertStr(input)
const textArray = Converter.convertStr2Array(text)
text = Converter.convertArray2Str(textArray)
let res = []
const curly_bracket_multiplier = 1.05
const square_bracket_multiplier = 1 / 1.05
const brackets = {
'{': { stack: [], multiplier: curly_bracket_multiplier },
'[': { stack: [], multiplier: square_bracket_multiplier },
};
}
/**
* 将指定范围内的数字乘以指定倍数
* @param start_position 起始位置
* @param multiplier 倍数
*/
function multiply_range(start_position, multiplier) {
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];
let word = match[0]
if (word in brackets) {
brackets[word].stack.push(res.length);
brackets[word].stack.push(res.length)
} else if (word == '}' || word == ']') {
const bracket = brackets[word === '}' ? '{' : '['];
const bracket = brackets[word === '}' ? '{' : '[']
if (bracket.stack.length > 0) {
multiply_range(bracket.stack.pop(), bracket.multiplier);
multiply_range(bracket.stack.pop(), bracket.multiplier)
}
} else {
res.push([word, 1.0]);
res.push([word, 1.0])
}
}
for (const bracketType in brackets) {
for (const pos of brackets[bracketType].stack) {
multiply_range(pos, brackets[bracketType].multiplier);
multiply_range(pos, brackets[bracketType].multiplier)
}
}
if (res.length == 0) {
res = [['', 1.0]];
res = [['', 1.0]]
}
let i = 0;
let i = 0
while (i + 1 < res.length) {
if (res[i][1] == res[i + 1][1]) {
res[i][0] += res[i + 1][0];
res.splice(i + 1, 1);
res[i][0] += res[i + 1][0]
res.splice(i + 1, 1)
} else {
i += 1;
i += 1
}
}
let result = '';
let result = ''
for (const [word, value] of res) {
result += value === 1.0 ? word : `(${word}:${value.toString()})`;
result += value === 1.0 ? word : `(${word}:${value.toString()})`
}
return result;
return result
}
/**
* 触发 input 事件
* @param target 目标元素
*/
static dispatchInputEvent(target) {
let inputEvent = new Event('input');
Object.defineProperty(inputEvent, 'target', { value: target });
target.dispatchEvent(inputEvent);
let inputEvent = new Event('input')
Object.defineProperty(inputEvent, 'target', { value: target })
target.dispatchEvent(inputEvent)
}
/**
* 点击转换按钮的事件处理函数
* @param type 类型
*/
static onClickConvert(type) {
const default_prompt = '';
const default_negative = '';
const prompt = gradioApp().querySelector(
`#${type}_prompt > label > textarea`,
);
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`,
);
const negResult = Converter.convert(negprompt.value);
const default_prompt = ''
const default_negative = ''
const prompt = gradioApp().querySelector(`#${type}_prompt > label > textarea`)
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`)
const negResult = Converter.convert(negprompt.value)
negprompt.value =
negResult.match(/^lowres,/) === null
? negResult.length === 0
? default_negative
: default_negative + negResult
: negResult;
Converter.dispatchInputEvent(negprompt);
: negResult
Converter.dispatchInputEvent(negprompt)
}
/**
* 创建转换按钮
* @param id 按钮 id
* @param innerHTML 按钮文本
* @param onClick 点击事件处理函数
* @returns 新建的按钮元素
*/
static createButton(id, innerHTML, onClick) {
const button = document.createElement('button');
button.id = id;
button.type = 'button';
button.innerHTML = innerHTML;
button.title = 'Format prompt~🪄';
button.className = 'lg secondary gradio-button tool svelte-1ipelgc';
button.addEventListener('click', onClick);
return button;
const button = document.createElement('button')
button.id = id
button.type = 'button'
button.innerHTML = innerHTML
button.title = 'Format prompt~🪄'
button.className = 'lg secondary gradio-button tool svelte-1ipelgc'
button.addEventListener('click', onClick)
return button
}
/**
* 添加转换按钮
* @param type - 组件类型
*/
static addPromptButton(type) {
const generateBtn = gradioApp().querySelector(`#${type}_generate`);
const actionsColumn = gradioApp().querySelector(`#${type}_style_create`);
const nai2local = gradioApp().querySelector(`#${type}_formatconvert`);
if (!generateBtn || !actionsColumn || nai2local) return;
const convertBtn = Converter.createButton(
`${type}_formatconvert`,
'🪄',
() => Converter.onClickConvert(type),
);
actionsColumn.parentNode.append(convertBtn);
const generateBtn = gradioApp().querySelector(`#${type}_generate`)
const actionsColumn = gradioApp().querySelector(`#${type}_style_create`)
const nai2local = gradioApp().querySelector(`#${type}_formatconvert`)
if (!generateBtn || !actionsColumn || nai2local) return
const convertBtn = Converter.createButton(`${type}_formatconvert`, '🪄', () => Converter.onClickConvert(type))
actionsColumn.parentNode?.append(convertBtn)
}
}
/**
* 注册UI更新回调函数
* 在UI更新时添加提示按钮
*/
onUiUpdate(() => {
Converter.addPromptButton('txt2img');
Converter.addPromptButton('img2img');
});
Converter.addPromptButton('txt2img')
Converter.addPromptButton('img2img')
})

View File

@ -1,68 +1,68 @@
'use strict'
class BracketChecker {
textArea
counterElt
errorStrings
constructor(textArea, counterElt) {
this.textArea = textArea;
this.counterElt = counterElt;
this.textArea = textArea
this.counterElt = counterElt
this.errorStrings = [
{
regex: /\(/g,
error:
'(...) - Different number of opening and closing parentheses detected.\n',
regex: '\\(',
error: '(...) - Different number of opening and closing parentheses detected.\n',
},
{
regex: /\[/g,
error:
'[...] - Different number of opening and closing square brackets detected.\n',
regex: '\\[',
error: '[...] - Different number of opening and closing square brackets detected.\n',
},
{
regex: /\{/g,
error:
'{...} - Different number of opening and closing curly brackets detected.\n',
regex: '\\{',
error: '{...} - Different number of opening and closing curly brackets detected.\n',
},
];
]
}
check() {
var title = '';
/**
* 检查文本框中的括号是否匹配并更新计数器元素的标题和样式
*/
check = () => {
let title = ''
this.errorStrings.forEach(({ regex, error }) => {
var openMatches = (this.textArea.value.match(regex) || []).length;
var closeMatches = (
this.textArea.value.match(
regex.replace(/\(/g, ')').replace(/\[/g, ']').replace(/\{/g, '}'),
) || []
).length;
if (openMatches != closeMatches) {
const openMatches = (this.textArea.value.match(new RegExp(regex, 'g')) || []).length
const closeMatches = (
this.textArea.value.match(new RegExp(regex.replace(/\(/g, ')').replace(/\[/g, ']').replace(/\{/g, '}'), 'g')) ||
[]
).length
if (openMatches !== closeMatches) {
if (!this.counterElt.title.includes(error)) {
title += error;
title += error
}
} else {
title = this.counterElt.title.replace(error, '');
title = this.counterElt.title.replace(error, '')
}
});
this.counterElt.title = title;
this.counterElt.classList.toggle('error', !!title);
})
this.counterElt.title = title
this.counterElt.classList.toggle('error', !!title)
}
}
function setupBracketChecking(id_prompt, id_counter) {
var textarea = gradioApp().querySelector(`#${id_prompt} > label > textarea`);
var counter = gradioApp().getElementById(id_counter);
var bracketChecker = new BracketChecker(textarea, counter);
textarea.addEventListener('input', () => bracketChecker.check());
/**
* 初始化括号匹配检查器
* @param id_prompt 包含文本框的元素的 ID
* @param id_counter 显示计数器的元素的 ID
*/
function setupBracketChecking(idPrompt, idCounter) {
const textarea = gradioApp().querySelector(`#${idPrompt} > label > textarea`)
const counter = gradioApp().getElementById(idCounter)
const bracketChecker = new BracketChecker(textarea, counter)
textarea.addEventListener('input', bracketChecker.check)
}
const shadowRootLoaded = setInterval(() => {
var shadowRoot = document.querySelector('gradio-app').shadowRoot;
if (!shadowRoot) return;
var shadowTextArea = shadowRoot.querySelector(
`#txt2img_prompt > label > textarea`,
);
if (!shadowTextArea) return;
clearInterval(shadowRootLoaded);
['txt2img', 'txt2img_neg', 'img2img', 'img2img_neg'].forEach((prompt) => {
setupBracketChecking(`${prompt}_prompt`, `${prompt}_token_counter`);
setupBracketChecking(
`${prompt}_prompt`,
`${prompt}_negative_token_counter`,
);
});
}, 1000);
const shadowRoot = document.querySelector('gradio-app')?.shadowRoot
if (!shadowRoot) return
const shadowTextArea = shadowRoot.querySelector(`#txt2img_prompt > label > textarea`)
if (!shadowTextArea) return
clearInterval(shadowRootLoaded)
;['txt2img', 'txt2img_neg', 'img2img', 'img2img_neg'].forEach((prompt) => {
setupBracketChecking(`${prompt}_prompt`, `${prompt}_token_counter`)
setupBracketChecking(`${prompt}_prompt`, `${prompt}_negative_token_counter`)
})
}, 1000)

View File

@ -1,25 +1,45 @@
{
"name": "sd-web-ui-kitchen-theme",
"version": "1.0.0",
"main": "index.js",
"author": "canisminor1990 <i@canisminor.cc>",
"license": "MIT",
"author": "canisminor1990 <i@canisminor.cc>",
"main": "index.js",
"scripts": {
"build": "gulp build",
"dev": "gulp watch",
"build": "gulp less",
"prettier": "prettier --write **/*.{js,jsx,tsx,ts,less,css,md,json}"
},
"dependencies": {},
"devDependencies": {
"husky": "4.3.8",
"gulp": "^4.0.2",
"gulp-less": "^5.0.0",
"lint-staged": "^13.2.0",
"prettier": "^2.8.7"
"lint": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx}\" --fix",
"prepare": "husky install",
"prettier": "prettier -c --write \"**/**\"",
"release": "semantic-release",
"setup": "umi setup"
},
"lint-staged": {
"*.{js,jsx,less,css,md,json}": [
"prettier --write"
]
},
"dependencies": {},
"devDependencies": {
"@commitlint/cli": "^17",
"@umijs/lint": "^4.0.64",
"commitlint": "^17",
"commitlint-config-gitmoji": "^2",
"eslint": "^8",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^2.2.1",
"gulp": "^4.0.2",
"gulp-less": "^5.0.0",
"gulp-typescript": "^6.0.0-alpha.1",
"gulp-use-tsconfig": "^1.5.4",
"husky": "^8.0.3",
"lint-staged": "^13.2.0",
"prettier": "^2",
"prettier-plugin-organize-imports": "^3",
"prettier-plugin-packagejson": "^2",
"semantic-release": "^19",
"semantic-release-config-gitmoji": "^1",
"stylelint": "^15.4.0",
"typescript": "^5.0.0",
"umi": "^4.0.64"
}
}

19
src/script/favicon.ts Normal file
View File

@ -0,0 +1,19 @@
/**
* favicon
*/
class FaviconHandler {
/**
* favicon
*/
static setFavicon(): void {
const link: HTMLLinkElement = document.createElement('link')
link.rel = 'icon'
link.type = 'image/svg+xml'
link.href = 'https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg'
document.getElementsByTagName('head')[0].appendChild(link)
}
}
document.addEventListener('DOMContentLoaded', () => {
FaviconHandler.setFavicon()
})

275
src/script/format-prompt.ts Normal file
View File

@ -0,0 +1,275 @@
/**
*
*/
class Converter {
/**
*
* @param value
* @returns
*/
static round(value: number): number {
return Math.round(value * 10000) / 10000
}
/**
*
* @param srt
* @returns
*/
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
* @returns
*/
static convert(input: string): string {
const re_attention = /\{|\[|\}|\]|[^\{\}\[\]]+/gmu
let text = Converter.convertStr(input)
const textArray = Converter.convertStr2Array(text)
text = Converter.convertArray2Str(textArray)
let res: [string, number][] = []
const curly_bracket_multiplier = 1.05
const square_bracket_multiplier = 1 / 1.05
const brackets: Record<string, { stack: number[]; multiplier: number }> = {
'{': { stack: [], multiplier: curly_bracket_multiplier },
'[': { stack: [], multiplier: square_bracket_multiplier },
}
/**
*
* @param start_position
* @param multiplier
*/
function multiply_range(start_position: number, multiplier: number) {
for (let pos = start_position; pos < res.length; pos++) {
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])
}
}
for (const bracketType in brackets) {
for (const pos of brackets[bracketType].stack) {
multiply_range(pos, brackets[bracketType].multiplier)
}
}
if (res.length == 0) {
res = [['', 1.0]]
}
let i = 0
while (i + 1 < res.length) {
if (res[i][1] == res[i + 1][1]) {
res[i][0] += res[i + 1][0]
res.splice(i + 1, 1)
} else {
i += 1
}
}
let result = ''
for (const [word, value] of res) {
result += value === 1.0 ? word : `(${word}:${value.toString()})`
}
return result
}
/**
* input
* @param target
*/
static dispatchInputEvent(target: EventTarget) {
let inputEvent = new Event('input')
Object.defineProperty(inputEvent, 'target', { value: target })
target.dispatchEvent(inputEvent)
}
/**
*
* @param type
*/
static 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 id id
* @param innerHTML
* @param onClick
* @returns
*/
static createButton(id: string, innerHTML: string, onClick: () => void): HTMLButtonElement {
const button = document.createElement('button')
button.id = id
button.type = 'button'
button.innerHTML = innerHTML
button.title = 'Format prompt~🪄'
button.className = 'lg secondary gradio-button tool svelte-1ipelgc'
button.addEventListener('click', onClick)
return button
}
/**
*
* @param type -
*/
static addPromptButton(type: string): void {
const generateBtn: HTMLElement | null = gradioApp().querySelector(`#${type}_generate`)
const actionsColumn: HTMLElement | null = gradioApp().querySelector(`#${type}_style_create`)
const nai2local: HTMLElement | null = gradioApp().querySelector(`#${type}_formatconvert`)
if (!generateBtn || !actionsColumn || nai2local) return
const convertBtn: HTMLElement = Converter.createButton(`${type}_formatconvert`, '🪄', () =>
Converter.onClickConvert(type)
)
actionsColumn.parentNode?.append(convertBtn)
}
}
/**
* UI
* UI
*/
onUiUpdate(() => {
Converter.addPromptButton('txt2img')
Converter.addPromptButton('img2img')
})

View File

@ -0,0 +1,76 @@
interface ErrorString {
regex: string
error: string
}
class BracketChecker {
private textArea: HTMLTextAreaElement
private counterElt: HTMLElement
private errorStrings: ErrorString[]
constructor(textArea: HTMLTextAreaElement, counterElt: HTMLElement) {
this.textArea = textArea
this.counterElt = counterElt
this.errorStrings = [
{
regex: '\\(',
error: '(...) - Different number of opening and closing parentheses detected.\n',
},
{
regex: '\\[',
error: '[...] - Different number of opening and closing square brackets detected.\n',
},
{
regex: '\\{',
error: '{...} - Different number of opening and closing curly brackets detected.\n',
},
]
}
/**
*
*/
public check = (): void => {
let title = ''
this.errorStrings.forEach(({ regex, error }) => {
const openMatches = (this.textArea.value.match(new RegExp(regex, 'g')) || []).length
const closeMatches = (
this.textArea.value.match(new RegExp(regex.replace(/\(/g, ')').replace(/\[/g, ']').replace(/\{/g, '}'), 'g')) ||
[]
).length
if (openMatches !== closeMatches) {
if (!this.counterElt.title.includes(error)) {
title += error
}
} else {
title = this.counterElt.title.replace(error, '')
}
})
this.counterElt.title = title
this.counterElt.classList.toggle('error', !!title)
}
}
/**
*
* @param id_prompt ID
* @param id_counter ID
*/
function setupBracketChecking(idPrompt: string, idCounter: string): void {
const textarea = gradioApp().querySelector(`#${idPrompt} > label > textarea`) as HTMLTextAreaElement
const counter = gradioApp().getElementById(idCounter) as HTMLElement
const bracketChecker = new BracketChecker(textarea, counter)
textarea.addEventListener('input', bracketChecker.check)
}
const shadowRootLoaded = setInterval(() => {
const shadowRoot = document.querySelector('gradio-app')?.shadowRoot
if (!shadowRoot) return
const shadowTextArea = shadowRoot.querySelector(`#txt2img_prompt > label > textarea`) as HTMLTextAreaElement
if (!shadowTextArea) return
clearInterval(shadowRootLoaded)
;['txt2img', 'txt2img_neg', 'img2img', 'img2img_neg'].forEach((prompt) => {
setupBracketChecking(`${prompt}_prompt`, `${prompt}_token_counter`)
setupBracketChecking(`${prompt}_prompt`, `${prompt}_negative_token_counter`)
})
}, 1000)

View File

@ -9,11 +9,7 @@
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0.8),
transparent
) !important;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), transparent) !important;
opacity: 0;
&:hover {
opacity: 1;

View File

@ -63,10 +63,9 @@
--paddingXL: calc(8px * var(--paddingBase));
/* Shadow */
--boxShadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadowSecondary: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadowSecondary: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
/* Border */
--borderRadiusBase: 2;

View File

@ -54,9 +54,8 @@
--loader-color: var(--color-accent);
/* Typography */
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-mono: 'Hack', 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
@ -132,10 +131,8 @@
--block-title-text-color: var(--neutral-200);
--block-info-text-size: var(--text-sm);
--block-label-padding: var(--spacing-sm) var(--spacing-lg);
--block-label-radius: calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px);
--block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px);
--block-label-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
--block-radius: var(--radius-lg);
@ -168,9 +165,7 @@
--button-primary-border-color-hover: var(--button-primary-border-color);
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-background-fill: var(--neutral-600);
--button-secondary-background-fill-hover: var(
--button-secondary-background-fill
);
--button-secondary-background-fill-hover: var(--button-secondary-background-fill);
--button-secondary-border-color: var(--neutral-600);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color-hover: var(--button-secondary-text-color);
@ -195,12 +190,8 @@
--checkbox-border-color-selected: var(--secondary-600);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: var(--button-secondary-background-fill);
--checkbox-label-background-fill-hover: var(
--button-secondary-background-fill-hover
);
--checkbox-label-background-fill-selected: var(
--checkbox-label-background-fill
);
--checkbox-label-background-fill-hover: var(--button-secondary-background-fill-hover);
--checkbox-label-background-fill-selected: var(--checkbox-label-background-fill);
--checkbox-label-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);

View File

@ -54,9 +54,8 @@
--loader-color: var(--color-accent);
/* Typography */
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-mono: 'Hack', 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
@ -130,10 +129,8 @@
--block-label-background-fill: var(--background-fill-primary);
--block-label-border-color: var(--border-color-primary);
--block-label-padding: var(--spacing-sm) var(--spacing-lg);
--block-label-radius: calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px);
--block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px);
--block-label-text-color: var(--neutral-500);
--block-label-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
@ -170,9 +167,7 @@
--button-primary-text-color: var(--primary-600);
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-background-fill: var(--neutral-200);
--button-secondary-background-fill-hover: var(
--button-secondary-background-fill
);
--button-secondary-background-fill-hover: var(--button-secondary-background-fill);
--button-secondary-border-color: var(--neutral-200);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color: var(--neutral-700);
@ -196,12 +191,8 @@
--checkbox-border-radius: var(--radius-sm);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: var(--button-secondary-background-fill);
--checkbox-label-background-fill-hover: var(
--button-secondary-background-fill-hover
);
--checkbox-label-background-fill-selected: var(
--checkbox-label-background-fill
);
--checkbox-label-background-fill-hover: var(--button-secondary-background-fill-hover);
--checkbox-label-background-fill-selected: var(--checkbox-label-background-fill);
--checkbox-label-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);

1
src/types/gradio.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare const gradioApp: () => DocumentFragment

65
src/types/webui.d.ts vendored Normal file
View File

@ -0,0 +1,65 @@
declare const onUiUpdate: (callback: () => void) => void
declare const onUiLoaded: (callback: () => void) => void
declare const onUiTabChange: (callback: () => void) => void
declare const switch_to_txt2img: () => void
declare const switch_to_img2img: () => void
interface Window {
threedopenpose: {
onResize: (width: number, height: number) => void
onChangeCameraNear: (value: number) => void
onChangeCameraFar: (value: number) => void
onChangeCameraFocalLength: (value: number) => void
onChangeHeadSize: (value: number) => void
onChangeNoseToNeck: (value: number) => void
onChangeShoulderWidth: (value: number) => void
onChangeShoulderToHip: (value: number) => void
onChangeArmLength: (value: number) => void
onChangeForearm: (value: number) => void
onChangeUpperArm: (value: number) => void
onChangeHandSize: (value: number) => void
onChangeHips: (value: number) => void
onChangeLegLength: (value: number) => void
onChangeThigh: (value: number) => void
onChangeLowerLeg: (value: number) => void
onChangeFootSize: (value: number) => void
detectImage: () => void
setBackground: () => void
saveScene: () => void
loadScene: () => void
restoreLastSavedScene: () => void
undo: () => void
redo: () => void
randomPose: () => void
copyBodyZ: () => void
copyBodyX: () => void
removeBody: () => void
onChangeMoveMode: (value: boolean) => void
onChangeOnlyHand: (value: boolean) => void
onChangeEnablePreview: (value: boolean) => void
makeImages: () => void
sendTxt2img: (
pose_image: string | null,
pose_target: string,
depth_image: string | null,
depth_target: string,
normal_image: string | null,
normal_target: string,
canny_image: string | null,
canny_target: string
) => void
sendImg2img: (
pose_image: string,
pose_target: string,
depth_image: string,
depth_target: string,
normal_image: string,
normal_target: string,
canny_image: string,
canny_target: string
) => void
downloadPoseImage: (image: string | null) => void
downloadDepthImage: (image: string | null) => void
downloadNormalImage: (image: string | null) => void
downloadCannyImage: (image: string | null) => void
}
}

View File

@ -366,10 +366,9 @@ template {
--paddingLG: calc(6px * var(--paddingBase));
--paddingXL: calc(8px * var(--paddingBase));
/* Shadow */
--boxShadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadowSecondary: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
--boxShadowSecondary: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
/* Border */
--borderRadiusBase: 2;
--borderRadiusXS: calc(1px * var(--borderRadiusBase));
@ -430,9 +429,8 @@ template {
--link-text-color-visited: var(--secondary-500);
--loader-color: var(--color-accent);
/* Typography */
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-mono: 'Hack', 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
@ -501,10 +499,8 @@ template {
--block-label-background-fill: var(--background-fill-primary);
--block-label-border-color: var(--border-color-primary);
--block-label-padding: var(--spacing-sm) var(--spacing-lg);
--block-label-radius: calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px);
--block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px);
--block-label-text-color: var(--neutral-500);
--block-label-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
@ -539,9 +535,7 @@ template {
--button-primary-text-color: var(--primary-600);
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-background-fill: var(--neutral-200);
--button-secondary-background-fill-hover: var(
--button-secondary-background-fill
);
--button-secondary-background-fill-hover: var(--button-secondary-background-fill);
--button-secondary-border-color: var(--neutral-200);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color: var(--neutral-700);
@ -564,12 +558,8 @@ template {
--checkbox-border-radius: var(--radius-sm);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: var(--button-secondary-background-fill);
--checkbox-label-background-fill-hover: var(
--button-secondary-background-fill-hover
);
--checkbox-label-background-fill-selected: var(
--checkbox-label-background-fill
);
--checkbox-label-background-fill-hover: var(--button-secondary-background-fill-hover);
--checkbox-label-background-fill-selected: var(--checkbox-label-background-fill);
--checkbox-label-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);
@ -651,9 +641,8 @@ template {
--color-accent-soft: var(--neutral-700);
--loader-color: var(--color-accent);
/* Typography */
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-mono: 'Hack', 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
@ -724,10 +713,8 @@ template {
--block-title-text-color: var(--neutral-200);
--block-info-text-size: var(--text-sm);
--block-label-padding: var(--spacing-sm) var(--spacing-lg);
--block-label-radius: calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0
calc(var(--radius-lg) - 1px);
--block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px);
--block-label-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
--block-radius: var(--radius-lg);
@ -758,9 +745,7 @@ template {
--button-primary-border-color-hover: var(--button-primary-border-color);
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-background-fill: var(--neutral-600);
--button-secondary-background-fill-hover: var(
--button-secondary-background-fill
);
--button-secondary-background-fill-hover: var(--button-secondary-background-fill);
--button-secondary-border-color: var(--neutral-600);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color-hover: var(--button-secondary-text-color);
@ -784,12 +769,8 @@ template {
--checkbox-border-color-selected: var(--secondary-600);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: var(--button-secondary-background-fill);
--checkbox-label-background-fill-hover: var(
--button-secondary-background-fill-hover
);
--checkbox-label-background-fill-selected: var(
--checkbox-label-background-fill
);
--checkbox-label-background-fill-hover: var(--button-secondary-background-fill-hover);
--checkbox-label-background-fill-selected: var(--checkbox-label-background-fill);
--checkbox-label-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);
@ -1127,11 +1108,7 @@ div.svelte-awbtu4 .gradio-file {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0.8),
transparent
) !important;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), transparent) !important;
opacity: 0;
}
.extra-network-thumbs .actions .additional > ul:hover {

6
tsconfig-check.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true
}
}

21
tsconfig.json Normal file
View File

@ -0,0 +1,21 @@
{
"extends": "./src/.umi/tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}

1
typings.d.ts vendored Normal file
View File

@ -0,0 +1 @@
import 'umi/typings'

View File

@ -1,27 +1,27 @@
const fs = require('fs');
const path = require('path');
const fs = require('fs')
const path = require('path')
// 从本地文件读取CSS
const cssFilePath = path.resolve(__dirname, 'style.css');
const css = fs.readFileSync(cssFilePath, 'utf-8');
const cssFilePath = path.resolve(__dirname, 'style.css')
const css = fs.readFileSync(cssFilePath, 'utf-8')
// 用于存储变量及其值的对象
const cssVariables = {};
const cssVariables = {}
// 正则表达式用于匹配CSS变量及其值
const cssVarRegex = /--\w+[^:]*:\s*([^;]*);/g;
const cssVarReferenceRegex = /var\((--\w+)\)/g;
const cssVarRegex = /--\w+[^:]*:\s*([^;]*);/g
const cssVarReferenceRegex = /var\((--\w+)\)/g
// 解析CSS变量及其值
let match;
let match
while ((match = cssVarRegex.exec(css))) {
const variable = match[0].split(':')[0].trim();
const value = match[1].trim();
cssVariables[variable] = value;
const variable = match[0].split(':')[0].trim()
const value = match[1].trim()
cssVariables[variable] = value
}
// 对变量进行排序,确保被引用的变量在引用它的变量之前
const sortedVariables = Object.keys(cssVariables);
const sortedVariables = Object.keys(cssVariables)
// 按类别对变量进行分组
const groups = {
@ -38,68 +38,63 @@ const groups = {
input: [],
table: [],
other: [],
};
}
sortedVariables.forEach((variable) => {
const value = cssVariables[variable];
const value = cssVariables[variable]
const isColor =
value.startsWith('#') ||
value.includes('rgb') ||
value.includes('color') ||
variable.includes('color') ||
variable.includes('fill') ||
variable.includes('neutral');
variable.includes('neutral')
const isTypography =
variable.includes('text') ||
variable.includes('font') ||
variable.includes('prose') ||
variable.includes('link');
variable.includes('text') || variable.includes('font') || variable.includes('prose') || variable.includes('link')
const isSpacing =
variable.includes('spacing') ||
variable.includes('padding') ||
variable.includes('gap') ||
variable.includes('margin');
value.includes('padding') || value.includes('margin');
const isBorder = variable.includes('radius') || variable.includes('border');
const isBoxShadow = variable.includes('shadow');
variable.includes('margin')
value.includes('padding') || value.includes('margin')
const isBorder = variable.includes('radius') || variable.includes('border')
const isBoxShadow = variable.includes('shadow')
if (variable.includes('--body')) {
groups.body.push(variable);
groups.body.push(variable)
} else if (variable.includes('--block')) {
groups.block.push(variable);
groups.block.push(variable)
} else if (variable.includes('--panel')) {
groups.panel.push(variable);
groups.panel.push(variable)
} else if (variable.includes('--button')) {
groups.button.push(variable);
groups.button.push(variable)
} else if (variable.includes('--checkbox')) {
groups.checkbox.push(variable);
groups.checkbox.push(variable)
} else if (variable.includes('--input')) {
groups.input.push(variable);
groups.input.push(variable)
} else if (variable.includes('--table')) {
groups.table.push(variable);
groups.table.push(variable)
} else if (isBorder) {
groups.border.push(variable);
groups.border.push(variable)
} else if (isBoxShadow) {
groups.boxShadow.push(variable);
groups.boxShadow.push(variable)
} else if (isColor) {
groups.colors.push(variable);
groups.colors.push(variable)
} else if (isTypography) {
groups.typography.push(variable);
groups.typography.push(variable)
} else if (isSpacing) {
groups.spacing.push(variable);
groups.spacing.push(variable)
} else {
groups.other.push(variable);
groups.other.push(variable)
}
});
})
// 生成排序后的CSS变量
const generateGroupCss = (groupName) => {
const cache = groups[groupName].map(
(variable) => `${variable}: ${cssVariables[variable]};`,
);
const firstPart = cache.filter((item) => item.includes('var'));
const secondPart = cache.filter((item) => !item.includes('var'));
return [...secondPart, ...firstPart].join('\n');
};
const cache = groups[groupName].map((variable) => `${variable}: ${cssVariables[variable]};`)
const firstPart = cache.filter((item) => item.includes('var'))
const secondPart = cache.filter((item) => !item.includes('var'))
return [...secondPart, ...firstPart].join('\n')
}
const sortedCss =
'#output {\n' +
@ -129,9 +124,9 @@ const sortedCss =
generateGroupCss('table') +
`\n\n/* Other */\n` +
generateGroupCss('other') +
'}';
'}'
console.log(sortedCss);
console.log(sortedCss)
// 将排序后的CSS变量写入文件
fs.writeFileSync('sorted-css-variables.css', sortedCss);
fs.writeFileSync('sorted-css-variables.css', sortedCss)

9135
yarn.lock

File diff suppressed because it is too large Load Diff