feat(break-change): full support gradio-3.23.0

pull/23/head
canisminor1990 2023-03-27 00:50:15 +08:00
parent 9509e3d6eb
commit e47578c9f1
33 changed files with 4979 additions and 3748 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

10
gulpfile.js Normal file
View File

@ -0,0 +1,10 @@
const gulp = require("gulp");
const less = require("gulp-less");
gulp.task("less", function () {
return gulp.src("src/theme/*.less").pipe(less()).pipe(gulp.dest("./"));
});
gulp.task("watch", function () {
gulp.watch("src/theme/**/*", gulp.parallel("less"));
});

View File

@ -1,58 +0,0 @@
class InjectBackground{
constructor(){
this.image;
}
async init(selector="div[class^=mx-auto][class*=container]"){
this.element = undefined
while(true){
this.element = gradioApp().querySelector(selector)
if (this.element){
break
}
await delay(500)
}
this.element.setAttribute("style", "background-image: url(file=static/background.png); background-size: contain; background-attachment: fixed; background-position: center; background-repeat: no-repeat")
}
removeStyle(){
this.element.removeStyle()
}
removeImage(){
this.element.style['background-image'] = ""
}
updateImage(path){
this.element.style['background-image'] = `url(file=${path})`
}
//destroy not necessarily needed at this time, it's to keep the api similar
destroy(){
this.removeStyle()
}
async refreshImage(file_name){
setTimeout(location.reload(), 200)
//this.updateImage("static/background.png")
console.log(file_name)
return file_name
}
}
/*
element.style {
background-image: url(file=logo.png);
background-size: cover;
background-attachment: fixed;
background-position: center;
}
*/
let injectBackground = new InjectBackground()
async function registerInjectHandler(){
await injectBackground.init()
while(true){
if(injectBackground.element){
break
}
await delay(500)
}
qkcssImagemap.injectBackground = injectBackground
}
function delay(ms){return new Promise(resolve => setTimeout(resolve, ms))}
document.addEventListener("DOMContentLoaded", async function (){await registerInjectHandler()})

View File

@ -1,22 +1,14 @@
class FaviconHandler {
static setFavicon() {
const link = document.createElement('link');
link.rel = 'icon';
link.type = 'image/svg+xml';
link.href = getComputedStyle(gradioApp().querySelector('.icon-container')).backgroundImage.replace(/^url\("|"\)$/g, '');
document.getElementsByTagName('head')[0].appendChild(link);
}
static observeGradioApp() {
const observer = new MutationObserver(() => {
const iconContainer = gradioApp().querySelector('.icon-container');
if (iconContainer) {
observer.disconnect();
FaviconHandler.setFavicon();
}
});
observer.observe(gradioApp(), { childList: true, subtree: true });
}
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);
}
}
document.addEventListener("DOMContentLoaded", () => {
FaviconHandler.observeGradioApp();
FaviconHandler.setFavicon();
});

219
javascript/format-prompt.js Normal file
View File

@ -0,0 +1,219 @@
class Converter {
static round(value) {
return Math.round(value * 10000) / 10000;
}
static convertStr(srt) {
return srt.replace(//g, ":").replace(//g, "(").replace(//g, ")");
}
static convertStr2Array(str) {
// 匹配各种括号中的内容,包括括号本身
const bracketRegex = /(\(|\)|<|>|\[|\])/g;
// 将字符串按照各种括号分割成数组
const splitByBracket = (str) => {
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;
}
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;
};
// 将字符串按照逗号和各种括号分割成数组
const splitByComma = (str) => {
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;
} else if (str[i].match(bracketRegex)) {
inBracket = !inBracket;
}
}
arr.push(str.substring(start).trim());
return arr;
};
// 清洗字符串并输出数组
const cleanStr = (str) => {
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;
});
}
static convertArray2Str(array) {
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(", ");
}
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 brackets = {
"{": { stack: [], multiplier: curly_bracket_multiplier },
"[": { stack: [], multiplier: square_bracket_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);
}
}
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;
}
static dispatchInputEvent(target) {
let inputEvent = new Event("input");
Object.defineProperty(inputEvent, "target", { value: target });
target.dispatchEvent(inputEvent);
}
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);
negprompt.value =
negResult.match(/^lowres,/) === null
? negResult.length === 0
? default_negative
: default_negative + negResult
: negResult;
Converter.dispatchInputEvent(negprompt);
}
static createButton(id, innerHTML, onClick) {
const button = document.createElement("button");
button.id = id;
button.type = "button";
button.innerHTML = innerHTML;
button.className = "lg secondary gradio-button tool svelte-1ipelgc";
button.addEventListener("click", onClick);
return button;
}
static addPromptButton(type) {
const generateBtn = gradioApp().querySelector(`#${type}_generate`);
const actionsColumn = gradioApp().querySelector(`#${type}_style_create`);
const nai2local = gradioApp().querySelector(`#${type}_nai2localconvert`);
if (!generateBtn || !actionsColumn || nai2local) return;
const convertBtn = Converter.createButton(
`${type}_nai2localconvert`,
"🪄",
() => Converter.onClickConvert(type)
);
actionsColumn.parentNode.append(convertBtn);
}
}
onUiUpdate(() => {
Converter.addPromptButton("txt2img");
Converter.addPromptButton("img2img");
});

View File

@ -1,100 +0,0 @@
class MatrixEffect{
constructor(){
this.matrixCanvas = document.createElement("canvas")
this.matrixCanvas.setAttribute("style", "position: fixed;")
gradioApp().querySelector("div[class*=container]:not([class^=modal])").insertAdjacentElement('afterbegin', this.matrixCanvas)
}
async initialize(){
while(!gradioApp().querySelector('canvas')){
await delay(300)
}
// Initialising the canvas
this.ctx = this.matrixCanvas.getContext('2d');
// Setting the width and height of the canvas
this.matrixCanvas.width = window.innerWidth;
this.matrixCanvas.height = window.innerHeight;
// Setting up the letters
this.letters = 'ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ';
this.letters = this.letters.split('');
// Setting up the columns
this.fontSize = 10,
this.columns = this.matrixCanvas.width / this.fontSize;
// Setting up the drops
this.drops = [];
for (var i = 0; i < this.columns; i++) {
this.drops[i] = 1;
}
this.running = true;
//timer
this.then = Date.now();
this.fps = 20;
this.fpsInterval = 1000/this.fps;
// Setting up the draw function
this.draw = () => {
this.now = Date.now();
this.elapsed = this.now - this.then;
if (this.elapsed > this.fpsInterval){
this.then = this.now - (this.elapsed % this.fpsInterval);
this.ctx.fillStyle = 'rgba(0, 0, 0, .1)';
this.ctx.fillRect(0, 0, this.matrixCanvas.width, this.matrixCanvas.height);
for (var i = 0; i < this.drops.length; i++) {
text = this.letters[Math.floor(Math.random() * this.letters.length)];
this.ctx.fillStyle = '#0f0';
this.ctx.fillText(text, i * this.fontSize, this.drops[i] * this.fontSize);
this.drops[i]++;
if (this.drops[i] * this.fontSize > this.matrixCanvas.height && Math.random() > .95) {
this.drops[i] = 0;
}
}
}
if (this.running){
requestAnimationFrame(this.draw)
}
}
}
destroy(){
this.running = false;
//clearInterval(this.Interval)
this.matrixCanvas.remove()
}
}
let matrixEffect;
async function registerMatrixToHandler(){
await delay(1000);
while(qkcssFXMap == undefined){
await delay(500)
}
qkcssFXMap["matrixfx"] = [launchMatrixEffect, matrixEffect];
}
async function launchMatrixEffect(){
await delay(1000)
while (!gradioApp().querySelector("div[class*=container]:not([class^=modal])")){
await delay(300);
}
// Loop the animation
matrixEffect = new MatrixEffect()
//Shortciruited it
qkcssFXMap["matrixfx"][1] = matrixEffect
await delay(500)
matrixEffect.initialize()
matrixEffect.Interval = matrixEffect.draw();
//matrixEffect.Interval = setInterval(matrixEffect.draw, 33);
}
function delay(ms){return new Promise(resolve => setTimeout(resolve, ms))}
//document.addEventListener("DOMContentLoaded", async function() {await launchMatrixEffect()})
document.addEventListener("DOMContentLoaded", async function() {await registerMatrixToHandler()})

View File

