hd0013's picture
Upload folder using huggingface_hub
8fdc036 verified
raw
history blame contribute delete
No virus
5.04 kB
<script lang="ts">
import { getContext, onMount, tick } from "svelte";
import { click_outside } from "../utils/events";
import { layer_manager, type LayerScene } from "./utils";
import { EDITOR_KEY, type EditorContext } from "../ImageEditor.svelte";
import type { FileData } from "@gradio/client";
import { Layers } from "@gradio/icons";
let show_layers = false;
export let layer_files: (FileData | null)[] | null = [];
export let enable_layers = true;
const { pixi, current_layer, dimensions, register_context } =
getContext<EditorContext>(EDITOR_KEY);
const LayerManager = layer_manager();
let layers: LayerScene[] = [];
register_context("layers", {
init_fn: () => {
new_layer();
},
reset_fn: () => {
LayerManager.reset();
}
});
async function validate_layers(): Promise<void> {
let invalid = layers.some(
(layer) =>
layer.composite.texture?.width != $dimensions[0] ||
layer.composite.texture?.height != $dimensions[1]
);
if (invalid) {
LayerManager.reset();
if (!layer_files || layer_files.length == 0) new_layer();
else render_layer_files(layer_files);
}
}
$: $dimensions, validate_layers();
async function new_layer(): Promise<void> {
if (!$pixi) return;
const [active_layer, all_layers] = LayerManager.add_layer(
$pixi.layer_container,
$pixi.renderer,
...$dimensions
);
$current_layer = active_layer;
layers = all_layers;
}
$: render_layer_files(layer_files);
function is_not_null<T>(x: T | null): x is T {
return x !== null;
}
async function render_layer_files(
_layer_files: typeof layer_files
): Promise<void> {
await tick();
if (!_layer_files || _layer_files.length == 0) {
LayerManager.reset();
new_layer();
return;
}
if (!$pixi) return;
const fetch_promises = await Promise.all(
_layer_files.map((f) => {
if (!f || !f.url) return null;
return fetch(f.url);
})
);
const blobs = await Promise.all(
fetch_promises.map((p) => {
if (!p) return null;
return p.blob();
})
);
LayerManager.reset();
let last_layer: [LayerScene, LayerScene[]] | null = null;
for (const blob of blobs.filter(is_not_null)) {
last_layer = await LayerManager.add_layer_from_blob(
$pixi.layer_container,
$pixi.renderer,
blob,
$pixi.view
);
}
if (!last_layer) return;
$current_layer = last_layer[0];
layers = last_layer[1];
}
onMount(async () => {
await tick();
if (!$pixi) return;
$pixi = { ...$pixi!, get_layers: LayerManager.get_layers };
});
</script>
{#if enable_layers}
<div
class="layer-wrap"
class:closed={!show_layers}
use:click_outside={() => (show_layers = false)}
>
<button
aria-label="Show Layers"
on:click={() => (show_layers = !show_layers)}
><span class="icon"><Layers /></span> Layer {layers.findIndex(
(l) => l === $current_layer
) + 1}
</button>
{#if show_layers}
<ul>
{#each layers as layer, i (i)}
<li>
<button
class:selected_layer={$current_layer === layer}
on:click={() =>
($current_layer = LayerManager.change_active_layer(i))}
>Layer {i + 1}</button
>
</li>
{/each}
<li>
<button aria-label="Add Layer" on:click={new_layer}> +</button>
</li>
</ul>
{/if}
<span class="sep"></span>
</div>
{/if}
<style>
.icon {
width: 14px;
margin-right: var(--spacing-md);
color: var(--block-label-text-color);
margin-right: var(--spacing-lg);
margin-top: 1px;
}
.layer-wrap {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.layer-wrap button {
justify-content: flex-start;
align-items: flex-start;
width: 100%;
border-bottom: 1px solid var(--block-border-color);
display: flex;
align-items: center;
justify-content: center;
font-size: var(--scale-000);
line-height: var(--line-sm);
padding-bottom: 1px;
margin-left: var(--spacing-xl);
padding: var(--spacing-sm) 0;
}
.layer-wrap li:last-child button {
border-bottom: none;
text-align: center;
font-size: var(--scale-0);
line-height: 1;
font-weight: var(--weight-bold);
padding: 5px 0 1px 0;
}
.closed > button {
border-bottom: none;
}
.layer-wrap button:hover {
background-color: none;
}
.layer-wrap button:hover .icon {
color: var(--color-accent);
}
.selected_layer {
background-color: var(--block-background-fill);
color: var(--color-accent);
font-weight: bold;
}
ul {
position: absolute;
bottom: 0;
left: 0;
background: var(--block-background-fill);
width: calc(100% + 1px);
list-style: none;
z-index: var(--layer-top);
border: 1px solid var(--block-border-color);
padding: var(--spacing-sm) 0;
text-wrap: none;
transform: translate(-1px, 1px);
border-radius: var(--radius-sm);
border-bottom-right-radius: 0;
}
.layer-wrap ul > li > button {
margin-left: 0;
}
.sep {
height: 12px;
background-color: var(--block-border-color);
width: 1px;
display: block;
margin-left: var(--spacing-xl);
}
</style>