little things

Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
Victor Seiji Hariki 2022-12-02 14:31:49 -03:00
parent 1260537da2
commit ac70691cff
No known key found for this signature in database
GPG key ID: 53D76502731B4A7C
8 changed files with 244 additions and 28 deletions

View file

@ -1,6 +1,12 @@
* {
font-size: 100%;
font-family: Arial, Helvetica, sans-serif;
user-select: none;
}
input,
textarea {
user-select: auto;
}
/* Body is stuck with no scroll */
@ -146,59 +152,83 @@ body {
position: relative;
display: flex;
align-items: center;
align-items: stretch;
justify-content: space-between;
width: 100%;
height: fit-content;
}
.host-field-wrapper input {
flex-shrink: 0;
width: calc(100% - 15px);
display: block;
border: 0;
}
.host-field-wrapper .connection-status {
width: 15px;
height: 15px;
position: absolute;
left: calc(100% - 15px);
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
box-sizing: inherit;
border-radius: 50%;
margin: 5px;
cursor: pointer;
aspect-ratio: 1;
transition-duration: 50ms;
padding-top: 1px;
padding-bottom: 1px;
overflow: hidden;
}
.host-field-wrapper .connection-status:active,
.host-field-wrapper .connection-status:hover {
width: 19px;
height: 19px;
width: fit-content;
padding-left: 5px;
padding-right: 6px;
margin: 3px;
filter: brightness(110%);
}
.host-field-wrapper .connection-status:active {
width: 17px;
height: 17px;
filter: brightness(80%);
}
margin: 4px;
.host-field-wrapper .connection-status > #connection-status-indicator-text {
opacity: 0%;
transition-duration: 20ms;
}
.host-field-wrapper
.connection-status:hover
> #connection-status-indicator-text {
opacity: 100%;
}
.host-field-wrapper .connection-status.online {
background-color: #49dd49;
color: #1f3f1f;
}
.host-field-wrapper .connection-status.offline {
background-color: #dd4949;
color: #3f1f1f;
}
.host-field-wrapper .connection-status.cors-issue {
background-color: #dddd49;
color: #3f3f1f;
}
.host-field-wrapper .connection-status.before {
background-color: #777;
color: #1f1f1f;
}
input#host {
@ -222,6 +252,19 @@ div.prompt-wrapper > textarea:focus {
width: 700px;
}
/* Style Field */
select > .style-select-option {
cursor: pointer;
}
select > .style-select-option:hover {
background-color: #999;
}
select > .style-select-option:active {
background-color: #aaa;
}
/* Tool buttons */
.button-array {
display: flex;

View file

@ -38,14 +38,69 @@
}
.resource-manager > .resource-list > * {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.resource-manager > .resource-list > * > .resource-title {
overflow: hidden;
margin: 5px;
text-overflow: ellipsis;
}
.resource-manager > .resource-list > * > .actions {
display: flex;
align-items: center;
}
.resource-manager .actions > button {
display: flex;
align-items: stretch;
padding: 0;
width: 30px;
aspect-ratio: 1;
background-color: transparent;
border: 0;
cursor: pointer;
}
.resource-manager .actions > button:hover {
background-color: rgba(255, 255, 255, 0.5);
}
.resource-manager .actions > button:active {
background-color: rgba(255, 255, 255, 0.7);
}
.resource-manager .actions > button > *:first-child {
flex: 1;
margin: 3px;
-webkit-mask-size: contain;
mask-size: contain;
background-color: var(--c-primary);
}
.resource-manager .actions > .rename-btn > *:first-child {
-webkit-mask-image: url("/res/icons/edit.svg");
mask-image: url("/res/icons/edit.svg");
}
.resource-manager .actions > .delete-btn > *:first-child {
-webkit-mask-image: url("/res/icons/trash.svg");
mask-image: url("/res/icons/trash.svg");
}
.resource-manager > .resource-list > .selected:hover,
.resource-manager > .resource-list > *:hover {
background-color: #ffff;
background-color: #fff8;
}
.resource-manager > .resource-list > .selected {
background-color: #fff6;

View file

@ -43,8 +43,6 @@
padding: 0;
background-color: var(--c-text);
right: 2px;
top: 10px;
@ -78,6 +76,8 @@
border-radius: 5px;
cursor: pointer;
transition-duration: 50ms;
}
#ui-toolbar .tool.using {
@ -87,3 +87,8 @@
#ui-toolbar .tool:hover {
background-color: var(--c-hover);
}
#ui-toolbar .tool:active {
background-color: var(--c-hover);
filter: brightness(120%);
}

View file

@ -34,9 +34,9 @@
Host
<div class="host-field-wrapper">
<input id="host" value="http://127.0.0.1:7860" />
<div
id="connection-status-indicator"
class="connection-status"></div>
<div id="connection-status-indicator" class="connection-status">
<span id="connection-status-indicator-text">Connected</span>
</div>
</div>
</label>
<!-- Prompts section -->
@ -51,6 +51,12 @@
<div class="prompt-wrapper">
<textarea id="negPrompt"></textarea>
</div>
<label for="styleSelect">Styles:</label>
<select
id="styleSelect"
class="wideSelect"
onchange="changeStyles()"
multiple></select>
<!-- <hr /> -->
</div>
<!-- SD section -->

View file