@ -1,239 +0,0 @@
// Maximum number of histories will be kept
const MaxHistory = 10;
// History of positive prompt
let historyBox = (function () {
let _historyBox = [];
return {
push: function (prompt) {
if (prompt == _historyBox[_historyBox.length - 1]) return;
_historyBox.push(prompt);
if (MaxHistory < _historyBox.length) {
_historyBox.shift();
}
},
pop: function () {
let prePrompt = _historyBox.pop();
return prePrompt;
},
};
})();
// History of negative prompt
let nhistoryBox = (function () {
let _historyBox = [];
return {
push: function (prompt) {
if (prompt == _historyBox[_historyBox.length - 1]) return;
_historyBox.push(prompt);
if (MaxHistory < _historyBox.length) {
_historyBox.shift();
}
},
pop: function () {
let prePrompt = _historyBox.pop();
return prePrompt;
},
};
})();
// Round function
function round(value) {
return Math.round(value * 10000) / 10000;
}
function convert(input) {
[111, 2233];
const re_attention = /\{|\[|\}|\]|[^\{\}\[\]]+/gmu;
let text = input
.replace("", ":")
.replace("", "(")
.replace("", ")")
.replace(/\s+/gi, " ")
.replace("", ",")
.replace("<", ", <")
.replace(", ,", ",")
.replace(",,", ",")
.replace("> <", ">, <");
let res = [];
let curly_brackets = [];
let square_brackets = [];
const curly_bracket_multiplier = 1.05;
const square_bracket_multiplier = 1 / 1.05;
function multiply_range(start_position, multiplier) {
for (let pos = start_position; pos < res.length; pos++) {
res[pos][1] = round(res[pos][1] * multiplier);
}
}
for (const match of text.matchAll(re_attention)) {
let word = match[0];
if (word == "{") {
curly_brackets.push(res.length);
} else if (word == "[") {
square_brackets.push(res.length);
} else if (word == "}" && curly_brackets.length > 0) {
multiply_range(curly_brackets.pop(), curly_bracket_multiplier);
} else if (word == "]" && square_brackets.length > 0) {
multiply_range(square_brackets.pop(), square_bracket_multiplier);
} else {
res.push([word, 1.0]);
}
}
for (const pos of curly_brackets) {
multiply_range(pos, curly_bracket_multiplier);
}
for (const pos of square_brackets) {
multiply_range(pos, square_bracket_multiplier);
}
if (res.length == 0) {
res = [["", 1.0]];
}
// console.log(res);
// merge runs of identical weights
let i = 0;
while (i + 1 < res.length) {
// console.log("test:" + res[i] + " : " + res[i+1])
if (res[i][1] == res[i + 1][1]) {
res[i][0] = res[i][0] + res[i + 1][0];
// console.log("splicing:" + res[i+1]);
res.splice(i + 1, 1);
} else {
i += 1;
}
}
// console.log(res);
let result = "";
for (let i = 0; i < res.length; i++) {
if (res[i][1] == 1.0) {
result += res[i][0];
} else {
result += "(" + res[i][0] + ":" + res[i][1].toString() + ")";
}
}
return result;
}
function dispatchInputEvent(target) {
let inputEvent = new Event("input");
Object.defineProperty(inputEvent, "target", { value: target });
target.dispatchEvent(inputEvent);
}
function onClickConvert(type) {
const default_prompt = "";
const default_negative = "";
let result = "";
let prompt = gradioApp().querySelector(`#${type}_prompt > label > textarea`);
historyBox.push(prompt.value);
result = convert(prompt.value);
if (result.length != 0) {
if (result.match(/^masterpiece, best quality,/) == null) {
result = default_prompt + result;
}
}
prompt.value = result;
dispatchInputEvent(prompt);
result = "";
let negprompt = gradioApp().querySelector(
`#${type}_neg_prompt > label > textarea`
);
nhistoryBox.push(negprompt.value);
result = convert(negprompt.value);
if (result.length != 0) {
if (result.match(/^lowres,/) == null) {
result = default_negative + result;
}
} else {
result = default_negative;
}
negprompt.value = result;
dispatchInputEvent(negprompt);
}
function onClickGenerate(type) {
let prompt = gradioApp().querySelector(`#${type}g_prompt > label > textarea`);
historyBox.push(prompt.value);
let negprompt = gradioApp().querySelector(
`#${type}_neg_prompt > label > textarea`
);
nhistoryBox.push(negprompt.value);
}
function onClickUndo(type) {
let prompt = gradioApp().querySelector(`#${type}_prompt > label > textarea`);
let prePrompt = historyBox.pop();
if (!prePrompt) {
prompt.value = "";
} else {
prompt.value = prePrompt;
}
dispatchInputEvent(prompt);
let negprompt = gradioApp().querySelector(
`#${type}_neg_prompt > label > textarea`
);
let prenegprompt = nhistoryBox.pop();
if (!prenegprompt) {
negprompt.value = "";
} else {
negprompt.value = prenegprompt;
}
dispatchInputEvent(negprompt);
}
function createButton(id, innerHTML, onClick) {
const button = document.createElement("button");
button.id = id;
button.type = "button";
button.innerHTML = innerHTML;
button.className = "gr-button gr-button-lg gr-button-secondary";
button.style = `padding-left: 0.1em; padding-right: 0em; margin: 0.1em 0;max-height: 2em; max-width: 6em`;
button.addEventListener("click", onClick);
return button;
}
function addPromptButton(type) {
const generateBtn = gradioApp().querySelector(`#${type}_generate`);
const actionsColumn = gradioApp().querySelector(`#${type}_actions_column`);
const nai2local = gradioApp().querySelector(`#${type}_nai2local`);
if (!generateBtn || !actionsColumn || nai2local) return;
generateBtn.addEventListener("click", () => onClickGenerate(type));
const nai2LocalArea = document.createElement("div");
nai2LocalArea.id = `${type}_nai2local`;
nai2LocalArea.className = "overflow-hidden flex col gap-4";
nai2LocalArea.style =
"padding: 0.4em 0em; display: flex; justify-content: center;";
const convertBtn = createButton("nai2localconvert", "🪄", () =>
onClickConvert(type)
);
const undoBtn = createButton("nai2localUndo", "History", () =>
onClickUndo(type)
);
nai2LocalArea.appendChild(convertBtn);
nai2LocalArea.appendChild(undoBtn);
actionsColumn.append(nai2LocalArea);
}
onUiUpdate(() => {
addPromptButton("txt2img");
addPromptButton("img2img");
});

View File

@ -0,0 +1,68 @@
class BracketChecker {
constructor(textArea, counterElt) {
this.textArea = textArea;
this.counterElt = counterElt;
this.errorStrings = [
{
regex: /\(/g,
error:
"(...) - Different number of opening and closing parentheses detected.\n",
},
{
regex: /\[/g,
error:
"[...] - Different number of opening and closing square brackets detected.\n",
},
{
regex: /\{/g,
error:
"{...} - Different number of opening and closing curly brackets detected.\n",
},
];
}
check() {
var 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) {
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);
}
}
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());
}
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);

View File

