✨ feat: add antd token support
commit
6c712233be
|
|
@ -0,0 +1,32 @@
|
|||
on:
|
||||
schedule:
|
||||
# runs once a week on sunday
|
||||
- cron: "55 23 * * 0"
|
||||
jobs:
|
||||
# This workflow contains a single job called "traffic"
|
||||
traffic:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "traffic"
|
||||
|
||||
# Calculates traffic and clones and stores in CSV file
|
||||
- name: GitHub traffic
|
||||
uses: sangonzal/repository-traffic-action@v.0.1.6
|
||||
env:
|
||||
TRAFFIC_ACTION_TOKEN: ${{ secrets.TRAFFIC_ACTION_TOKEN }}
|
||||
|
||||
|
||||
# Commits files to repository
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v4
|
||||
with:
|
||||
author_name: Gerschel
|
||||
message: "GitHub traffic"
|
||||
add: "./traffic/*"
|
||||
ref: "traffic" # commits to branch "traffic"
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
**/node_modules
|
||||
npm-debug.log*
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
|
||||
# production
|
||||
**/dist
|
||||
/plugins/
|
||||
/es
|
||||
/lib
|
||||
/logs
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.eslintcache
|
||||
.husky
|
||||
|
||||
# umi
|
||||
/src/.umi
|
||||
/src/.umi-production
|
||||
/src/.umi-test
|
||||
/.env.local
|
||||
|
||||
# ide
|
||||
.idea
|
||||
.vscode
|
||||
.history
|
||||
*.log
|
||||
functions/*
|
||||
lambda/mock/index.js
|
||||
.temp/**
|
||||
|
||||
# test
|
||||
**/test-output
|
||||
config.yml
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
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()})
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
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 });
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
FaviconHandler.observeGradioApp();
|
||||
});
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
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()})
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
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
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,387 @@
|
|||
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)
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
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()
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue