mirror of
https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
synced 2024-06-07 21:20:49 +00:00
Fix bug with resizegrid resetting on tab change. Add content to details view.
This commit is contained in:
parent
dc5b155cda
commit
25e516a1d3
@ -1,11 +1,16 @@
|
||||
import os
|
||||
import html
|
||||
import datetime
|
||||
import math
|
||||
import matplotlib as mpl
|
||||
import colorsys
|
||||
|
||||
import network
|
||||
import networks
|
||||
|
||||
from modules import shared, ui_extra_networks
|
||||
from modules.ui_extra_networks import quote_js
|
||||
from ui_edit_user_metadata import LoraUserMetadataEditor
|
||||
from ui_edit_user_metadata import LoraUserMetadataEditor, build_tags
|
||||
|
||||
|
||||
class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
||||
@ -89,3 +94,134 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
||||
|
||||
def create_user_metadata_editor(self, ui, tabname):
|
||||
return LoraUserMetadataEditor(ui, tabname, self)
|
||||
|
||||
def get_model_detail_metadata_table(self, model_name: str) -> str:
|
||||
res = super().get_model_detail_metadata_table(model_name)
|
||||
|
||||
metadata = self.metadata.get(model_name)
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
|
||||
keys = {
|
||||
'ss_output_name': "Output name:",
|
||||
'ss_sd_model_name': "Model:",
|
||||
'ss_clip_skip': "Clip skip:",
|
||||
'ss_network_module': "Kohya module:",
|
||||
}
|
||||
|
||||
params = []
|
||||
|
||||
for k, lbl in keys.items():
|
||||
v = metadata.get(k, None)
|
||||
if v is not None and str(v) != "None":
|
||||
params.append((lbl, html.escape(v)))
|
||||
|
||||
ss_training_started_at = metadata.get('ss_training_started_at')
|
||||
if ss_training_started_at:
|
||||
date_trained = datetime.datetime.utcfromtimestamp(
|
||||
float(ss_training_started_at)
|
||||
).strftime('%Y-%m-%d %H:%M')
|
||||
params.append(("Date trained:", date_trained))
|
||||
|
||||
ss_bucket_info = metadata.get("ss_bucket_info")
|
||||
if ss_bucket_info and "buckets" in ss_bucket_info:
|
||||
resolutions = {}
|
||||
for _, bucket in ss_bucket_info["buckets"].items():
|
||||
resolution = bucket["resolution"]
|
||||
resolution = f'{resolution[1]}x{resolution[0]}'
|
||||
resolutions[resolution] = resolutions.get(resolution, 0) + int(bucket["count"])
|
||||
|
||||
resolutions_list = sorted(resolutions.keys(), key=resolutions.get, reverse=True)
|
||||
resolutions_text = html.escape(", ".join(resolutions_list))
|
||||
resolutions_text = (
|
||||
"<div class='styled-scrollbar' style='overflow-x: auto'>"
|
||||
f"{resolutions_text}"
|
||||
"</div>"
|
||||
)
|
||||
params.append(("Resolutions:", resolutions_text))
|
||||
|
||||
image_count = 0
|
||||
for v in metadata.get("ss_dataset_dirs", {}).values():
|
||||
image_count += int(v.get("img_count", 0))
|
||||
|
||||
if image_count:
|
||||
params.append(("Dataset size:", image_count))
|
||||
|
||||
tbl_metadata = "".join([f"<tr><th>{tr[0]}</th><td>{tr[1]}</td>" for tr in params])
|
||||
|
||||
return res + tbl_metadata
|
||||
|
||||
def get_model_detail_extra_html(self, model_name: str) -> str:
|
||||
"""Generates HTML to show in the details view."""
|
||||
res = ""
|
||||
|
||||
item = self.items.get(model_name, {})
|
||||
metadata = item.get("metadata", {}) or {}
|
||||
user_metadata = item.get("user_metadata", {}) or {}
|
||||
|
||||
sd_version = item.get("sd_version", None)
|
||||
preferred_weight = user_metadata.get("preferred weight", None)
|
||||
activation_text = user_metadata.get("activation text", None)
|
||||
negative_text = user_metadata.get("negative text", None)
|
||||
|
||||
rows = []
|
||||
|
||||
if sd_version is not None:
|
||||
rows.append(("SD Version:", sd_version))
|
||||
|
||||
if preferred_weight is not None:
|
||||
rows.append(("Preferred weight:", preferred_weight))
|
||||
|
||||
if activation_text is not None:
|
||||
rows.append(("Activation text:", activation_text))
|
||||
|
||||
if negative_text is not None:
|
||||
rows.append(("Negative propmt:", negative_text))
|
||||
|
||||
rows_html = "".join([f"<tr><th>{tr[0]}</th><td>{tr[1]}</td>" for tr in rows])
|
||||
|
||||
if rows_html:
|
||||
res += "<h3>User Metadata</h3>"
|
||||
res += f"<table><tbody>{rows_html}</tbody></table>"
|
||||
|
||||
tags = build_tags(metadata)
|
||||
if tags is None or len(tags) == 0:
|
||||
return res
|
||||
|
||||
min_tag = min(int(x[1]) for x in tags)
|
||||
max_tag = max(int(x[1]) for x in tags)
|
||||
cmap = mpl.colormaps["coolwarm"]
|
||||
|
||||
def _clamp(x: float, min_val: float, max_val: float) -> float:
|
||||
return max(min_val, min(x, max_val))
|
||||
|
||||
def _get_fg_color(r, g, b) -> str:
|
||||
return "#000000" if (r * 0.299 + g * 0.587 + b * 0.114) > 0.5 else "#FFFFFF"
|
||||
|
||||
tag_elems = []
|
||||
for (tag_name, tag_count) in tags:
|
||||
# Normalize tag count
|
||||
tag_count = int(tag_count)
|
||||
cmap_idx = math.floor((tag_count - min_tag) / (max_tag - min_tag) * (cmap.N - 1))
|
||||
base_color = cmap(cmap_idx)
|
||||
base_color = [_clamp(x, 0, 1) for x in base_color]
|
||||
base_fg_color = _get_fg_color(*base_color[:3])
|
||||
h, lum, s = colorsys.rgb_to_hls(*base_color[:3])
|
||||
lum = max(min(lum * 0.7, 1.0), 0.0)
|
||||
dark_color = colorsys.hls_to_rgb(h, lum, s)
|
||||
dark_color = [_clamp(x, 0, 1) for x in dark_color]
|
||||
dark_fg_color = _get_fg_color(*dark_color[:3])
|
||||
base_color = mpl.colors.rgb2hex(base_color)
|
||||
dark_color = mpl.colors.rgb2hex(dark_color)
|
||||
tag_style = f"background: {mpl.colors.rgb2hex(base_color)};"
|
||||
name_style = f"color: {base_fg_color};"
|
||||
count_style = f"background: {dark_color}; color: {dark_fg_color};"
|
||||
tag_elems.append((
|
||||
f"<span class='model-info--tag' style='{tag_style}'>"
|
||||
f"<span class='model-info--tag-name' style='{name_style}'>{tag_name}</span>"
|
||||
f"<span class='model-info--tag-count' style='{count_style}'>{tag_count}</span>"
|
||||
"</span>"
|
||||
))
|
||||
res += "<h3>Model Tags</h3>"
|
||||
res += f"<div class='model-info--tags'>{''.join(tag_elems)}</div>"
|
||||
return res
|
||||
|
17
html/extra-networks-model-details.html
Normal file
17
html/extra-networks-model-details.html
Normal file
@ -0,0 +1,17 @@
|
||||
<div class="extra-network-content--dets-view-model-info">
|
||||
<div class="model-info--header">
|
||||
<h1>{name}</h1>
|
||||
<button class="extra-network-control model-info--close" title="Close model details">
|
||||
<svg class="extra-network-control--icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M 2 2 L 14 14 M 2 14 L 14 2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p>{description}</p>
|
||||
<h3>Model Metadata</h3>
|
||||
<table>
|
||||
<tbody>{metadata_table}</tbody>
|
||||
</table>
|
||||
{model_specific}
|
||||
</div>
|
@ -204,7 +204,7 @@
|
||||
</div>
|
||||
<div id="{tabname}_{extra_networks_tabname}_dets_view_cell" class="resize-grid--cell"
|
||||
style="{dets_view_cell_style}" {dets_view_cell_data_attributes}>
|
||||
<div class="extra-network-content extra-network-content--dets-view"></div>
|
||||
<div class="extra-network-content extra-network-content--dets-view styled-scrollbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@
|
||||
ExtraNetworksClusterizeCardList,
|
||||
waitForElement,
|
||||
isString,
|
||||
isObject,
|
||||
isElement,
|
||||
isElementThrowError,
|
||||
fetchWithRetryAndBackoff,
|
||||
@ -395,7 +396,10 @@ class ExtraNetworksTab {
|
||||
this.resize_grid.toggle({elem: div_dirs, override: this.dirs_view_en});
|
||||
this.resize_grid.toggle({elem: div_tree, override: this.tree_view_en});
|
||||
this.resize_grid.toggle({elem: div_card, override: this.card_view_en});
|
||||
this.resize_grid.toggle({elem: div_dets, override: this.dets_view_en});
|
||||
this.resize_grid.toggle({
|
||||
elem: div_dets,
|
||||
override: this.dets_view_en && div_dets.innerHTML !== "",
|
||||
});
|
||||
|
||||
// apply the previous sort/filter options
|
||||
await this.applyListButtonStates();
|
||||
@ -462,7 +466,10 @@ class ExtraNetworksTab {
|
||||
this.resize_grid.toggle({elem: div_dirs, override: this.dirs_view_en});
|
||||
this.resize_grid.toggle({elem: div_tree, override: this.tree_view_en});
|
||||
this.resize_grid.toggle({elem: div_card, override: this.card_view_en});
|
||||
this.resize_grid.toggle({elem: div_dets, override: this.dets_view_en});
|
||||
this.resize_grid.toggle({
|
||||
elem: div_dets,
|
||||
override: this.dets_view_en && div_dets.innerHTML !== "",
|
||||
});
|
||||
}
|
||||
|
||||
unload() {
|
||||
@ -911,6 +918,45 @@ class ExtraNetworksTab {
|
||||
}
|
||||
this.applyDirectoryFilters();
|
||||
}
|
||||
|
||||
showDetsView(source_elem) {
|
||||
const div_dets = this.container_elem.querySelector(".extra-network-content--dets-view");
|
||||
|
||||
const _popup = (msg) => {
|
||||
const elem = document.createElement("pre");
|
||||
elem.classList.add("popup-metadata");
|
||||
elem.textContent = msg;
|
||||
popup(elem);
|
||||
};
|
||||
|
||||
const _clear_details = () => {
|
||||
div_dets.innerHTML = "";
|
||||
};
|
||||
|
||||
const _show_details = (response) => {
|
||||
if (!isObject(response) || !isString(response.html)) {
|
||||
console.warn("Error parsing model details.");
|
||||
div_dets.innerHTML = "Error parsing model details.";
|
||||
return;
|
||||
}
|
||||
div_dets.innerHTML = response.html;
|
||||
};
|
||||
|
||||
_clear_details();
|
||||
|
||||
requestGet(
|
||||
"./sd_extra_networks/get-model-details",
|
||||
{
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
model_name: source_elem.dataset.name,
|
||||
},
|
||||
(response) => _show_details(response),
|
||||
() => _popup("Error fetching model details."),
|
||||
);
|
||||
if (this.dets_view_en) {
|
||||
this.resize_grid.toggle({elem: div_dets, override: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function popup(contents) {
|
||||
@ -1309,20 +1355,30 @@ function extraNetworksControlDetsViewOnClick(event) {
|
||||
/** Handles `onclick` events for the Card Details View button.
|
||||
*
|
||||
* Toggles the card details view in the extra networks pane.
|
||||
*
|
||||
* This button is unique in that we allow the user to enable/disable it
|
||||
* regardless of whether we actually show the details view. This is because
|
||||
* the details view only actually shows when the user has a model selected.
|
||||
* Otherwise, the view is always hidden.
|
||||
*/
|
||||
const btn = event.target.closest(".extra-network-control--dets-view");
|
||||
const controls = btn.closest(".extra-network-controls");
|
||||
const tab = extra_networks_tabs[controls.dataset.tabnameFull];
|
||||
|
||||
btn.toggleAttribute("data-selected");
|
||||
tab.dets_view_en = "selected" in btn.dataset;
|
||||
|
||||
const div_dets = tab.container_elem.querySelector(".extra-network-content--dets-view");
|
||||
|
||||
try {
|
||||
tab.resize_grid.toggle({elem: div_dets, override: !("selected" in btn.dataset)});
|
||||
tab.resize_grid.toggle({
|
||||
elem: div_dets,
|
||||
override: tab.dets_view_en && div_dets.innerHTML !== "",
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn("Error attempting to enable dets_view:", error);
|
||||
return;
|
||||
}
|
||||
btn.toggleAttribute("data-selected");
|
||||
tab.dets_view_en = "selected" in btn.dataset;
|
||||
}
|
||||
|
||||
function extraNetworksControlRefreshOnClick(event) {
|
||||
@ -1376,11 +1432,6 @@ function extraNetworksSelectModel({tab, prompt, neg_prompt, allow_neg, checkpoin
|
||||
}
|
||||
|
||||
function extraNetworksCardOnClick(event) {
|
||||
// Do not select the card if its child button-row is the target of the event.
|
||||
if (event.target.closest(".button-row")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = event.target.closest(".card");
|
||||
const pane = btn.closest(".extra-network-pane");
|
||||
const tab = extra_networks_tabs[pane.dataset.tabnameFull];
|
||||
@ -1398,6 +1449,34 @@ function extraNetworksCardOnClick(event) {
|
||||
});
|
||||
}
|
||||
|
||||
function extraNetworksDetsViewCloseOnClick(event) {
|
||||
const btn = event.target.closest(".model-info--close");
|
||||
const pane = btn.closest(".extra-network-pane");
|
||||
const tab = extra_networks_tabs[pane.dataset.tabnameFull];
|
||||
|
||||
const div_dets = tab.container_elem.querySelector(".extra-network-content--dets-view");
|
||||
div_dets.innerHTML = "";
|
||||
tab.resize_grid.toggle({elem: div_dets, override: false});
|
||||
}
|
||||
|
||||
function extraNetworksDetsViewTagOnClick(event) {
|
||||
const btn = event.target.closest(".model-info--tag");
|
||||
const pane = btn.closest(".extra-network-pane");
|
||||
const tab = extra_networks_tabs[pane.dataset.tabnameFull];
|
||||
|
||||
const tag_name_elem = btn.querySelector(".model-info--tag-name");
|
||||
isElementThrowError(tag_name_elem);
|
||||
extraNetworksUpdatePrompt(tab.active_prompt_elem, tag_name_elem.textContent);
|
||||
}
|
||||
|
||||
function extraNetworksCardOnLongPress(event) {
|
||||
const btn = event.target.closest(".card");
|
||||
const pane = btn.closest(".extra-network-pane");
|
||||
const tab = extra_networks_tabs[pane.dataset.tabnameFull];
|
||||
|
||||
tab.showDetsView(btn);
|
||||
}
|
||||
|
||||
function extraNetworksTreeFileOnClick(event) {
|
||||
// Do not select the row if its child button-row is the target of the event.
|
||||
if (event.target.closest(".tree-list-item-action")) {
|
||||
@ -1674,7 +1753,6 @@ function extraNetworksSetupEventDelegators() {
|
||||
|
||||
const click_event_map = {
|
||||
".tree-list-item--file": extraNetworksTreeFileOnClick,
|
||||
".card": extraNetworksCardOnClick,
|
||||
".copy-path-button": extraNetworksBtnCopyPathOnClick,
|
||||
".edit-button": extraNetworksBtnEditMetadataOnClick,
|
||||
".metadata-button": extraNetworksBtnShowMetadataOnClick,
|
||||
@ -1717,6 +1795,19 @@ function extraNetworksSetupEventDelegators() {
|
||||
selector: ".extra-network-dirs-view-button",
|
||||
handler: extraNetworksBtnDirsViewItemOnClick,
|
||||
},
|
||||
{
|
||||
selector: ".card",
|
||||
negative: ".button-row",
|
||||
handler: extraNetworksCardOnClick,
|
||||
},
|
||||
{
|
||||
selector: ".model-info--close",
|
||||
handler: extraNetworksDetsViewCloseOnClick,
|
||||
},
|
||||
{
|
||||
selector: ".model-info--tag",
|
||||
handler: extraNetworksDetsViewTagOnClick,
|
||||
}
|
||||
];
|
||||
|
||||
const short_ctrl_press_event_map = [
|
||||
@ -1752,6 +1843,11 @@ function extraNetworksSetupEventDelegators() {
|
||||
selector: ".extra-network-dirs-view-button",
|
||||
handler: extraNetworksBtnDirsViewItemOnLongPress,
|
||||
},
|
||||
{
|
||||
selector: ".card",
|
||||
negative: ".button-row",
|
||||
handler: extraNetworksCardOnLongPress,
|
||||
},
|
||||
];
|
||||
|
||||
const long_ctrl_press_event_map = [
|
||||
|
@ -842,6 +842,8 @@ class ResizeGrid extends ResizeGridAxis {
|
||||
axis: axis,
|
||||
callbacks: callbacks,
|
||||
});
|
||||
|
||||
this.elem.id = id;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
@ -1013,7 +1015,7 @@ class ResizeGrid extends ResizeGridAxis {
|
||||
|
||||
this.resize_observer = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.target.id === this.elem.id) {
|
||||
if (entry.target.id === this.id) {
|
||||
clearTimeout(this.resize_observer_timer);
|
||||
this.resize_observer_timer = setTimeout(() => {
|
||||
this.onResize();
|
||||
@ -1157,6 +1159,18 @@ class ResizeGrid extends ResizeGridAxis {
|
||||
onResize() {
|
||||
/** Resizes grid items on resize observer events. */
|
||||
const curr_dims = this.elem.getBoundingClientRect();
|
||||
|
||||
// If height and width are 0, this indicates the element is not visible anymore.
|
||||
// We don't want to do anything if the element isn't visible.
|
||||
if (curr_dims.height === 0 && curr_dims.width === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do nothing if the dimensions haven't changed.
|
||||
if (JSON.stringify(curr_dims) === JSON.stringify(this.prev_dims)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const d_w = curr_dims.width - this.prev_dims.width;
|
||||
const d_h = curr_dims.height - this.prev_dims.height;
|
||||
|
||||
|
@ -8,13 +8,14 @@ from base64 import b64decode
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
import datetime
|
||||
|
||||
import gradio as gr
|
||||
from fastapi.exceptions import HTTPException
|
||||
from PIL import Image
|
||||
from starlette.responses import FileResponse, JSONResponse, Response
|
||||
|
||||
from modules import errors, extra_networks, shared, util
|
||||
from modules import errors, extra_networks, shared, util, sysinfo
|
||||
from modules.images import read_info_from_image, save_image_with_geninfo
|
||||
from modules.infotext_utils import image_from_url_text
|
||||
from modules.ui_common import OutputPanel
|
||||
@ -24,6 +25,7 @@ extra_pages = []
|
||||
allowed_dirs = set()
|
||||
default_allowed_preview_extensions = ["png", "jpg", "jpeg", "webp", "gif"]
|
||||
|
||||
|
||||
class ListItem:
|
||||
"""
|
||||
Attributes:
|
||||
@ -244,6 +246,7 @@ class ExtraNetworksPage:
|
||||
self.btn_edit_metadata_tpl = shared.html("extra-networks-btn-edit-metadata.html")
|
||||
self.btn_dirs_view_item_tpl = shared.html("extra-networks-btn-dirs-view-item.html")
|
||||
self.btn_chevron_tpl = shared.html("extra-networks-btn-chevron.html")
|
||||
self.model_details_tpl = shared.html("extra-networks-model-details.html")
|
||||
|
||||
def clear_data(self) -> None:
|
||||
self.is_ready = False
|
||||
@ -998,6 +1001,63 @@ class ExtraNetworksPage:
|
||||
def create_user_metadata_editor(self, ui, tabname) -> UserMetadataEditor:
|
||||
return UserMetadataEditor(ui, tabname, self)
|
||||
|
||||
def get_model_detail_metadata_table(self, model_name: str) -> str:
|
||||
item = self.items.get(model_name, {})
|
||||
|
||||
def _relative_path(path):
|
||||
for parent_path in self.allowed_directories_for_previews():
|
||||
if path_is_parent(parent_path, path):
|
||||
return os.path.relpath(path, parent_path)
|
||||
|
||||
return os.path.basename(path)
|
||||
|
||||
try:
|
||||
filename = item["filename"]
|
||||
shorthash = item.get("shorthash", None)
|
||||
|
||||
stats = os.stat(filename)
|
||||
params = [
|
||||
('Filename: ', _relative_path(filename)),
|
||||
('File size: ', sysinfo.pretty_bytes(stats.st_size)),
|
||||
('Hash: ', shorthash),
|
||||
('Modified: ', datetime.datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M')),
|
||||
]
|
||||
except Exception as exc:
|
||||
errors.display(exc, f"reading info for {model_name}")
|
||||
params = []
|
||||
|
||||
return "".join([f"<tr><th>{tr[0]}</th><td>{tr[1]}</td>" for tr in params])
|
||||
|
||||
def get_model_detail_extra_html(self, _model_name: str) -> str:
|
||||
"""Returns extra HTML to add to model details.
|
||||
|
||||
NOTE: This is intended to be subclassed to provide more model-specific info
|
||||
in the model details. Thus the base class just returns an empty string.
|
||||
"""
|
||||
return ""
|
||||
|
||||
def gen_model_details_html(self, model_name):
|
||||
tbl_metadata = self.get_model_detail_metadata_table(model_name)
|
||||
|
||||
item = self.items.get(model_name, {})
|
||||
user_metadata = item.get("user_metadata", None)
|
||||
if user_metadata:
|
||||
description = user_metadata.get("description", "")
|
||||
else:
|
||||
description = item.get("description", "")
|
||||
|
||||
if not description:
|
||||
description = ""
|
||||
|
||||
model_specific = self.get_model_detail_extra_html(model_name)
|
||||
|
||||
return self.model_details_tpl.format(
|
||||
name=model_name,
|
||||
description=description,
|
||||
metadata_table=tbl_metadata,
|
||||
model_specific=model_specific,
|
||||
)
|
||||
|
||||
|
||||
@functools.cache
|
||||
def allowed_preview_extensions_with_extra(extra_extensions=None):
|
||||
@ -1197,6 +1257,12 @@ def get_metadata(extra_networks_tabname: str = "", item: str = "") -> JSONRespon
|
||||
return JSONResponse({"metadata": json.dumps(metadata, indent=4, ensure_ascii=False)})
|
||||
|
||||
|
||||
def get_model_details(extra_networks_tabname: str = "", model_name: str = "") -> JSONResponse:
|
||||
page = get_page_by_name(extra_networks_tabname)
|
||||
|
||||
return JSONResponse({"html": page.gen_model_details_html(model_name)})
|
||||
|
||||
|
||||
def get_single_card(
|
||||
tabname: str = "",
|
||||
extra_networks_tabname: str = "",
|
||||
@ -1234,6 +1300,7 @@ def add_pages_to_demo(app):
|
||||
app.add_api_route("/sd_extra_networks/fetch-card-data", fetch_card_data, methods=["GET"])
|
||||
app.add_api_route("/sd_extra_networks/page-is-ready", page_is_ready, methods=["GET"])
|
||||
app.add_api_route("/sd_extra_networks/clear-page-data", clear_page_data, methods=["GET"])
|
||||
app.add_api_route("/sd_extra_networks/get-model-details", get_model_details, methods=["GET"])
|
||||
|
||||
|
||||
def quote_js(s):
|
||||
|
100
style.css
100
style.css
@ -1711,7 +1711,7 @@ body.resizing.resize-grid-row {
|
||||
/* Custom scrollbar style. Only works on chromium based browsers. */
|
||||
.styled-scrollbar::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
width: var(--text-lg);
|
||||
width: var(--spacing-xxl);
|
||||
}
|
||||
|
||||
.styled-scrollbar::-webkit-scrollbar-track {
|
||||
@ -1722,13 +1722,17 @@ body.resizing.resize-grid-row {
|
||||
.styled-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
border: calc(var(--button-border-width) * 4) solid var(--background-fill-primary);
|
||||
border: var(--spacing-sm) solid var(--background-fill-primary);
|
||||
}
|
||||
|
||||
.styled-scrollbar::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.styled-scrollbar::-webkit-scrollbar-corner {
|
||||
background: var(--background-fill-primary);
|
||||
}
|
||||
|
||||
/* Long-press buttons. Wipe L->R effect when button is held, then toggles color. */
|
||||
.extra-network-dirs-view-button {
|
||||
position: relative;
|
||||
@ -1869,3 +1873,95 @@ body.resizing.resize-grid-row {
|
||||
padding: var(--block-label-padding);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view {
|
||||
padding: var(--block-padding);
|
||||
overflow: clip auto;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info p {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info table {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--prose-text-weight);
|
||||
margin-left: var(--spacing-lg) !important;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info table :is(th, td) {
|
||||
padding-top: var(--spacing-sm) !important;
|
||||
padding-bottom: var(--spacing-sm) !important;
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info table th {
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
.extra-network-content--dets-view-model-info table td {
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
.model-info--tags {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.model-info--header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.model-info--header h1 {
|
||||
flex: 1;
|
||||
margin: 0 !important;
|
||||
justify-items: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.model-info--close {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.model-info--tag {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--button-shadow);
|
||||
border-width: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
text-shadow: var(--shadow-drop);
|
||||
font-size: var(--button-large-text-size);
|
||||
font-weight: var(--body-text-weight);
|
||||
transition: var(--button-transition);
|
||||
padding: var(--spacing-xs) calc(2 * var(--spacing-xs));
|
||||
}
|
||||
|
||||
.model-info--tag:active {
|
||||
box-shadow: var(--button-shadow-active);
|
||||
}
|
||||
|
||||
.model-info--tag::hover {
|
||||
box-shadow: var(--button-shadow-hover);
|
||||
}
|
||||
|
||||
.model-info--tag-name {
|
||||
padding: var(--spacing-xs) calc(2 * var(--spacing-xs));
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.model-info--tag-count {
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--spacing-xs) calc(2 * var(--spacing-xs));
|
||||
font-weight: var(--button-large-text-weight);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user