@ -1,72 +0,0 @@
function quickcssFormatRule(val, ele, colorsSize){
//async is not needed, just trying to debug some error from colorpicker
ele = parseInt(ele)
//get sheet from style tag
let quickcssSheet = document.documentElement.querySelector("gradio-app").shadowRoot.querySelector("style").sheet
//get it's rules
let quickcssCssr = quickcssSheet.cssRules
//convert to array for finding index
let quickcssCssrArray = Array.from(quickcssCssr)
//use custom target to find index
let quickcssTarget = quickcssCssrArray.find( item => item.cssText.includes("quickcss_target"))
let quickcssTargetIndex = quickcssCssrArray.indexOf(quickcssTarget)
//Pull rule out
let quickcssRuleAsString = quickcssCssr[quickcssTargetIndex].cssText.toString()
//splitter for rule targets and body
let ruleSplitIndex = quickcssRuleAsString.indexOf("{")
//Target of rule
let ruleTargets = quickcssRuleAsString.slice(0, ruleSplitIndex)
//Body of rule
let quickcssRuleBody = quickcssRuleAsString.slice(ruleSplitIndex)
//Rule body edit
let asSplit = quickcssRuleBody.split(";")
let endStr = asSplit.slice(parseInt(colorsSize)).join(";")
//Edit to element position, index and length given as string via hiddenvals components
while (asSplit.length > parseInt(colorsSize))
{
asSplit.pop()
}
let asArray = new Array
asSplit.forEach( e => {asArray.push(e.split(":"))})
let stringarray = new Array
asArray.forEach( (e, i) => {stringarray.push( i==ele ? `${e[0]}: ${val}`: `${e[0]}: ${e[1]}`)})
stringarray = stringarray.join(";") + `;${endStr}`
let cssRule = ruleTargets + stringarray
//Delete old rule at
quickcssSheet.deleteRule(quickcssTargetIndex)
//insert (as in add at same location)
quickcssSheet.insertRule(cssRule, quickcssTargetIndex)
//returns must equal inputs size, so outputs must matchsize, python fn hijacks for finishing save data
return [stringarray, "", ""]
}
//Register js fx's
//they must support a destroy method
qkcssFXMap = {};
function launchEffect(filename){
qkcssFXMap[filename][0]()
}
function destroyEffect(filename){
qkcssFXMap[filename][1].destroy()
}
//Register js image injectors
qkcssImagemap = {};
function launchImage(name){
qkcssImagemap[name].register()
}
function removeImage(name){
qkcssImagemap[name].destroy()
}
function updateImage(name, new_name){
//notimplemented hidden component to send name?
qkcssImagemap[name].updateImage(new_name)
}
async function refreshImage(name){
await qkcssImagemap[name].refreshImage()
return name
}

18
package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "sd-web-ui-kitchen-theme",
"version": "1.0.0",
"main": "index.js",
"author": "canisminor1990 <i@canisminor.cc>",
"license": "MIT",
"scripts": {
"dev": "gulp watch",
"build": "gulp less"
},
"dependencies": {
"gulp": "^4.0.2",
"gulp-less": "^5.0.0"
},
"devDependencies": {
"prettier": "^2.8.7"
}
}

View File