@ -24,6 +24,7 @@ var stableDiffusionData = {
enable_hr: false,
firstphase_width: 0,
firstphase_height: 0,
styles: [],
// here's some more fields that might be useful
// ---txt2img specific:
@ -170,6 +171,10 @@ async function testHostConnection() {
let firstTimeOnline = true;
const setConnectionStatus = (status) => {
const connectionIndicatorText = document.getElementById(
"connection-status-indicator-text"
);
const statuses = {
online: () => {
connectionIndicator.classList.add("online");
@ -179,7 +184,8 @@ async function testHostConnection() {
"before",
"server-error"
);
connectionIndicator.title = "Connected";
connectionIndicatorText.textContent = connectionIndicator.title =
"Connected";
connectionStatus = true;
},
error: () => {
@ -190,6 +196,7 @@ async function testHostConnection() {
"before",
"cors-issue"
);
connectionIndicatorText.textContent = "Error";
connectionIndicator.title =
"Server is online, but is returning an error response";
connectionStatus = false;
@ -202,6 +209,7 @@ async function testHostConnection() {
"before",
"server-error"
);
connectionIndicatorText.textContent = "CORS";
connectionIndicator.title =
"Server is online, but CORS is blocking our requests";
connectionStatus = false;
@ -214,6 +222,7 @@ async function testHostConnection() {
"before",
"server-error"
);
connectionIndicatorText.textContent = "Offline";
connectionIndicator.title =
"Server seems to be offline. Please check the console for more information.";
connectionStatus = false;
@ -226,6 +235,7 @@ async function testHostConnection() {
"offline",
"server-error"
);
connectionIndicatorText.textContent = "Waiting";
connectionIndicator.title = "Waiting for check to complete.";
connectionStatus = false;
},
@ -256,6 +266,7 @@ async function testHostConnection() {
setConnectionStatus("online");
// Load data as soon as connection is first stablished
if (firstTimeOnline) {
getStyles();
getSamplers();
getUpscalers();
getModels();
@ -274,10 +285,7 @@ async function testHostConnection() {
await fetch(url, {mode: "no-cors"});
setConnectionStatus("corsissue");
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${document.URL.substring(
0,
document.URL.length - 1
)}'`;
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${window.location.protocol}//${window.location.host}/'`;
console.error(message);
if (notify) alert(message);
} catch (e) {
@ -746,6 +754,63 @@ function changeModel() {
});
}
async function getStyles() {
/** @type {HTMLSelectElement} */
var styleSelect = document.getElementById("styleSelect");
var url = document.getElementById("host").value + "/sdapi/v1/prompt-styles";
try {
const response = await fetch(url);
/** @type {{name: string, prompt: string, negative_prompt: string}[]} */
const data = await response.json();
/** @type {string[]} */
let stored = null;
try {
stored = JSON.parse(localStorage.getItem("promptStyle"));
} catch (e) {
stored = [];
}
data.forEach((style) => {
if (style.name === "None") return;
const option = document.createElement("option");
option.classList.add("style-select-option");
option.text = style.name;
option.value = style.name;
option.title = `prompt: ${style.prompt}\nnegative: ${style.negative_prompt}`;
option.selected = !!stored.find((styleName) => style.name === styleName);
styleSelect.add(option);
});
changeStyles();
stored.forEach((styleName, index) => {
if (!data.findIndex((style) => style.name === styleName)) {
stored.splice(index, 1);
}
});
localStorage.setItem("promptStyle", JSON.stringify(stored));
} catch (e) {
console.warn("[index] Failed to fetch prompt styles");
console.warn(e);
}
}
function changeStyles() {
/** @type {HTMLSelectElement} */
const styleSelectEl = document.getElementById("styleSelect");
const selected = Array.from(styleSelectEl.options).filter(
(option) => option.selected
);
const selectedString = selected.map((option) => option.value);
localStorage.setItem("promptStyle", JSON.stringify(selectedString));
// change the model
console.log(`[index] Changing styles to ${selectedString.join(", ")}`);
stableDiffusionData.styles = selectedString;
}
function getSamplers() {
var samplerSelect = document.getElementById("samplerSelect");
var url = document.getElementById("host").value + "/sdapi/v1/samplers";

View file

@ -104,8 +104,11 @@ const stampTool = () =>
);
const resourceWrapper = document.createElement("div");
resourceWrapper.id = `resource-${resource.id}`;
resourceWrapper.textContent = resource.name;
resourceWrapper.classList.add("resource");
const resourceTitle = document.createElement("span");
resourceTitle.textContent = resource.name;
resourceTitle.classList.add("resource-title");
resourceWrapper.appendChild(resourceTitle);
resourceWrapper.addEventListener("click", () =>
state.selectResource(resource)
@ -119,6 +122,34 @@ const stampTool = () =>
state.ctxmenu.previewPane.style.display = "none";
});
// Add action buttons
const actionArray = document.createElement("div");
actionArray.classList.add("actions");
const renameButton = document.createElement("button");
renameButton.addEventListener("click", () => {
const name = prompt("Rename your resource:", resource.name);
if (name) {
resource.name = name;
resourceTitle.textContent = name;
}
});
renameButton.title = "Rename Resource";
renameButton.appendChild(document.createElement("div"));
renameButton.classList.add("rename-btn");
const trashButton = document.createElement("button");
trashButton.addEventListener("click", () => {
state.ctxmenu.previewPane.style.display = "none";
state.deleteResource(resource.id);
});
trashButton.title = "Delete Resource";
trashButton.appendChild(document.createElement("div"));
trashButton.classList.add("delete-btn");
actionArray.appendChild(renameButton);
actionArray.appendChild(trashButton);
resourceWrapper.appendChild(actionArray);
state.ctxmenu.resourceList.appendChild(resourceWrapper);
resource.dom = {wrapper: resourceWrapper};
}

5
res/icons/edit.svg Normal file
View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 344 B

6
res/icons/trash.svg Normal file
View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 6h18"></path>
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path>
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
</svg>

After

Width:  |  Height:  |  Size: 330 B