little things
Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
parent
1260537da2
commit
ac70691cff
8 changed files with 244 additions and 28 deletions
|
@ -1,6 +1,12 @@
|
||||||
* {
|
* {
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
user-select: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Body is stuck with no scroll */
|
/* Body is stuck with no scroll */
|
||||||
|
@ -146,59 +152,83 @@ body {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: fit-content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper input {
|
.host-field-wrapper input {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: calc(100% - 15px);
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper .connection-status {
|
.host-field-wrapper .connection-status {
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
|
||||||
|
position: absolute;
|
||||||
|
left: calc(100% - 15px);
|
||||||
|
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
|
|
||||||
box-sizing: inherit;
|
box-sizing: inherit;
|
||||||
|
|
||||||
border-radius: 50%;
|
|
||||||
margin: 5px;
|
|
||||||
|
|
||||||
cursor: pointer;
|
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 {
|
.host-field-wrapper .connection-status:hover {
|
||||||
width: 19px;
|
width: fit-content;
|
||||||
height: 19px;
|
padding-left: 5px;
|
||||||
|
padding-right: 6px;
|
||||||
|
|
||||||
margin: 3px;
|
filter: brightness(110%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper .connection-status:active {
|
.host-field-wrapper .connection-status:active {
|
||||||
width: 17px;
|
filter: brightness(80%);
|
||||||
height: 17px;
|
}
|
||||||
|
|
||||||
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 {
|
.host-field-wrapper .connection-status.online {
|
||||||
background-color: #49dd49;
|
background-color: #49dd49;
|
||||||
|
color: #1f3f1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper .connection-status.offline {
|
.host-field-wrapper .connection-status.offline {
|
||||||
background-color: #dd4949;
|
background-color: #dd4949;
|
||||||
|
color: #3f1f1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper .connection-status.cors-issue {
|
.host-field-wrapper .connection-status.cors-issue {
|
||||||
background-color: #dddd49;
|
background-color: #dddd49;
|
||||||
|
color: #3f3f1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.host-field-wrapper .connection-status.before {
|
.host-field-wrapper .connection-status.before {
|
||||||
background-color: #777;
|
background-color: #777;
|
||||||
|
color: #1f1f1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
input#host {
|
input#host {
|
||||||
|
@ -222,6 +252,19 @@ div.prompt-wrapper > textarea:focus {
|
||||||
width: 700px;
|
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 */
|
/* Tool buttons */
|
||||||
.button-array {
|
.button-array {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -38,14 +38,69 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-manager > .resource-list > * {
|
.resource-manager > .resource-list > * {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
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 {
|
.resource-manager > .resource-list > *:hover {
|
||||||
background-color: #ffff;
|
background-color: #fff8;
|
||||||
}
|
}
|
||||||
.resource-manager > .resource-list > .selected {
|
.resource-manager > .resource-list > .selected {
|
||||||
background-color: #fff6;
|
background-color: #fff6;
|
||||||
|
|
|
@ -43,8 +43,6 @@
|
||||||
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
background-color: var(--c-text);
|
|
||||||
|
|
||||||
right: 2px;
|
right: 2px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
|
||||||
|
@ -78,6 +76,8 @@
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
transition-duration: 50ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ui-toolbar .tool.using {
|
#ui-toolbar .tool.using {
|
||||||
|
@ -87,3 +87,8 @@
|
||||||
#ui-toolbar .tool:hover {
|
#ui-toolbar .tool:hover {
|
||||||
background-color: var(--c-hover);
|
background-color: var(--c-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ui-toolbar .tool:active {
|
||||||
|
background-color: var(--c-hover);
|
||||||
|
filter: brightness(120%);
|
||||||
|
}
|
||||||
|
|
12
index.html
12
index.html
|
@ -34,9 +34,9 @@
|
||||||
Host
|
Host
|
||||||
<div class="host-field-wrapper">
|
<div class="host-field-wrapper">
|
||||||
<input id="host" value="http://127.0.0.1:7860" />
|
<input id="host" value="http://127.0.0.1:7860" />
|
||||||
<div
|
<div id="connection-status-indicator" class="connection-status">
|
||||||
id="connection-status-indicator"
|
<span id="connection-status-indicator-text">Connected</span>
|
||||||
class="connection-status"></div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<!-- Prompts section -->
|
<!-- Prompts section -->
|
||||||
|
@ -51,6 +51,12 @@
|
||||||
<div class="prompt-wrapper">
|
<div class="prompt-wrapper">
|
||||||
<textarea id="negPrompt"></textarea>
|
<textarea id="negPrompt"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<label for="styleSelect">Styles:</label>
|
||||||
|
<select
|
||||||
|
id="styleSelect"
|
||||||
|
class="wideSelect"
|
||||||
|
onchange="changeStyles()"
|
||||||
|
multiple></select>
|
||||||
<!-- <hr /> -->
|
<!-- <hr /> -->
|
||||||
</div>
|
</div>
|
||||||
<!-- SD section -->
|
<!-- SD section -->
|
||||||
|
|
75
js/index.js
75
js/index.js
|
@ -24,6 +24,7 @@ var stableDiffusionData = {
|
||||||
enable_hr: false,
|
enable_hr: false,
|
||||||
firstphase_width: 0,
|
firstphase_width: 0,
|
||||||
firstphase_height: 0,
|
firstphase_height: 0,
|
||||||
|
styles: [],
|
||||||
// here's some more fields that might be useful
|
// here's some more fields that might be useful
|
||||||
|
|
||||||
// ---txt2img specific:
|
// ---txt2img specific:
|
||||||
|
@ -170,6 +171,10 @@ async function testHostConnection() {
|
||||||
let firstTimeOnline = true;
|
let firstTimeOnline = true;
|
||||||
|
|
||||||
const setConnectionStatus = (status) => {
|
const setConnectionStatus = (status) => {
|
||||||
|
const connectionIndicatorText = document.getElementById(
|
||||||
|
"connection-status-indicator-text"
|
||||||
|
);
|
||||||
|
|
||||||
const statuses = {
|
const statuses = {
|
||||||
online: () => {
|
online: () => {
|
||||||
connectionIndicator.classList.add("online");
|
connectionIndicator.classList.add("online");
|
||||||
|
@ -179,7 +184,8 @@ async function testHostConnection() {
|
||||||
"before",
|
"before",
|
||||||
"server-error"
|
"server-error"
|
||||||
);
|
);
|
||||||
connectionIndicator.title = "Connected";
|
connectionIndicatorText.textContent = connectionIndicator.title =
|
||||||
|
"Connected";
|
||||||
connectionStatus = true;
|
connectionStatus = true;
|
||||||
},
|
},
|
||||||
error: () => {
|
error: () => {
|
||||||
|
@ -190,6 +196,7 @@ async function testHostConnection() {
|
||||||
"before",
|
"before",
|
||||||
"cors-issue"
|
"cors-issue"
|
||||||
);
|
);
|
||||||
|
connectionIndicatorText.textContent = "Error";
|
||||||
connectionIndicator.title =
|
connectionIndicator.title =
|
||||||
"Server is online, but is returning an error response";
|
"Server is online, but is returning an error response";
|
||||||
connectionStatus = false;
|
connectionStatus = false;
|
||||||
|
@ -202,6 +209,7 @@ async function testHostConnection() {
|
||||||
"before",
|
"before",
|
||||||
"server-error"
|
"server-error"
|
||||||
);
|
);
|
||||||
|
connectionIndicatorText.textContent = "CORS";
|
||||||
connectionIndicator.title =
|
connectionIndicator.title =
|
||||||
"Server is online, but CORS is blocking our requests";
|
"Server is online, but CORS is blocking our requests";
|
||||||
connectionStatus = false;
|
connectionStatus = false;
|
||||||
|
@ -214,6 +222,7 @@ async function testHostConnection() {
|
||||||
"before",
|
"before",
|
||||||
"server-error"
|
"server-error"
|
||||||
);
|
);
|
||||||
|
connectionIndicatorText.textContent = "Offline";
|
||||||
connectionIndicator.title =
|
connectionIndicator.title =
|
||||||
"Server seems to be offline. Please check the console for more information.";
|
"Server seems to be offline. Please check the console for more information.";
|
||||||
connectionStatus = false;
|
connectionStatus = false;
|
||||||
|
@ -226,6 +235,7 @@ async function testHostConnection() {
|
||||||
"offline",
|
"offline",
|
||||||
"server-error"
|
"server-error"
|
||||||
);
|
);
|
||||||
|
connectionIndicatorText.textContent = "Waiting";
|
||||||
connectionIndicator.title = "Waiting for check to complete.";
|
connectionIndicator.title = "Waiting for check to complete.";
|
||||||
connectionStatus = false;
|
connectionStatus = false;
|
||||||
},
|
},
|
||||||
|
@ -256,6 +266,7 @@ async function testHostConnection() {
|
||||||
setConnectionStatus("online");
|
setConnectionStatus("online");
|
||||||
// Load data as soon as connection is first stablished
|
// Load data as soon as connection is first stablished
|
||||||
if (firstTimeOnline) {
|
if (firstTimeOnline) {
|
||||||
|
getStyles();
|
||||||
getSamplers();
|
getSamplers();
|
||||||
getUpscalers();
|
getUpscalers();
|
||||||
getModels();
|
getModels();
|
||||||
|
@ -274,10 +285,7 @@ async function testHostConnection() {
|
||||||
await fetch(url, {mode: "no-cors"});
|
await fetch(url, {mode: "no-cors"});
|
||||||
|
|
||||||
setConnectionStatus("corsissue");
|
setConnectionStatus("corsissue");
|
||||||
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${document.URL.substring(
|
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${window.location.protocol}//${window.location.host}/'`;
|
||||||
0,
|
|
||||||
document.URL.length - 1
|
|
||||||
)}'`;
|
|
||||||
console.error(message);
|
console.error(message);
|
||||||
if (notify) alert(message);
|
if (notify) alert(message);
|
||||||
} catch (e) {
|
} 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() {
|
function getSamplers() {
|
||||||
var samplerSelect = document.getElementById("samplerSelect");
|
var samplerSelect = document.getElementById("samplerSelect");
|
||||||
var url = document.getElementById("host").value + "/sdapi/v1/samplers";
|
var url = document.getElementById("host").value + "/sdapi/v1/samplers";
|
||||||
|
|
|
@ -104,8 +104,11 @@ const stampTool = () =>
|
||||||
);
|
);
|
||||||
const resourceWrapper = document.createElement("div");
|
const resourceWrapper = document.createElement("div");
|
||||||
resourceWrapper.id = `resource-${resource.id}`;
|
resourceWrapper.id = `resource-${resource.id}`;
|
||||||
resourceWrapper.textContent = resource.name;
|
|
||||||
resourceWrapper.classList.add("resource");
|
resourceWrapper.classList.add("resource");
|
||||||
|
const resourceTitle = document.createElement("span");
|
||||||
|
resourceTitle.textContent = resource.name;
|
||||||
|
resourceTitle.classList.add("resource-title");
|
||||||
|
resourceWrapper.appendChild(resourceTitle);
|
||||||
|
|
||||||
resourceWrapper.addEventListener("click", () =>
|
resourceWrapper.addEventListener("click", () =>
|
||||||
state.selectResource(resource)
|
state.selectResource(resource)
|
||||||
|
@ -119,6 +122,34 @@ const stampTool = () =>
|
||||||
state.ctxmenu.previewPane.style.display = "none";
|
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);
|
state.ctxmenu.resourceList.appendChild(resourceWrapper);
|
||||||
resource.dom = {wrapper: resourceWrapper};
|
resource.dom = {wrapper: resourceWrapper};
|
||||||
}
|
}
|
||||||
|
|
5
res/icons/edit.svg
Normal file
5
res/icons/edit.svg
Normal 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
6
res/icons/trash.svg
Normal 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 |
Loading…
Reference in a new issue