@ -1,387 +0,0 @@
import gradio as gr
import modules.scripts as scripts
from modules import script_callbacks, shared
import os
import shutil
from pathlib import Path
basedir = scripts.basedir()
class MyTab():
def __init__(self, basedir):
#This extensions directory
self.extensiondir = basedir
#Up two directories, webui root
self.webui_dir = Path(self.extensiondir).parents[1]
self.style_folder = os.path.join(basedir, "style_choices")
self.backgrounds_folder = os.path.join(self.extensiondir, "backgrounds")
self.logos_folder = os.path.join(self.extensiondir, "logos")
self.favicon_folder = os.path.join(self.extensiondir, "favicons")
self.effects_folder = os.path.join(self.extensiondir, "effects")
self.javascript_folder = os.path.join(self.extensiondir, "javascript")
self.static_folder = os.path.join(self.webui_dir, "static")
self.favicon_workaround = gr.HTML(value='<div class="icon-container"></div>', render=False)
self.styles_list = self.get_files(self.style_folder)
self.backgrounds_list = self.get_files(self.backgrounds_folder)
self.logos_list = self.get_files(self.logos_folder)
self.favicon_list = self.get_files(self.favicon_folder)
self.effects_list = self.get_files(self.javascript_folder, file_filter=["quickcss.js", "utility.js", "background.js"], split=True)
self.styles_dropdown = gr.Dropdown(label="Styles", render=False, interactive=True, choices=self.styles_list, type="value")
self.background_dropdown = gr.Dropdown(label="Background", render=False, interactive=True, choices=self.backgrounds_list, type="value")
self.logos_dropdown = gr.Dropdown(label="Logos", render=False, interactive=True, choices=self.logos_list, type="value")
self.favicon_dropdown = gr.Dropdown(label="Favicon", render=False, interactive=True, choices=self.favicon_list, type="value")
self.effects_dropdown = gr.Dropdown(label="Effects (on until refresh)", render=False, interactive=True, choices=self.effects_list, type="value")
self.apply_style_bttn = gr.Button(value="Apply Style", render=False)
self.apply_background_bttn = gr.Button(value="Apply (Reload UI)", render=False)
#TODO: background off button to swap image in folder to blankbackground and disable style rule
self.refresh_bkcgrnd_droplist_button = gr.Button(value="Refresh List", render=False)
self.apply_logo_bttn = gr.Button(value="Apply Logo", render=False)
self.apply_favicon_bttn = gr.Button(value="Apply Favicon (edit webui.py to see)", render=False)
self.effects_button = gr.Button(value="Activate Selected Script", render=False)
self.effects_off_button = gr.Button(value="Deactivate Selected Script", render=False)
self.logo_image = gr.Image(render=False)
self.favicon_image = gr.Image(render=False)
self.import_style_file = gr.File(render=False, label="Import CSS file")
self.import_background_file = gr.File(render=False, label="Import Background Images")
self.import_logo_file = gr.File(render=False, label="Import Logo's (png)")
self.import_favicon_file = gr.File(render=False, label="Import favicons (svg)")
self.restart_bttn = gr.Button(value="Apply changes (Reload UI)", render=False, variant="primary")
self.remove_style = gr.Button(value="Remove Stylesheet", render=False)
# BEGIN CSS COLORPICK COMPONENTS
self.save_as_filename = gr.Text(label="Save Name", visible=False, render=False)
self.save_button = gr.Button(value="Save", visible=False, render=False, variant="primary")
#Test for file being set
self.file_exists = False
self.style_path = os.path.join(self.extensiondir, "style.css")
self.start_position_for_save = 0
self.insert_colorpicker_break_rule_for_save = 0
self.insert_break_rule_for_save = 0
if os.path.exists(self.style_path):
self.file_exists = True #Conditional for creating inputs
self.lines = []
line = ""
self.dynamic_compatible = False
with open(self.style_path, 'r', encoding='utf-8') as cssfile:
try:
for i, line in enumerate(cssfile):
line = line.strip()
if "/*BREAKFILEREADER*/" in line:
self.insert_break_rule_for_save = i - self.start_position_for_save
break
elif "/*ENDCOLORPICKERS*/" in line:
self.insert_colorpicker_break_rule_for_save = i - self.start_position_for_save
continue
if "quickcss_target" in line:
self.dynamic_compatible = True
self.start_position_for_save = i+1
continue
if self.dynamic_compatible:
if len(line) > 0:
self.lines.append(line.split(":"))
except UnicodeDecodeError as error:
print(f"{error}\nCheck style.css in this extensions folder.")
if self.dynamic_compatible:
self.dynamically_generated_components = [gr.ColorPicker(label=x[0].replace("-", "").replace("_", " ").title(), render=False, elem_id="quikcss_colorpicker", value=x[1].replace(";", "").strip())
if i < self.insert_colorpicker_break_rule_for_save else
gr.Slider(minimum=0, maximum=100, step=1, label=x[0].replace("-", "").replace("_", " ").title(), render=False, elem_id="quikcss_slider", value=x[1].replace(";", "").strip())
for i,x in enumerate(self.lines)
]
else:
self.dynamically_generated_components = []
# hidden_vals acts like an index, holds int values that are used in js
self.hidden_vals = [gr.Text(value=str(x), render=False, visible=False) for x in range(len(self.dynamically_generated_components))]
# length_of_colors similar to hidden vals, but provides length so js knows the limit when parsing rules
self.length_of_colors = gr.Text(value=len(self.dynamically_generated_components), visible=False, render=False)
# used as padding so we don't list index error or http 500 internal server, or http 422 forEach can't over undefined (promise pending)
self.dummy_picker = gr.Text(visible=False, render=False, elem_id="hidden")
# Acts like catcher, actual values store in list
self.js_result_component = gr.Text(render=False, interactive=False)
#dummy component for general purpose, currently used for _js effects; holds no relevant data, just for input/output element quota
self._dummy = gr.Text(value="", visible=False, render=False, show_label=False, interactive=False)
def ui(self, *args, **kwargs):
with gr.Blocks(analytics_enabled=False) as ui:
self.favicon_workaround.render()
with gr.Accordion(label="Some instructions", open=False):
gr.Markdown(value="""<center>This is a mix from old style to new style. It is not in it's finished state</center>
<center>To see effects, you must use dropdown, select as sheet, click apply, click restart. More options will be available on restart</center>
<center>I know it lives as a tab, but this was meant to be a demo at first, now it's growing to something more</center>
<center>To see favicon take affect, you will need to add `favicon_path="favicon.svg"` to webui.py</center>
<center>To do this, open file, search for `prevent_thread_lock` add comma, paste in text, save.</center>
<center>You may need to undo this for an update, if you have git issues and don't know how to deal with them</center>
<center>This won't break your system, if you find you can't update, try `git checkout webui.py` ~~`git fetch --all` `git reset --hard origin/master`~~</center>
<center>Once again, this `dynamic` demo has not removed/re-implemented all features present</center>
""")
if self.file_exists and self.dynamic_compatible:
with gr.Row(equal_height=True):
self.save_as_filename.render()
self.save_button.render()
#Necessary for values being accessible
self.length_of_colors.render()
self.dummy_picker.render()
self.js_result_component.render()
#Render hidden vals that serve as indices to map
for h in self.hidden_vals:
h.render()
with gr.Row():
#Render adjusters
for c in self.dynamically_generated_components:
with gr.Column(elem_id="quickcss_colorpicker"):
c.render()
with gr.Row():
with gr.Column():
self.styles_dropdown.render()
self.apply_style_bttn.render()
with gr.Column():
self.background_dropdown.render()
with gr.Row():
self.apply_background_bttn.render()
self.refresh_bkcgrnd_droplist_button.render()
with gr.Column():
self.logos_dropdown.render()
self.apply_logo_bttn.render()
with gr.Column():
self.favicon_dropdown.render()
self.apply_favicon_bttn.render()
with gr.Column():
self.effects_dropdown.render()
with gr.Row():
self.effects_button.render()
self.effects_off_button.render()
with gr.Accordion(label="Import Files", open=False):
with gr.Row():
with gr.Column():
self.import_style_file.render()
with gr.Column():
self.import_background_file.render()
with gr.Column():
self.import_logo_file.render()
with gr.Column():
self.import_favicon_file.render()
with gr.Row():
self.restart_bttn.render()
self.remove_style.render()
with gr.Row():
self.logo_image.render()
self.favicon_image.render()
self._dummy.render()
# Handlers
#Generate colorpickers and sliders handlers
if self.file_exists:
for comp,val in zip(self.dynamically_generated_components, self.hidden_vals):
comp.change(
fn = lambda *x: self.process_for_save(*x),
_js = "quickcssFormatRule",
inputs = [comp, val, self.length_of_colors],
outputs = [self.js_result_component] + [self.save_as_filename, self.dummy_picker]
)
self.save_as_filename.change(
fn = lambda x: gr.update(visible=bool(x)),
inputs = self.save_as_filename,
outputs = self.save_button
)
self.save_button.click(
fn = self.save,
inputs = [self.js_result_component, self.save_as_filename],
outputs = [self.js_result_component, self.styles_dropdown]
)
#Handler cont.
#Common interface
#NOTE: These dropdowns affect image placeholders
self.logos_dropdown.change(
fn = lambda x: self.get_image(x, folder = "logos"),
inputs = self.logos_dropdown,
outputs = self.logo_image
)
self.favicon_dropdown.change(
fn = lambda x: self.get_image(x, folder = "favicons"),
inputs = self.favicon_dropdown,
outputs = self.favicon_image
)
#buttons
self.apply_style_bttn.click(
fn = self.apply_choice_wrapper(self.style_folder, self.extensiondir, "style.css"),
inputs = self.styles_dropdown
)
self.apply_background_bttn.click(
fn = self.apply_choice_wrapper(self.backgrounds_folder, self.static_folder, "background.png"),#TODO: MAYBE: delete file extension
_js = "injectBackground.refreshImage",
inputs = self.background_dropdown,
outputs=self._dummy
)
self.refresh_bkcgrnd_droplist_button.click(
fn = lambda: self.refresh_list(self.refresh_bkcgrnd_droplist_button, self.backgrounds_folder, self.background_dropdown),
outputs=self.background_dropdown
)
self.apply_logo_bttn.click(
fn = self.apply_choice_wrapper(self.logos_folder, self.static_folder, "logo.png"),#TODO Update css files and change dir to static
inputs = self.logos_dropdown,
)
self.apply_favicon_bttn.click(
fn = self.apply_choice_wrapper(self.favicon_folder, self.static_folder, "favicon.svg"),#TODO update css files and change dir to static
inputs = self.favicon_dropdown
)
self.effects_button.click(
fn = None,
_js = "launchEffect",
inputs = self.effects_dropdown,
outputs = self._dummy
)
self.effects_off_button.click(
fn = None,
_js = "destroyEffect",
inputs = self.effects_dropdown,
outputs = self._dummy
)
self.remove_style.click(
fn = lambda: self.delete_style()
)
self.restart_bttn.click(fn=self.local_request_restart, _js='restart_reload', inputs=[], outputs=[])
#File Importers
self.import_style_file.change(
fn = lambda tmp_file: self.import_file_from_path(tmp_file, target_folder="style_choices", comp = self.styles_dropdown, func = self.get_files, folder=self.style_folder, focus_list=self.styles_list),
inputs=self.import_style_file,
outputs=self.styles_dropdown
)
self.import_background_file.change(
fn = lambda tmp_file: self.import_file_from_path(tmp_file, target_folder="backgrounds", comp = self.background_dropdown, func = self.get_files, folder=self.backgrounds_folder, focus_list=self.backgrounds_list),
inputs=self.import_background_file,
outputs=self.background_dropdown
)
self.import_logo_file.change(
fn = lambda tmp_file: self.import_file_from_path(tmp_file, target_folder="logos", comp = self.logos_dropdown, func = self.get_files, folder=self.logos_folder, focus_list=self.logos_list),
inputs=self.import_logo_file,
outputs=self.logos_dropdown
)
self.import_favicon_file.change(
fn = lambda tmp_file: self.import_file_from_path(tmp_file, target_folder="favicons", comp = self.favicon_dropdown, func = self.get_files, folder=self.favicon_folder, focus_list=self.favicon_list),
inputs=self.import_favicon_file,
outputs=self.favicon_dropdown
)
return [(ui, "Theme", "theme")]
def import_file_from_path(self, tmp_file_obj, target_folder, comp, func, **kwargs):
if tmp_file_obj:
shutil.copy(tmp_file_obj.name, os.path.join(self.extensiondir, target_folder, tmp_file_obj.orig_name))
# Update appropriate list
# Make backend the same as front-end so it matches when selected
comp.choices = func(**kwargs)
tmp_file_obj.flush()
# return sends update to front-end
return gr.update(choices=comp.choices)
def get_files(self, folder, focus_list=[], file_filter=[], split=False):
focus_list = [file_name if not split else os.path.splitext(file_name)[0] for file_name in os.listdir(folder) if os.path.isfile(os.path.join(folder, file_name)) and file_name not in file_filter]
return focus_list
def apply_choice_wrapper(self, src_base_path, dst_base_path, name):
"""Encapsulation so I don't need a different function for each type"""
def apply_choice(selection):
shutil.copy(os.path.join(src_base_path, selection), os.path.join(dst_base_path, name))
return apply_choice
def get_image(self, name, folder):
return os.path.join(self.extensiondir, folder, name)
def refresh_list(self, component, folder, focus_list, file_filter=[]):
component.choices = self.get_files(folder, focus_list, file_filter)
return gr.update(choices=component.choices)
def delete_style(self):
try:
os.remove(os.path.join(self.extensiondir, "style.css"))
except FileNotFoundError:
pass
def local_request_restart(self):
"Restart button"
shared.state.interrupt()
shared.state.need_restart = True
def process_for_save(self, x, *y):
return [x] + [gr.update(visible=True), None]
def save(self, js_cmp_val, filename):
rules = [f" {e};\n" for e in js_cmp_val[1:-1].split(";")][:-1]
#issue, save button needs to stay hidden until some color change
rules.insert(self.insert_colorpicker_break_rule_for_save, " /*ENDCOLORPICKERS*/\n")
rules.insert(self.insert_break_rule_for_save, " /*BREAKFILEREADER*/\n")
with open(self.style_path, 'r+') as file:
lines = file.readlines()
start_pos = self.start_position_for_save
for i, rule in enumerate(rules):
lines[start_pos + i] = rule
file.seek(0)
file.writelines(lines)
self.styles_dropdown.choices.insert(0, f"{filename}.css")
shutil.copy(self.style_path, os.path.join(self.style_folder, f"{filename}.css"))
return ["Saved", gr.update(choices=self.styles_dropdown.choices, value=self.styles_dropdown.choices[0])]
tab = MyTab(basedir)
script_callbacks.on_ui_tabs(tab.ui)

