cleanup and fix bugs.

This commit is contained in:
Sj-Si 2024-03-27 16:11:13 -04:00
parent d88e91c508
commit 0e0b613b4d
8 changed files with 158 additions and 137 deletions

View file

@ -1,5 +1,5 @@
<button
class='lg secondary gradio-button custom-button extra-network-dirs-view-button {extra_class}'
onclick='extraNetworkDirsOnClick(event, "{tabname_full}")'>
onclick='extraNetworksDirsOnClick(event, "{tabname_full}")'>
{path}
</button>

View file

@ -1,13 +1,12 @@
<div id='{tabname}_{extra_networks_tabname}_pane' class='extra-network-pane', data-tabname-full="{tabname}_{extra_networks_tabname}">
<div id="{tabname}_{extra_networks_tabname}_controls" class="extra-network-controls" style="display:none">
<div class="extra-network-controls hidden" data-tabname-full="{tabname}_{extra_networks_tabname}">
<div class="extra-network-control--search">
<svg class="extra-network-control--search-icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<circle cx="6" cy="6" r="5" />
<line x1="9.75" y1="9.75" x2="13" y2="13" />
</svg>
<input id="{tabname}_{extra_networks_tabname}_extra_search" class="extra-network-control--search-text"
type="text" placeholder="Search">
<input class="extra-network-control--search-text" type="text" placeholder="Search">
<button role="button" class="extra-network-control extra-network-control--search-clear"
onclick="extraNetworksControlSearchClearOnClick(event, '{tabname}_{extra_networks_tabname}');">
<svg class="extra-network-control--search-clear-icon" viewBox="0 0 16 16"
@ -91,8 +90,8 @@
data-sort-dir="{data_sort_dir}">
<svg class="extra-network-control--icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
fill="none" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<path id="extra-network-control--sort-dir-icon-ascending" d="M 8 1 L 3 7 L 13 7 Z" />
<path id="extra-network-control--sort-dir-icon-descending" d="M 8 15 L 3 9 L 13 9 Z" />
<path class="extra-network-control--sort-dir-icon-ascending" d="M 8 1 L 3 7 L 13 7 Z" />
<path class="extra-network-control--sort-dir-icon-descending" d="M 8 15 L 3 9 L 13 9 Z" />
</svg>
</button>
</div>
@ -100,8 +99,7 @@
<div class="extra-network-controls--container">
<div class="extra-network-controls--header">View Mode</div>
<div class="extra-network-controls--buttons">
<button id="{tabname}_{extra_networks_tabname}_extra_dirs_view"
class="extra-network-control extra-network-control--dirs-view"
<button class="extra-network-control extra-network-control--dirs-view"
title="Enable Directory View"
onclick="extraNetworksControlDirsViewOnClick(event, '{tabname}_{extra_networks_tabname}');"
{btn_dirs_view_data_attributes}>
@ -112,8 +110,7 @@
<rect x="12" y="6" width="4" height="4" rx="1" />
</svg>
</button>
<button id="{tabname}_{extra_networks_tabname}_extra_tree_view"
class="extra-network-control extra-network-control--tree-view"
<button class="extra-network-control extra-network-control--tree-view"
title="Enable Tree View"
onclick="extraNetworksControlTreeViewOnClick(event, '{tabname}_{extra_networks_tabname}');"
{btn_tree_view_data_attributes}>
@ -131,8 +128,7 @@
<div class="extra-network-controls--container">
<div class="extra-network-controls--header">Refresh</div>
<div class="extra-network-controls--buttons">
<button id="{tabname}_{extra_networks_tabname}_extra_refresh"
class="extra-network-control extra-network-control--refresh" title="Refresh tab"
<button class="extra-network-control extra-network-control--refresh" title="Refresh tab"
onclick="extraNetworksControlRefreshOnClick(event, '{tabname}_{extra_networks_tabname}');">
<svg class="extra-network-control--icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
@ -143,10 +139,8 @@
</div>
</div>
</div>
<div id="{tabname}_{extra_networks_tabname}_pane_content"
class="extra-network-content--container">
<div id='{tabname}_{extra_networks_tabname}_dirs'
class="extra-network-content extra-network-content--dirs {dirs_view_hidden_cls}">
<div class="extra-network-content--container">
<div class="extra-network-content extra-network-content--dirs-view {dirs_view_hidden_cls}">
{dirs_html}
</div>
<div class="extra-network-content extra-network-content--cards resize-handle-row">

