LocalStorage used bar

This commit is contained in:
space-nuko
2023-05-25 18:12:26 -05:00
parent 220be38a0b
commit 8cc2af6f80
5 changed files with 119 additions and 34 deletions

View File

@@ -85,10 +85,8 @@ export default class DanbooruTags {
} }
async load(force: boolean = false) { async load(force: boolean = false) {
console.log("Parsing danbooru tags CSV...")
if (this.tags.length > 0 && !force) { if (this.tags.length > 0 && !force) {
console.info("Danbooru tags already parsed") console.warn("Danbooru tags already parsed")
return; return;
} }

View File

@@ -297,7 +297,9 @@ export default class ComfyApp {
if (templateAndSvg == null) { if (templateAndSvg == null) {
errors.push("Invalid SVG template format") errors.push("Invalid SVG template format")
} }
templates.push(templateAndSvg) else {
templates.push(templateAndSvg)
}
} }
} }

View File

@@ -1,9 +1,9 @@
<script lang="ts"> <script lang="ts">
import { embedTemplateInSvg, type SerializedComfyBoxTemplate } from "$lib/ComfyBoxTemplate"; import { embedTemplateInSvg, type SerializedComfyBoxTemplate } from "$lib/ComfyBoxTemplate";
import templateState, { type TemplateState, type WritableTemplateStateStore } from "$lib/stores/templateState"; import templateState, { type TemplateState, type WritableTemplateStateStore } from "$lib/stores/templateState";
import { BoxSeam } from "svelte-bootstrap-icons"; import { BoxSeam, Hdd } from "svelte-bootstrap-icons";
import uiState from "$lib/stores/uiState"; import uiState from "$lib/stores/uiState";
import { download, truncateString } from "$lib/utils"; import { download, getLocalStorageUsedMB, MAX_LOCAL_STORAGE_MB, truncateString } from "$lib/utils";
import type ComfyApp from "./ComfyApp"; import type ComfyApp from "./ComfyApp";
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
import {fade} from 'svelte/transition'; import {fade} from 'svelte/transition';
@@ -27,6 +27,20 @@
source?: string source?: string
} }
let storageUsedPercent = 0;
let storageUsedMB = 0;
$: {
if ($templateState) {
storageUsedMB = getLocalStorageUsedMB()
storageUsedPercent = (storageUsedMB / MAX_LOCAL_STORAGE_MB) * 100;
}
else {
storageUsedPercent = 0;
storageUsedMB = 0;
}
}
let _sorted: TemplateLayout[] = [] let _sorted: TemplateLayout[] = []
$: $templateState && rebuildTemplates(templateState.getAllTemplates()); $: $templateState && rebuildTemplates(templateState.getAllTemplates());
@@ -149,8 +163,7 @@
{ {
name: "Close", name: "Close",
variant: "secondary", variant: "secondary",
onClick: () => { onClick: () => {}
}
}, },
] ]
}) })
@@ -161,30 +174,42 @@
<div class="template-entries"> <div class="template-entries">
{#if _sorted.length > 0} {#if _sorted.length > 0}
{@const draggable = $uiState.uiUnlocked} {@const draggable = $uiState.uiUnlocked}
<div class="template-category-group"> <div class="template-list">
<div class="template-category-header"> <div class="template-category-group">
General <div class="template-category-header">
General
</div>
<div class="template-entries-wrapper"
use:dndzone={{
type: "layout",
items: _sorted,
flipDurationMs,
dragDisabled: !draggable,
dropFromOthersDisabled: true
}}
on:consider={handleDndConsider}
on:finalize={handleDndFinalize}>
{#each _sorted.filter(i => i.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="template-entry" class:built-in={item.template.isBuiltIn} class:draggable on:click={() => handleClick(item)}>
<div class="template-name">{item.template.metadata.title}</div>
<div class="template-desc">{item.template.metadata.description}</div>
</div>
{#if item[SHADOW_ITEM_MARKER_PROPERTY_NAME]}
<div in:fade={{duration:200, easing: cubicIn}} class='template-drag-item-shadow'/>
{/if}
{/each}
</div>
</div> </div>
<div class="template-entries-wrapper" </div>
use:dndzone={{ <div class="storage-used">
type: "layout", <div class="storage-used-icon">
items: _sorted, <Hdd width="100%" height="2rem" />
flipDurationMs, </div>
dragDisabled: !draggable, <div class="storage-used-bar-wrapper">
dropFromOthersDisabled: true <div class="storage-used-bar" style="width: {storageUsedPercent}%;">
}} <span class="storage-used-label">{storageUsedMB.toFixed(2)} / {MAX_LOCAL_STORAGE_MB} MB</span>
on:consider={handleDndConsider} </div>
on:finalize={handleDndFinalize}>
{#each _sorted.filter(i => i.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="template-entry" class:built-in={item.template.isBuiltIn} class:draggable on:click={() => handleClick(item)}>
<div class="template-name">{item.template.metadata.title}</div>
<div class="template-desc">{item.template.metadata.description}</div>
</div>
{#if item[SHADOW_ITEM_MARKER_PROPERTY_NAME]}
<div in:fade={{duration:200, easing: cubicIn}} class='template-drag-item-shadow'/>
{/if}
{/each}
</div> </div>
</div> </div>
{:else} {:else}
@@ -207,9 +232,13 @@
.template-entries { .template-entries {
height: 100%; height: 100%;
overflow-y: auto;
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
margin: auto;
}
.template-list {
overflow-y: auto;
} }
.template-category-header { .template-category-header {
@@ -234,6 +263,16 @@
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
&.built-in {
background: repeating-linear-gradient(
45deg,
var(--neutral-900),
var(--neutral-900) 5px,
var(--neutral-800) 5px,
var(--neutral-800) 10px
);
}
font-size: 13pt; font-size: 13pt;
.template-desc { .template-desc {
opacity: 65%; opacity: 65%;
@@ -288,4 +327,45 @@
opacity: 0.5; opacity: 0.5;
margin: 0; margin: 0;
} }
.storage-used {
height: 2.5rem;
margin: 5px;
text-align: center;
position: relative;
padding: 0.1rem 0.5rem;
display: flex;
flex-direction: row;
gap: var(--spacing-lg);
.storage-used-icon {
color: var(--neutral-500);
margin: auto;
}
.storage-used-bar-wrapper {
width: 100%;
background: var(--panel-background-fill);
border: 1px solid var(--neutral-700);
position: relative;
.storage-used-bar {
height: 100%;
background: var(--neutral-700);
.storage-used-label {
width: 100%;
color: var(--neutral-200);
font-size: 12pt;
position: absolute;
margin: 0;
left: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
}
</style> </style>

View File

@@ -101,9 +101,12 @@
<BlockTitle>Metadata</BlockTitle> <BlockTitle>Metadata</BlockTitle>
<div> <div>
<Textbox label="Name" disabled={!editable} bind:value={$state.name} lines={1} max_lines={1} /> <Textbox label="Name" disabled={!editable} bind:value={$state.name} lines={1} max_lines={1} />
<Textbox label="Created At" disabled={true} bind:value={createdAt} lines={1} max_lines={1} />
<Textbox label="Author" disabled={!editable} bind:value={$state.author} lines={1} max_lines={1} /> <Textbox label="Author" disabled={!editable} bind:value={$state.author} lines={1} max_lines={1} />
<Textbox label="Description" disabled={!editable} bind:value={$state.description} lines={5} max_lines={5} /> <Textbox label="Description" disabled={!editable} bind:value={$state.description} lines={5} max_lines={5} />
<Row>
<Textbox label="Created At" disabled={true} bind:value={createdAt} lines={1} max_lines={1} />
<Textbox label="Size" disabled={true} value="{(templateAndSvg.svg.length/1024).toFixed(2)} KB" lines={1} max_lines={1} />
</Row>
</div> </div>
</Block> </Block>
</div> </div>

View File

@@ -75,7 +75,9 @@ export function download(filename: string, text: string, type: string = "text/pl
}, 0); }, 0);
} }
export function getLocalStorageUsed(): number { export const MAX_LOCAL_STORAGE_MB = 5;
export function getLocalStorageUsedMB(): number {
var total = 0; var total = 0;
for (const x in localStorage) { for (const x in localStorage) {
// Value is multiplied by 2 due to data being stored in `utf-16` format, which requires twice the space. // Value is multiplied by 2 due to data being stored in `utf-16` format, which requires twice the space.