View File

@ -1,67 +0,0 @@
from dataclasses import dataclass
import os
from pathlib import Path
import shutil
from modules import scripts
@dataclass
class DefaultFile:
"""Move file to location as filename"""
og_file:str
current_path:str
dir:str
save_as_filename:str
#class UpdateInstructions:
# @staticmethod
# def instructions(other_clss):
# #Create new folder
# in_root_folders = ["static"]
# #in_extension_folder = []
# for f_name in in_root_folders:
# other_clss.check_folder
class BasicUpdater:
def __init__(self):
#sd-web-ui-qkcss dir
self.extensions_dir = scripts.basedir()
self.root_dir = Path(self.extensions_dir).parents[1]
self.static_dir = os.path.join(self.root_dir, "static")
self.style_folder = os.path.join(self.extensions_dir, "style_choices")
self.logos_folder = os.path.join(self.extensions_dir, "logos")
self.favicon_folder = os.path.join(self.extensions_dir, "favicons")
self.backgrounds_folder = os.path.join(self.extensions_dir, "backgrounds")
self.effects_folder = os.path.join(self.extensions_dir, "effects")
self.javascript_folder = os.path.join(self.extensions_dir, "javascript")
self.file_defaults = [
DefaultFile(og_file="logo.png", current_path=self.logos_folder, dir=self.static_dir, save_as_filename="logo.png"),
DefaultFile(r"favicon Original.svg", self.favicon_folder, self.static_dir, "favicon.svg"),
DefaultFile("blankbackground.png", self.backgrounds_folder, self.static_dir, "background.png")
]
self.updater_file = os.path.join(self.extensions_dir, "update")
if os.path.exists(self.updater_file):
self.check_folders(self.static_dir)
for fd in self.file_defaults:
self.clone_file(fd)
#UpdateInstructions.instructions(self)
os.remove(self.updater_file)
def check_folders(self, folder_path):
if not os.path.exists(folder_path):
os.mkdir(folder_path)
def clone_file(self, defaults_object:DefaultFile):
from_file = os.path.join(defaults_object.current_path, defaults_object.og_file)
to_file = os.path.join(defaults_object.dir, defaults_object.save_as_filename)
if not os.path.exists(to_file):
shutil.copy(from_file, to_file)
BasicUpdater()

View File

@ -0,0 +1,45 @@
.extra-network-thumbs {
.actions {
.name {
background:linear-gradient(0deg, rgba(0,0,0,.8), transparent);
font-weight: 500;
text-shadow: 0 1px 1px rgba(0,0,0,.9);
}
.additional > ul {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, rgba(0,0,0,.8), transparent) !important;
opacity: 0;
&:hover {
opacity: 1;
}
}
}
.card {
border-radius: var(--borderRadiusXS);
background-size: cover;
box-shadow: var(--boxShadow);
outline: 1px solid rgba(0,0,0,.5);
transition: all 0.2s ease-in-out;
&:hover {
transform: scale(1.5);
z-index: 500;
box-shadow: 0 6px 24px -4px rgba(0,0,0,.8);
}
}
.metadata-button {
font-size: 10px !important;
right: 4px;
top: 24px;
opacity: 0;
&:hover {
opacity: 1;
}
}
}

View File

@ -0,0 +1,22 @@
.livePreview,
.gradio-gallery,
.gradio-image,
.gradio-video,
.gradio-file{
background: var(--galleryBackground) !important;
border: 2px solid var(--colorBorder) !important;
border-radius: var(--block-radius) !important;
}
div.svelte-awbtu4 {
.livePreview,
.gradio-gallery,
.gradio-image,
.gradio-video,
.gradio-file{
background: var(--galleryBackground) !important;
border: 2px solid var(--colorBorder) !important;
border-radius: var(--block-radius) !important;
}
}

View File

@ -0,0 +1,72 @@
#quicksettings {
position: fixed;
z-index: 1000;
flex-wrap: nowrap;
top: 12px;
display: flex;
align-items: center;
&:before {
content: "";
display: block;
background: var(--logo) no-repeat;
width: 129px;
height: 26px;
z-index: 1000;
margin-right: 36px;
margin-left: 16px;
margin-top: 12px;
}
&:after {
content: "";
display: block;
position: fixed;
width: 100vw;
height: 121px;
top: 0;
left: 0;
z-index: 999;
border-block-end: 1px solid var(--colorBorderSecondary);
background: var(--colorFillQuaternary);
backdrop-filter: blur(24px);
}
> * {
z-index: 1000;
}
button.svelte-1ipelgc {
margin-bottom: 3px;
}
}
#tabs {
> .tabitem {
background: transparent;
border: none;
padding: var(--padding);
margin-top: 118px;
}
> div:first-child {
position: fixed;
top: 90px;
z-index: 1000;
flex-wrap: nowrap;
width: 100%;
border: none;
> button {
border: none;
border-bottom: 2px solid transparent !important;
flex: none;
&:hover {
border: none;
border-bottom: 2px solid var(--colorPrimary) !important;
flex: none;
}
&.selected {
background: transparent;
border: none;
border-bottom: 2px solid var(--colorPrimary) !important;
}
}
}
}

View File

@ -0,0 +1,22 @@
[id$="2img_prompt"] textarea {
color: rgba(208, 226, 178, 0.98) !important;
max-height: 84px;
overflow-y: auto;
&:focus {
color: rgba(244, 255, 225, 0.98) !important;
}
}
[id$="2img_neg_prompt"] textarea {
color: rgba(236, 210, 213, 0.98) !important;
max-height: 84px;
overflow-y: auto;
&:focus {
color: rgba(255, 240, 242, 0.98) !important;
}
}
.block.token-counter span {
backdrop-filter: blur(24px);
display: inline-block;
}

View File

@ -0,0 +1,21 @@
.block.svelte-mppz8v {
background: transparent;
}
[id$="_script_container"] {
margin-top: 24px;
.block.svelte-mppz8v {
border: unset !important;
}
> div:not(.absolute) {
background-color: var(--colorFillTertiary) !important;
border-color: transparent !important;
transition: all 0.3s ease-in-out !important;
margin-bottom: var(--marginSM) !important;
margin-top: 0 !important;
padding: var(--padding) !important;
border-radius: var(--borderRadius) !important;
}
}

View File

@ -0,0 +1,98 @@
input[type="range"] {
-webkit-appearance: none !important ;
background: transparent !important;
&:focus {
outline: none !important;
}
&::-webkit-slider-runnable-track {
cursor: pointer !important;
height: 6px !important;
border-radius: 3px !important;
background: var(--colorFill) !important;
opacity: 0.6 !important;
}
&:hover::-webkit-slider-runnable-track {
background: var(--colorPrimary) !important;
opacity: 1 !important;
transition: all 0.2s ease-in-out;
}
&::-moz-range-track {
cursor: pointer !important;
height: 6px !important;
border-radius: 3px !important;
background: var(--colorPrimary) !important;
}
&:hover::-moz-range-track {
background: var(--colorPrimary) !important;
transition: all 0.2s ease-in-out;
}
&::-ms-fill-upper,
&::-ms-fill-lower {
cursor: pointer !important;
height: 6px !important;
border-radius: 3px !important;
background: var(--colorPrimary) !important;
}
&:hover::-ms-fill-upper,
&:hover::-ms-fill-lower {
background: var(--colorBgElevated) !important;
transition: all 0.2s ease-in-out;
}
&::-webkit-slider-thumb {
border: 2px solid var(--colorText) !important;
height: 16px !important;
width: 16px !important;
border-radius: 16px !important;
background: var(--colorBgElevated) !important;
cursor: pointer !important;
-webkit-appearance: none !important;
margin-top: -5px !important;
}
&:active::-webkit-slider-thumb {
box-shadow: 0 0 3px var(--colorPrimary) !important;
border: 2px solid var(--colorPrimary) !important;
background: var(--colorBgElevated) !important;
}
&::-moz-range-thumb {
border: 2px solid var(--colorText) !important;
height: 16px !important;
width: 16px !important;
border-radius: 16px !important;
background: var(--colorBgElevated) !important;
cursor: pointer !important;
margin-top: -5px !important;
z-index: 999;
}
&:active::-moz-range-thumb {
box-shadow: 0 0 3px var(--colorPrimary) !important;
border: 2px solid var(--colorPrimary) !important;
background: var(--colorBgElevated) !important;
}
&::-ms-thumb {
border: 2px solid var(--colorText) !important;
height: 16px !important;
width: 16px !important;
border-radius: 16px !important;
background: var(--colorBgElevated) !important;
cursor: pointer !important;
margin-top: -5px !important;
}
&:active::-ms-thumb {
box-shadow: 0 0 3px var(--colorPrimary) !important;
border: 2px solid var(--colorPrimary) !important;
background: var(--colorBgElevated) !important;
}
}