View file

@ -1,21 +1,12 @@
<button
class="tree-list-item tree-list-item--{btn_type}"
onclick="extraNetworksTreeOnClick(event, '{tabname}_{extra_networks_tabname}');{onclick_extra}"
title={btn_title}
{data_attributes}>
<span data-filterable-item-text hidden>{search_terms}</span>
<span class='tree-list-item-action tree-list-item-action--leading'>
{action_list_item_action_leading}
</span>
<span class="tree-list-item-visual tree-list-item-visual--leading">
{action_list_item_visual_leading}
</span>
<span class="tree-list-item-label tree-list-item-label--truncate">
{action_list_item_label}
</span>
<span class="tree-list-item-visual tree-list-item-visual--trailing">
{action_list_item_visual_trailing}
</span>
<span class="tree-list-item-action tree-list-item-action--trailing">
{action_list_item_action_trailing}
</span>
<span class='tree-list-item-action tree-list-item-action--leading'>{action_list_item_action_leading}</span>
<span class="tree-list-item-visual tree-list-item-visual--leading">{action_list_item_visual_leading}</span>
<span class="tree-list-item-label tree-list-item-label--truncate">{action_list_item_label}</span>
<span class="tree-list-item-visual tree-list-item-visual--trailing">{action_list_item_visual_trailing}</span>
<span class="tree-list-item-action tree-list-item-action--trailing">{action_list_item_action_trailing}</span>
</div>

View file