View File

@ -0,0 +1,7 @@
[id$="_row_aspect_ratio"],
[id$="_row_resolutions"] {
display: inline-block !important;
margin: 0;
padding: 0;
width: 180px !important;
}

43
src/theme/style.less Normal file
View File

@ -0,0 +1,43 @@
/* Root */
@import "utils/normalize";
/* Var */
@import "var/antd";
@import "var/gradioRoot";
@import "var/gradioDark";
/* Components */
@import "components/header";
@import "components/sliders";
@import "components/prompt-textarea";
@import "components/gallery";
@import "components/script-container";
@import "components/extra-network";
/* Plugin */
@import "plugin/aspect_ratio";
/* Theme Fix*/
.gradio-container {
font-size: var(--fontSize);
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
background-image: radial-gradient(
circle 600px at calc(100% - 300px) 300px,
var(--colorPrimaryBgHover),
var(--colorBgLayout)
);
background-repeat: no-repeat;
}
#txtimg_hr_finalres {
color: var(--colorPrimary) !important;
}
#interrogate, #deepbooru {
max-height: 72px;;
}

349
src/theme/utils/normalize.less vendored Normal file
View File

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

86
src/theme/var/antd.less Normal file
View File

@ -0,0 +1,86 @@
:root {
--colorPrimaryBg: #111a2c;
--colorPrimaryBgHover: #112545;
--colorPrimaryBorder: #15325b;
--colorPrimaryBorderHover: #15417e;
--colorPrimaryHover: #3c89e8;
--colorPrimary: #1668dc;
--colorPrimaryActive: #1554ad;
--colorPrimaryTextHover: #3c89e8;
--colorPrimaryText: #1668dc;
--colorPrimaryTextActive: #1554ad;
--colorErrorBg: #2c1618;
--colorErrorBgHover: #451d1f;
--colorErrorBorder: #5b2526;
--colorErrorBorderHover: #7e2e2f;
--colorErrorHover: #e86e6b;
--colorError: #dc4446;
--colorErrorActive: #ad393a;
--colorErrorTextHover: #e86e6b;
--colorErrorText: #dc4446;
--colorErrorTextActive: #ad393a;
--colorText: rgba(255, 255, 255, 0.85);
--colorTextSecondary: rgba(255, 255, 255, 0.65);
--colorTextTertiary: rgba(255, 255, 255, 0.45);
--colorTextQuaternary: rgba(255, 255, 255, 0.25);
--colorBgContainer: #141414;
--colorBgElevated: #1f1f1f;
--colorBgLayout: #141414;
--colorBgSpotlight: #424242;
--colorBgMask: rgba(0, 0, 0, 0.45);
--colorBorder: #424242;
--colorBorderSecondary: #303030;
--colorFill: rgba(255, 255, 255, 0.18);
--colorFillSecondary: rgba(255, 255, 255, 0.12);
--colorFillTertiary: rgba(255, 255, 255, 0.08);
--colorFillQuaternary: rgba(255, 255, 255, 0.04);
/* Typography */
--fontSizeBase: 14;
--fontSizeSM: calc(1px * var(--fontSizeBase) - 2px);
--fontSize: calc(1px * var(--fontSizeBase));
--fontSizeLG: calc(1px * var(--fontSizeBase) + 2px);
--fontSizeXL: calc(1px * var(--fontSizeBase) + 4px);
/* Spacing */
--marginBase: 4;
--marginXXS: calc(1px * var(--marginBase));
--marginXS: calc(2px * var(--marginBase));
--marginSM: calc(3px * var(--marginBase));
--margin: calc(4px * var(--marginBase));
--marginMD: calc(5px * var(--marginBase));
--marginLG: calc(6px * var(--marginBase));
--marginXL: calc(8px * var(--marginBase));
--marginXXL: calc(12px * var(--marginBase));
--paddingBase: 4;
--paddingXXS: calc(1px * var(--paddingBase));
--paddingXS: calc(2px * var(--paddingBase));
--paddingSM: calc(3px * var(--paddingBase));
--padding: calc(4px * var(--paddingBase));
--paddingMD: calc(5px * var(--paddingBase));
--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);
/* Border */
--borderRadiusBase: 2;
--borderRadiusXS: calc(1px * var(--borderRadiusBase));
--borderRadiusSM: calc(2px * var(--borderRadiusBase));
--borderRadius: calc(3px * var(--borderRadiusBase));
--borderRadiusLG: calc(4px * var(--borderRadiusBase));
/* Other */
--logo: url("https://gw.alipayobjects.com/zos/bmw-prod/9ecb2822-1592-4cb0-a087-ce0097fef2ca.svg");
--favicon: url("https://gw.alipayobjects.com/zos/bmw-prod/51a51720-8a30-4430-b6c9-be5712364f04.svg");
--galleryBackground: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAIKADAAQAAAABAAAAIAAAAACPTkDJAAAAZUlEQVRIDe2VMQoAMAgDa9/g/1/oIzrpZBCh2dLFkkoDF0Fz99OdiOjks+2/7S8fRRmMMIVoRGSoYzvvqF8ZIMKlC1GhQBc6IkPzq32QmdAzkEGihpWOSPsAss8HegYySNSw0hE9WQ4StafZFqkAAAAASUVORK5CYII=)
0% 0% / 20px;
}

View File

@ -0,0 +1,240 @@
.dark {
/* Colors */
--neutral-50: var(--colorText);
--neutral-100: var(--colorText);
--neutral-200: var(--colorTextSecondary);
--neutral-300: var(--colorTextTertiary);
--neutral-400: var(--colorTextQuaternary);
--neutral-500: var(--colorFill);
--neutral-600: var(--colorFillSecondary);
--neutral-700: var(--colorFillTertiary);
--neutral-800: var(--colorFillQuaternary);
--neutral-900: var(--colorBgElevated);
--neutral-950: var(--colorBgContainer);
--primary-50: #eff6ff;
--primary-100: #dbeafe;
--primary-200: #bfdbfe;
--primary-300: #93c5fd;
--primary-400: var(--colorPrimaryTextHover);
--primary-500: var(--colorPrimaryText);
--primary-600: var(--colorPrimary);
--primary-700: var(--colorPrimary);
--primary-800: var(--colorPrimaryBorder);
--primary-900: var(--colorPrimaryBgHover);
--primary-950: var(--colorPrimaryBg);
--secondary-50: #eff6ff;
--secondary-100: #dbeafe;
--secondary-200: #bfdbfe;
--secondary-300: #93c5fd;
--secondary-400: var(--colorPrimaryTextHover);
--secondary-500: var(--colorPrimaryText);
--secondary-600: var(--colorPrimary);
--secondary-700: var(--colorPrimary);
--secondary-800: var(--colorPrimaryBorder);
--secondary-900: var(--colorPrimaryBgHover);
--secondary-950: var(--colorPrimaryBg);
--error-text-color: #ef4444;
--error-background-fill: var(--colorErrorBg);
--background-fill-primary: var(--neutral-950);
--background-fill-secondary: var(--neutral-900);
--stat-background-fill: var(--primary-500);
--link-text-color-active: var(--secondary-500);
--link-text-color: var(--secondary-500);
--link-text-color-hover: var(--secondary-400);
--link-text-color-visited: var(--secondary-600);
--color-accent: var(--primary-500);
--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-mono: "Hack", "IBM Plex Mono", "ui-monospace", "Consolas", monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
--section-header-text-weight: 400;
--text-lg: var(--fontSizeLG);
--text-md: var(--fontSize);
--text-sm: var(--fontSizeSM);
--text-xl: var(--fontSizeXL);
--text-xs: var(--fontSizeSM);
--text-xxl: var(--fontSizeXL);
--text-xxs: var(--fontSizeSM);
--prose-text-size: var(--text-md);
--section-header-text-size: var(--text-md);
/* Spacing */
--form-gap-width: 0px;
--spacing-lg: 8px;
--spacing-md: 6px;
--spacing-sm: 4px;
--spacing-xl: 10px;
--spacing-xs: 2px;
--spacing-xxl: 16px;
--spacing-xxs: 1px;
--layout-gap: var(--spacing-xxl);
/* Border */
--error-border-width: 1px;
--radius-lg: var(--borderRadiusLG);
--radius-md: var(--borderRadius);
--radius-sm: var(--borderRadiusSM);
--radius-xl: var(--borderRadiusXS);
--radius-xs: var(--borderRadiusSM);
--radius-xxl: var(--borderRadiusLG);
--radius-xxs: var(--borderRadiusXS);
--border-color-accent: var(--neutral-600);
--border-color-primary: var(--neutral-700);
--error-border-color: var(--border-color-primary);
--container-radius: var(--radius-lg);
--embed-radius: var(--radius-lg);
/* BoxShadow */
--shadow-spread: 1px;
--shadow-drop: var(--boxShadow);
--shadow-drop-lg: var(--boxShadowSecondary);
--shadow-inset: var(--boxShadow) inset;
/* Body */
--body-text-weight: 400;
--body-background-fill: var(--background-fill-primary);
--body-text-color: var(--neutral-100);
--body-text-color-subdued: var(--neutral-400);
--body-text-size: var(--text-md);
/* Block */
--block-border-width: 1px;
--block-info-text-weight: 400;
--block-label-border-width: 1px;
--block-label-margin: 0;
--block-label-text-weight: 400;
--block-shadow: none;
--block-title-background-fill: none;
--block-title-border-color: none;
--block-title-border-width: 0px;
--block-title-padding: 0;
--block-title-radius: none;
--block-title-text-weight: 400;
--block-background-fill: var(--neutral-800);
--block-border-color: var(--border-color-primary);
--block-info-text-color: var(--body-text-color-subdued);
--block-label-background-fill: var(--background-fill-secondary);
--block-label-border-color: var(--border-color-primary);
--block-label-text-color: var(--neutral-200);
--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-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
--block-radius: var(--radius-lg);
--block-title-text-size: var(--text-md);
/* Panel */
--panel-border-width: 0;
--panel-background-fill: var(--background-fill-secondary);
--panel-border-color: var(--border-color-primary);
/* Button */
--button-primary-text-color: white;
--button-secondary-text-color: white;
--button-large-text-weight: 600;
--button-shadow: none;
--button-shadow-active: none;
--button-shadow-hover: none;
--button-small-text-weight: 400;
--button-transition: background-color 0.2s ease;
--button-border-width: var(--input-border-width);
--button-cancel-background-fill: var(--button-secondary-background-fill);
--button-cancel-background-fill-hover: var(--button-cancel-background-fill);
--button-cancel-border-color: var(--button-secondary-border-color);
--button-cancel-border-color-hover: var(--button-cancel-border-color);
--button-cancel-text-color: var(--button-secondary-text-color);
--button-cancel-text-color-hover: var(--button-cancel-text-color);
--button-primary-background-fill: var(--primary-700);
--button-primary-background-fill-hover: var(--button-primary-background-fill);
--button-primary-border-color: var(--primary-600);
--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-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);
--button-large-padding: var(--spacing-lg) calc(2 * var(--spacing-lg));
--button-large-radius: var(--radius-lg);
--button-large-text-size: var(--text-lg);
--button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm));
--button-small-radius: var(--radius-lg);
--button-small-text-size: var(--text-md);
/* Checkbox */
--checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
--checkbox-label-shadow: none;
--checkbox-label-text-weight: 400;
--checkbox-background-color: var(--neutral-800);
--checkbox-background-color-focus: var(--checkbox-background-color);
--checkbox-background-color-hover: var(--checkbox-background-color);
--checkbox-background-color-selected: var(--secondary-600);
--checkbox-border-color: var(--neutral-700);
--checkbox-border-color-focus: var(--secondary-500);
--checkbox-border-color-hover: var(--neutral-600);
--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-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);
--checkbox-label-text-color: var(--body-text-color);
--checkbox-label-text-color-selected: var(--checkbox-label-text-color);
--checkbox-border-radius: var(--radius-sm);
--checkbox-label-gap: var(--spacing-lg);
--checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md));
--checkbox-label-text-size: var(--text-md);
--checkbox-shadow: var(--input-shadow);
/* Input */
--input-border-width: 0px;
--input-shadow: none;
--input-text-weight: 400;
--input-background-fill: var(--neutral-700);
--input-background-fill-focus: var(--secondary-600);
--input-background-fill-hover: var(--input-background-fill);
--input-border-color: var(--border-color-primary);
--input-border-color-focus: var(--neutral-700);
--input-border-color-hover: var(--input-border-color);
--input-placeholder-color: var(--neutral-500);
--input-padding: var(--spacing-xl);
--input-radius: var(--radius-lg);
--input-shadow-focus: var(--input-shadow);
--input-text-size: var(--text-md);
/* Table */
--table-border-color: var(--neutral-700);
--table-even-background-fill: var(--neutral-950);
--table-odd-background-fill: var(--neutral-900);
--table-row-focus: var(--color-accent-soft);
--table-radius: var(--radius-lg);
/* Other */
--radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
}

View File