@ -194,11 +194,13 @@ function toggleCss(key, css, enable) {
function extraNetworksRefreshTab(tabname_full) {
// Reapply controls since they don't change on refresh.
let btn_dirs_view = gradioApp().querySelector(`#${tabname_full}_extra_dirs_view`);
let btn_tree_view = gradioApp().querySelector(`#${tabname_full}_extra_tree_view`);
const controls = gradioApp().getElementById(`${tabname_full}_controls`);
let btn_dirs_view = controls.querySelector(".extra-network-control--dirs-view");
let btn_tree_view = controls.querySelector(".extra-network-control--tree-view");
let div_dirs = gradioApp().querySelector(`#${tabname_full}_dirs`);
let div_tree = gradioApp().querySelector(`.extra-network-content.resize-handle-col:has(> #${tabname_full}_tree_list_scroll_area)`);
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
let div_dirs = pane.querySelector(".extra-network-content--dirs-view");
let div_tree = pane.querySelector(`.extra-network-content.resize-handle-col:has(> #${tabname_full}_tree_list_scroll_area)`);
// Remove "hidden" class if button is enabled, otherwise add it.
div_dirs.classList.toggle("hidden", !("selected" in btn_dirs_view.dataset));
@ -222,44 +224,33 @@ function extraNetworksRegisterPromptForTab(tabname, id) {
function extraNetworksSetupTabContent(tabname, pane, controls_div) {
const tabname_full = pane.id;
let txt_search;
let controls;
Promise.all([
waitForElement(`#${tabname_full}_extra_search`).then((elem) => txt_search = elem),
waitForElement(`#${tabname_full}_dirs`),
waitForElement(`#${tabname_full}_pane .extra-network-controls`).then(elem => controls = elem),
waitForElement(`#${tabname_full}_pane .extra-network-content--dirs-view`),
waitForElement(`#${tabname_full}_tree_list_scroll_area > #${tabname_full}_tree_list_content_area`),
waitForElement(`#${tabname_full}_cards_list_scroll_area > #${tabname_full}_cards_list_content_area`),
]).then(() => {
// Insert the controls into the page.
// add an ID since we will be moving this element elsewhere.
controls.id = `${tabname_full}_controls`;
controls_div.insertBefore(controls, null);
// Now that we have our elements in DOM, we create the clusterize lists.
clusterizers[tabname_full] = {
tree_list: new ExtraNetworksClusterizeTreeList({
data_id: `${tabname_full}_tree_list_data`,
scroll_id: `${tabname_full}_tree_list_scroll_area`,
content_id: `${tabname_full}_tree_list_content_area`,
txt_search_elem: txt_search,
}),
cards_list: new ExtraNetworksClusterizeCardsList({
data_id: `${tabname_full}_cards_list_data`,
scroll_id: `${tabname_full}_cards_list_scroll_area`,
content_id: `${tabname_full}_cards_list_content_area`,
txt_search_elem: txt_search,
}),
};
// Debounce search text input. This way we only search after user is done typing.
const search_input_debounce = debounce(() => {
extraNetworksApplyFilter(tabname_full);
}, SEARCH_INPUT_DEBOUNCE_TIME_MS);
txt_search.addEventListener("keyup", search_input_debounce);
// Update search filter whenever the search input's clear button is pressed.
txt_search.addEventListener("extra-network-control--search-clear", () => {
extraNetworksApplyFilter(tabname_full);
});
// Insert the controls into the page.
const controls = gradioApp().querySelector(`#${tabname_full}_controls`);
controls_div.insertBefore(controls, null);
if (pane.style.display != "none") {
extraNetworksShowControlsForPage(tabname, tabname_full);
}
@ -314,7 +305,8 @@ function extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePromp
function extraNetworksShowControlsForPage(tabname, tabname_full) {
gradioApp().querySelectorAll(`#${tabname}_extra_tabs .extra-network-controls-div > div`).forEach((elem) => {
elem.style.display = `${tabname_full}_controls` === elem.id ? "" : "none";
let show = `${tabname_full}_controls` === elem.id;
elem.classList.toggle("hidden", !show);
});
}
@ -338,23 +330,24 @@ function extraNetworksApplyFilter(tabname_full) {
return;
}
// We only want to filter/sort the cards list.
clusterizers[tabname_full].cards_list.applyFilter();
// If the search input has changed since selecting a button to populate it
// then we want to disable the button that previously populated the search input.
const txt_search = gradioApp().querySelector(`#${tabname_full}_extra_search`);
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
const txt_search = gradioApp().querySelector(`#${tabname_full}_controls .extra-network-control--search-text`);
if (!isElementLogError(txt_search)) {
return;
}
// We only want to filter/sort the cards list.
clusterizers[tabname_full].cards_list.applyFilter(txt_search.value.toLowerCase());
// If the search input has changed since selecting a button to populate it
// then we want to disable the button that previously populated the search input.
// tree view buttons
let btn = gradioApp().querySelector(`#${tabname_full}_tree_list_content_area .tree-list-item[data-selected=""]`);
let btn = pane.querySelector(".tree-list-item[data-selected='']");
if (isElement(btn) && btn.dataset.path !== txt_search.value && "selected" in btn.dataset) {
clusterizers[tabname_full].tree_list.onRowSelected(btn.dataset.divId, btn, false);
}
// dirs view buttons
btn = gradioApp().querySelector(`#${tabname_full}_dirs .extra-network-dirs-view-button[data-selected=""]`);
btn = pane.querySelector(".extra-network-dirs-view-button[data-selected='']");
if (isElement(btn) && btn.textContent.trim() !== txt_search.value) {
delete btn.dataset.selected;
}
@ -390,31 +383,79 @@ function extraNetworkClusterizersOnTabLoad(tabname_full) { /** promise */
});
}
function extraNetworksSetupEventHandlers() {
// Handle doubleclick events from the resize handle.
// This will automatically fit the left pane to the size of its largest loaded row.
window.addEventListener("resizeHandleDblClick", (e) => {
function extraNetworksAutoSetTreeWidth(pane) {
if (!isElementLogError(pane)) {
return;
}
const tabname_full = pane.dataset.tabnameFull;
// This event is only applied to the currently selected tab if has clusterize lists.
if (!(tabname_full in clusterizers)) {
return;
}
const row = pane.querySelector(".resize-handle-row");
if (!isElementLogError(row)) {
return;
}
const left_col = row.firstElementChild;
if (!isElementLogError(left_col)) {
return;
}
if (left_col.classList.contains("hidden")) {
// If the left column is hidden then we don't want to do anything.
return;
}
const pad = parseFloat(row.style.gridTemplateColumns.split(" ")[1]);
const min_left_col_width = parseFloat(left_col.style.flexBasis.slice(0, -2));
// We know that the tree list is the left column. That is the only one we want to resize.
let max_width = clusterizers[tabname_full].tree_list.getMaxRowWidth();
// Add the resize handle's padding to the result and default to minLeftColWidth if necessary.
max_width = Math.max(max_width + pad, min_left_col_width);
// Mimicks resizeHandle.js::setLeftColGridTemplate().
row.style.gridTemplateColumns = `${max_width}px ${pad}px 1fr`;
}
function extraNetworksSetupEventDelegators() {
/** Sets up event delegators for all extraNetworks tabs.
*
* These event handlers are not tied to any specific elements on the page.
* We do this because elements within each tab may be removed and replaced
* which would break references to elements in DOM and thus prevent any event
* listeners from firing.
*/
window.addEventListener("resizeHandleDblClick", event => {
// See resizeHandle.js::onDoubleClick() for event detail.
e.stopPropagation();
const tabname_full = e.target.closest(".extra-network-pane").dataset.tabnameFull;
// This event is only applied to the currently selected tab if has clusterize list.
if (!(tabname_full in clusterizers)) {
return;
event.stopPropagation();
extraNetworksAutoSetTreeWidth(event.target.closest(".extra-network-pane"));
});
// Update search filter whenever the search input's clear button is pressed.
window.addEventListener("extra-network-control--search-clear", event => {
event.stopPropagation();
extraNetworksApplyFilter(event.detail.tabname_full);
});
// Debounce search text input. This way we only search after user is done typing.
const search_input_debounce = debounce((tabname_full) => {
extraNetworksApplyFilter(tabname_full);
}, SEARCH_INPUT_DEBOUNCE_TIME_MS);
window.addEventListener("keyup", event => {
const controls = event.target.closest(".extra-network-controls");
if (isElement(controls)) {
const tabname_full = controls.dataset.tabnameFull;
const target = event.target.closest(".extra-network-control--search-text");
if (isElement(target)) {
search_input_debounce.call(target, tabname_full);
}
}
// Shouldn't be possible, but if tree is hidden then we want to ignore this event
// since there wouldn't be any content to calculate row width. When hidden,
// the resize handle shouldn't exist on page but just in case...
if (gradioApp().getElementById(`${tabname_full}_tree_list_scroll_area`).parentElement.classList.contains("hidden")) {
return;
}
// We know that the tree list is the left column. That is the only one we want to resize.
let max_width = clusterizers[tabname_full].tree_list.getMaxRowWidth();
// Add the resize handle's padding to the result and default to minLeftColWidth if necessary.
max_width = Math.max(max_width + e.detail.pad, e.detail.minLeftColWidth);
e.detail.setLeftColGridTemplate(e.target, max_width);
});
}
@ -422,7 +463,7 @@ function setupExtraNetworks() {
waitForBool(initialUiOptionsLoaded).then(() => {
extraNetworksSetupTab('txt2img');
extraNetworksSetupTab('img2img');
extraNetworksSetupEventHandlers();
extraNetworksSetupEventDelegators();
});
}
@ -531,9 +572,9 @@ function extraNetworksTreeProcessDirectoryClick(event, btn, tabname_full) {
function _updateSearch(_search_text) {
// Update search input with select button's path.
var search_input_elem = gradioApp().querySelector(`#${tabname_full}_extra_search`);
search_input_elem.value = _search_text;
updateInput(search_input_elem);
const txt_search = gradioApp().querySelector(`#${tabname_full}_controls .extra-network-control--search-text`);
txt_search.value = _search_text;
updateInput(txt_search);
extraNetworksApplyFilter(tabname_full);
}
@ -573,10 +614,9 @@ function extraNetworksTreeOnClick(event, tabname_full) {
event.stopPropagation();
}
function extraNetworkDirsOnClick(event, tabname_full) {
function extraNetworksDirsOnClick(event, tabname_full) {
/** Handles `onclick` events for buttons in the directory view. */
let txt_search = gradioApp().querySelector(`#${tabname_full}_extra_search`);
const txt_search = gradioApp().querySelector(`#${tabname_full}_controls .extra-network-control--search-text`);
function _deselect_all() {
// deselect all buttons
gradioApp().querySelectorAll(".extra-network-dirs-view-button").forEach((elem) => {
@ -615,7 +655,10 @@ function extraNetworksControlSearchClearOnClick(event, tabname_full) {
txt_search.dispatchEvent(
new CustomEvent(
"extra-network-control--search-clear",
{detail: {tabname_full: tabname_full}},
{
bubbles: true,
detail: {tabname_full: tabname_full}
},
)
);
}
@ -688,7 +731,8 @@ function extraNetworksControlDirsViewOnClick(event, tabname_full) {
show = true;
}
gradioApp().getElementById(`${tabname_full}_dirs`).classList.toggle("hidden", !show);
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
pane.querySelector(".extra-network-content--dirs-view").classList.toggle("hidden", !show);
}
function extraNetworksControlRefreshOnClick(event, tabname_full) {

View file

@ -126,7 +126,6 @@ class ExtraNetworksClusterize {
data_id,
scroll_id,
content_id,
txt_search_elem,
rows_in_block = 10,
blocks_in_cluster = 4,
show_no_data_row = true,
@ -148,14 +147,10 @@ class ExtraNetworksClusterize {
if (!isStringLogError(content_id)) {
return;
}
if (!isElementLogError(txt_search_elem)) {
return;
}
this.data_id = data_id;
this.scroll_id = scroll_id;
this.content_id = content_id;
this.txt_search_elem = txt_search_elem;
this.rows_in_block = rows_in_block;
this.blocks_in_cluster = blocks_in_cluster;
this.show_no_data_row = show_no_data_row;
@ -830,8 +825,8 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
const prev_style = child.style.cssText;
const n_cols = child_style.getPropertyValue("grid-template-columns").split(" ").length;
child.style.gridTemplateColumns = `repeat(${n_cols}, max-content)`;
row_width += getComputedDims(child).width;
// Re-apply previous style.
row_width += child.scrollWidth;
// Restore previous style.
child.style.cssText = prev_style;
}
max_width = Math.max(max_width, row_width);
@ -840,9 +835,8 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
return;
}
// Add the container's padding to the result.
max_width += getComputedPaddingDims(this.content_elem).width;
// Add the scrollbar's width to the result. Will add 0 if scrollbar isnt present.
// Adds the scroll element's border and the scrollbar's width to the result.
// If scrollbar isn't visible, then only the element border is added.
max_width += this.scroll_elem.offsetWidth - this.scroll_elem.clientWidth;
return max_width;
}
@ -856,7 +850,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
this.no_data_text = "No files matching filter.";
this.sort_mode_str = "path";
this.sort_dir_str = "ascending";
this.filter_str = "";
this.default_filter_str = "";
this.filter_str = this.default_filter_str;
}
updateJson(json) {
@ -980,10 +975,10 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
applyFilter(filter_str) {
/** Filters our data object by setting each member's `active` attribute then sorts the result. */
if (filter_str !== undefined && filter_str !== null) {
if (!isNullOrUndefined(filter_str)) {
this.filter_str = filter_str.toLowerCase();
} else {
this.filter_str = this.txt_search_elem.value.toLowerCase();
} else if (isNullOrUndefined(this.filter_str)) {
this.filter_str = this.default_filter_str;
}
for (const [k, v] of Object.entries(this.data_obj)) {

View file

@ -59,17 +59,8 @@
parent.style.gridTemplateColumns = parent.style.originalGridTemplateColumns;
// Fire custom event to modify left column width externally.
parent.dispatchEvent(
new CustomEvent("resizeHandleDblClick", {
bubbles: true,
detail: {
setLeftColGridTemplate: setLeftColGridTemplate,
pad: PAD,
minLeftColWidth: parent.minLeftColWidth,
},
}),
);
// Fire a custom event so user can perform additional tasks on double click.
parent.dispatchEvent(new CustomEvent("resizeHandleDblClick", {bubbles: true}));
}
const leftCol = parent.firstElementChild;
@ -164,7 +155,13 @@
} else {
delta = R.screenX - evt.changedTouches[0].screenX;
}
const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - R.parent.minRightColWidth - PAD), R.parent.minLeftColWidth);
const leftColWidth = Math.max(
Math.min(
R.leftColStartWidth - delta,
R.parent.offsetWidth - R.parent.minRightColWidth - PAD,
),
R.parent.minLeftColWidth,
);
setLeftColGridTemplate(R.parent, leftColWidth);
}
});

View file

@ -245,6 +245,7 @@ class ExtraNetworksPage:
tabname: str,
label: str,
btn_type: str,
btn_title: str,
dir_is_empty: bool = False,
metadata: Optional[str] = None,
parent_id: Optional[int] = None,
@ -258,6 +259,9 @@ class ExtraNetworksPage:
) -> str:
if btn_type not in ["file", "dir"]:
raise ValueError("Invalid button type:", btn_type)
label = label.strip()
btn_title = btn_title.strip()
action_list_item_action_leading = "<i class='tree-list-item-action-chevron'></i>"
action_list_item_visual_leading = "🗀"
@ -308,6 +312,7 @@ class ExtraNetworksPage:
"data_attributes": data_attributes,
"search_terms": "",
"btn_type": btn_type,
"btn_title": btn_title,
"tabname": tabname,
"onclick_extra": onclick_extra if onclick_extra else "",
"extra_networks_tabname": self.extra_networks_tabname,
@ -357,6 +362,7 @@ class ExtraNetworksPage:
data_depth=depth,
data_path=k,
btn_type="dir",
btn_title=k,
dir_is_empty=dir_is_empty,
)
last_div_id = self.build_tree_html_dict(
@ -408,6 +414,7 @@ class ExtraNetworksPage:
data_allow_neg=str(self.allow_negative_prompt).lower(),
onclick_extra=onclick,
btn_type="file",
btn_title=v.item["name"],
)
div_id += 1
return div_id

View file

@ -1252,7 +1252,7 @@ body.resizing .resize-handle {
flex-direction: column;
}
.extra-network-content--dirs {
.extra-network-content--dirs-view {
flex: 0 1 0%;
flex-direction: row;
flex-wrap: wrap;
@ -1345,10 +1345,6 @@ body.resizing .resize-handle {
background: var(--button-secondary-background-fill-hover);
}
.extra-network-control:hover .extra-network-control--icon {
color: var(--button-secondary-text-color-hover);
}
.extra-network-control:active {
background: var(--button-secondary-background-fill);
}
@ -1357,10 +1353,6 @@ body.resizing .resize-handle {
color: var(--button-secondary-text-color-hover);
}
.extra-network-control[data-selected] {
background: var(--button-secondary-background-fill);
}
.extra-network-control[data-selected] .extra-network-control--icon {
color: var(--button-secondary-text-color);
}
@ -1443,32 +1435,33 @@ body.resizing .resize-handle {
}
/* Customize behavior or sort direction button icon. */
.extra-network-control--sort-dir[data-sort-dir="ascending"] #extra-network-control--sort-dir-icon-ascending {
.extra-network-control--sort-dir[data-sort-dir="ascending"] .extra-network-control--sort-dir-icon-ascending {
fill: var(--button-secondary-text-color);
stroke: var(--button-secondary-text-color);
}
.extra-network-control--sort-dir[data-sort-dir="ascending"] #extra-network-control--sort-dir-icon-descending {
.extra-network-control--sort-dir[data-sort-dir="ascending"] .extra-network-control--sort-dir-icon-descending {
stroke: var(--input-placeholder-color);
}
.extra-network-control--sort-dir[data-sort-dir="descending"] #extra-network-control--sort-dir-icon-descending {
.extra-network-control--sort-dir[data-sort-dir="descending"] .extra-network-control--sort-dir-icon-descending {
fill: var(--button-secondary-text-color);
stroke: var(--button-secondary-text-color);
}
.extra-network-control--sort-dir[data-sort-dir="descending"] #extra-network-control--sort-dir-icon-ascending {
.extra-network-control--sort-dir[data-sort-dir="descending"] .extra-network-control--sort-dir-icon-ascending {
stroke: var(--input-placeholder-color);
}
/* ==== ICONS ==== */
.extra-network-control--refresh:hover .extra-network-control--icon {
animation: rotate 3s infinite;
animation: extra-network-control--refresh-keyframe-rotate 3s infinite;
transform-origin: 50% 50%;
transform-box: fill-box;
color: var(--button-secondary-text-color);
}
@keyframes rotate {
@keyframes extra-network-control--refresh-keyframe-rotate {
from {
transform: rotate(0deg);
}
@ -1480,7 +1473,7 @@ body.resizing .resize-handle {
.extra-network-tree-content {
padding: var(--spacing-md);
width: 100%;
flex: 1;
}
.extra-network-cards-content {