@ -0,0 +1,240 @@
:root {
/* Colors */
--neutral-50: var(--colorText);
--neutral-100: var(--colorText);
--neutral-200: var(--colorTextSecondary);
--neutral-300: var(--colorTextTertiary);
--neutral-400: var(--colorTextQuaternary);
--neutral-500: var(--colorFill);
--neutral-600: var(--colorFillSecondary);
--neutral-700: var(--colorFillTertiary);
--neutral-800: var(--colorFillQuaternary);
--neutral-900: var(--colorBgElevated);
--neutral-950: var(--colorBgContainer);
--primary-50: #eff6ff;
--primary-100: #dbeafe;
--primary-200: #bfdbfe;
--primary-300: #93c5fd;
--primary-400: var(--colorPrimaryTextHover);
--primary-500: var(--colorPrimaryText);
--primary-600: var(--colorPrimary);
--primary-700: var(--colorPrimary);
--primary-800: var(--colorPrimaryBorder);
--primary-900: var(--colorPrimaryBgHover);
--primary-950: var(--colorPrimaryBg);
--secondary-50: #eff6ff;
--secondary-100: #dbeafe;
--secondary-200: #bfdbfe;
--secondary-300: #93c5fd;
--secondary-400: var(--colorPrimaryTextHover);
--secondary-500: var(--colorPrimaryText);
--secondary-600: var(--colorPrimary);
--secondary-700: var(--colorPrimary);
--secondary-800: var(--colorPrimaryBorder);
--secondary-900: var(--colorPrimaryBgHover);
--secondary-950: var(--colorPrimaryBg);
--error-background-fill: var(--colorErrorBg);
--error-text-color: var(--colorError);
--background-fill-primary: var(--neutral-950);
--background-fill-secondary: var(--neutral-900);
--stat-background-fill: var(--primary-300);
--color-accent: var(--primary-500);
--color-accent-soft: var(--primary-50);
--link-text-color: var(--secondary-600);
--link-text-color-active: var(--secondary-600);
--link-text-color-hover: var(--secondary-700);
--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-mono: "Hack", "IBM Plex Mono", "ui-monospace", "Consolas", monospace;
--prose-header-text-weight: 600;
--prose-text-weight: 400;
--section-header-text-weight: 400;
--text-lg: var(--fontSizeLG);
--text-md: var(--fontSize);
--text-sm: var(--fontSizeSM);
--text-xl: var(--fontSizeXL);
--text-xs: var(--fontSizeSM);
--text-xxl: var(--fontSizeXL);
--text-xxs: var(--fontSizeSM);
--prose-text-size: var(--text-md);
--section-header-text-size: var(--text-md);
/* Spacing */
--form-gap-width: 0px;
--spacing-lg: 8px;
--spacing-md: 6px;
--spacing-sm: 4px;
--spacing-xl: 10px;
--spacing-xs: 2px;
--spacing-xxl: 16px;
--spacing-xxs: 1px;
--layout-gap: var(--spacing-xxl);
/* Border */
--error-border-color: #fecaca;
--error-border-width: 1px;
--radius-lg: var(--borderRadiusLG);
--radius-md: var(--borderRadius);
--radius-sm: var(--borderRadiusSM);
--radius-xl: var(--borderRadiusXS);
--radius-xs: var(--borderRadiusSM);
--radius-xxl: var(--borderRadiusLG);
--radius-xxs: var(--borderRadiusXS);
--border-color-accent: var(--primary-300);
--border-color-primary: var(--neutral-200);
--container-radius: var(--radius-lg);
--embed-radius: var(--radius-lg);
/* BoxShadow */
--shadow-spread: 1px;
--shadow-drop: var(--boxShadow);
--shadow-drop-lg: var(--boxShadowSecondary);
--shadow-inset: var(--boxShadow) inset;
/* Body */
--body-text-weight: 400;
--body-background-fill: var(--background-fill-primary);
--body-text-color: var(--neutral-800);
--body-text-color-subdued: var(--neutral-400);
--body-text-size: var(--text-md);
/* Block */
--block-border-width: 1px;
--block-info-text-weight: 400;
--block-label-border-width: 1px;
--block-label-margin: 0;
--block-label-text-weight: 400;
--block-shadow: none;
--block-title-background-fill: none;
--block-title-border-color: none;
--block-title-border-width: 0px;
--block-title-padding: 0;
--block-title-radius: none;
--block-title-text-weight: 400;
--block-background-fill: var(--background-fill-primary);
--block-border-color: var(--border-color-primary);
--block-info-text-color: var(--body-text-color-subdued);
--block-info-text-size: var(--text-sm);
--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-text-color: var(--neutral-500);
--block-label-text-size: var(--text-sm);
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
--block-radius: var(--radius-lg);
--block-title-text-color: var(--neutral-500);
--block-title-text-size: var(--text-md);
/* Panel */
--panel-border-width: 0;
--panel-background-fill: var(--background-fill-secondary);
--panel-border-color: var(--border-color-primary);
/* Button */
--button-large-text-weight: 600;
--button-shadow: none;
--button-shadow-active: none;
--button-shadow-hover: none;
--button-small-text-weight: 400;
--button-transition: background-color 0.2s ease;
--button-border-width: var(--input-border-width);
--button-cancel-background-fill: var(--button-secondary-background-fill);
--button-cancel-background-fill-hover: var(--button-cancel-background-fill);
--button-cancel-border-color: var(--button-secondary-border-color);
--button-cancel-border-color-hover: var(--button-cancel-border-color);
--button-cancel-text-color: var(--button-secondary-text-color);
--button-cancel-text-color-hover: var(--button-cancel-text-color);
--button-large-padding: var(--spacing-lg) calc(2 * var(--spacing-lg));
--button-large-radius: var(--radius-lg);
--button-large-text-size: var(--text-lg);
--button-primary-background-fill: var(--primary-200);
--button-primary-background-fill-hover: var(--button-primary-background-fill);
--button-primary-border-color: var(--primary-200);
--button-primary-border-color-hover: var(--button-primary-border-color);
--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-border-color: var(--neutral-200);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color: var(--neutral-700);
--button-secondary-text-color-hover: var(--button-secondary-text-color);
--button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm));
--button-small-radius: var(--radius-lg);
--button-small-text-size: var(--text-md);
/* Checkbox */
--checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
--checkbox-label-shadow: none;
--checkbox-label-text-weight: 400;
--checkbox-background-color: var(--background-fill-primary);
--checkbox-background-color-focus: var(--checkbox-background-color);
--checkbox-background-color-hover: var(--checkbox-background-color);
--checkbox-background-color-selected: var(--secondary-600);
--checkbox-border-color: var(--neutral-300);
--checkbox-border-color-focus: var(--secondary-500);
--checkbox-border-color-hover: var(--neutral-300);
--checkbox-border-color-selected: var(--secondary-600);
--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-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);
--checkbox-label-gap: var(--spacing-lg);
--checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md));
--checkbox-label-text-color: var(--body-text-color);
--checkbox-label-text-color-selected: var(--checkbox-label-text-color);
--checkbox-label-text-size: var(--text-md);
--checkbox-shadow: var(--input-shadow);
/* Input */
--input-border-width: 0px;
--input-shadow: none;
--input-text-weight: 400;
--input-background-fill: var(--neutral-100);
--input-background-fill-focus: var(--secondary-500);
--input-background-fill-hover: var(--input-background-fill);
--input-border-color: var(--border-color-primary);
--input-border-color-focus: var(--secondary-300);
--input-border-color-hover: var(--input-border-color);
--input-padding: var(--spacing-xl);
--input-placeholder-color: var(--neutral-400);
--input-radius: var(--radius-lg);
--input-shadow-focus: var(--input-shadow);
--input-text-size: var(--text-md);
/* Table */
--table-even-background-fill: white;
--table-border-color: var(--neutral-300);
--table-odd-background-fill: var(--neutral-50);
--table-radius: var(--radius-lg);
--table-row-focus: var(--color-accent-soft);
/* Other */
--radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
}

2215
style.css

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

137
utils/formatCSS.js Normal file
View File

@ -0,0 +1,137 @@
const fs = require("fs");
const path = require("path");
// 从本地文件读取CSS
const cssFilePath = path.resolve(__dirname, "style.css");
const css = fs.readFileSync(cssFilePath, "utf-8");
// 用于存储变量及其值的对象
const cssVariables = {};
// 正则表达式用于匹配CSS变量及其值
const cssVarRegex = /--\w+[^:]*:\s*([^;]*);/g;
const cssVarReferenceRegex = /var\((--\w+)\)/g;
// 解析CSS变量及其值
let match;
while ((match = cssVarRegex.exec(css))) {
const variable = match[0].split(":")[0].trim();
const value = match[1].trim();
cssVariables[variable] = value;
}
// 对变量进行排序,确保被引用的变量在引用它的变量之前
const sortedVariables = Object.keys(cssVariables);
// 按类别对变量进行分组
const groups = {
colors: [],
typography: [],
spacing: [],
border: [],
boxShadow: [],
body: [],
block: [],
panel: [],
button: [],
checkbox: [],
input: [],
table: [],
other: [],
};
sortedVariables.forEach((variable) => {
const value = cssVariables[variable];
const isColor =
value.startsWith("#") ||
value.includes("rgb") ||
value.includes("color") ||
variable.includes("color") ||
variable.includes("fill") ||
variable.includes("neutral");
const isTypography =
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");
if (variable.includes("--body")) {
groups.body.push(variable);
} else if (variable.includes("--block")) {
groups.block.push(variable);
} else if (variable.includes("--panel")) {
groups.panel.push(variable);
} else if (variable.includes("--button")) {
groups.button.push(variable);
} else if (variable.includes("--checkbox")) {
groups.checkbox.push(variable);
} else if (variable.includes("--input")) {
groups.input.push(variable);
} else if (variable.includes("--table")) {
groups.table.push(variable);
} else if (isBorder) {
groups.border.push(variable);
} else if (isBoxShadow) {
groups.boxShadow.push(variable);
} else if (isColor) {
groups.colors.push(variable);
} else if (isTypography) {
groups.typography.push(variable);
} else if (isSpacing) {
groups.spacing.push(variable);
} else {
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 sortedCss =
"#output {\n" +
`/* Colors */\n` +
generateGroupCss("colors") +
`\n\n/* Typography */\n` +
generateGroupCss("typography") +
`\n\n/* Spacing */\n` +
generateGroupCss("spacing") +
`\n\n/* Border */\n` +
generateGroupCss("border") +
`\n\n/* BoxShadow */\n` +
generateGroupCss("boxShadow") +
`\n\n/* Body */\n` +
generateGroupCss("body") +
`\n\n/* Block */\n` +
generateGroupCss("block") +
`\n\n/* Panel */\n` +
generateGroupCss("panel") +
`\n\n/* Button */\n` +
generateGroupCss("button") +
`\n\n/* Checkbox */\n` +
generateGroupCss("checkbox") +
`\n\n/* Input */\n` +
generateGroupCss("input") +
`\n\n/* Table */\n` +
generateGroupCss("table") +
`\n\n/* Other */\n` +
generateGroupCss("other") +
"}";
console.log(sortedCss);
// 将排序后的CSS变量写入文件
fs.writeFileSync("sorted-css-variables.css", sortedCss);

2371
yarn.lock Normal file

File diff suppressed because it is too large Load Diff