refined doll editor windowing logic
This commit is contained in:
@@ -1,21 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { page } from "$app/stores";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import DollEditor from "./doll-editor.svelte";
|
||||
import type { DollDto } from "../../../../types/bindings/DollDto";
|
||||
import type { CreateDollDto } from "../../../../types/bindings/CreateDollDto";
|
||||
import type { UpdateDollDto } from "../../../../types/bindings/UpdateDollDto";
|
||||
import DollPreview from "../DollPreview.svelte";
|
||||
|
||||
let mode: "create" | "edit" = "create";
|
||||
let dollId: string | null = null;
|
||||
let loading = true;
|
||||
let error: string | null = null;
|
||||
|
||||
let initialName = "";
|
||||
let initialBodyColor = "#FFFFFF";
|
||||
let initialOutlineColor = "#000000";
|
||||
let name = "";
|
||||
let bodyColor = "#FFFFFF";
|
||||
let outlineColor = "#000000";
|
||||
|
||||
onMount(async () => {
|
||||
// Check URL search params for ID
|
||||
@@ -36,9 +35,9 @@
|
||||
loading = true;
|
||||
try {
|
||||
const doll: DollDto = await invoke("get_doll", { id });
|
||||
initialName = doll.name;
|
||||
initialBodyColor = doll.configuration.colorScheme.body;
|
||||
initialOutlineColor = doll.configuration.colorScheme.outline;
|
||||
name = doll.name;
|
||||
bodyColor = doll.configuration.colorScheme.body;
|
||||
outlineColor = doll.configuration.colorScheme.outline;
|
||||
} catch (e) {
|
||||
error = (e as Error)?.message ?? String(e);
|
||||
console.error("Failed to fetch doll:", e);
|
||||
@@ -47,11 +46,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSave(
|
||||
name: string,
|
||||
bodyColor: string,
|
||||
outlineColor: string,
|
||||
) {
|
||||
async function handleSave() {
|
||||
if (!name.trim()) return;
|
||||
|
||||
try {
|
||||
if (mode === "create") {
|
||||
const dto: CreateDollDto = {
|
||||
@@ -90,7 +87,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-screen h-screen bg-base-100">
|
||||
<div class="w-screen h-screen bg-base-100 flex flex-col">
|
||||
{#if loading}
|
||||
<div class="flex h-full items-center justify-center">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
@@ -103,15 +100,69 @@
|
||||
<button class="btn btn-sm mt-4" on:click={handleCancel}>Close</button>
|
||||
</div>
|
||||
{:else}
|
||||
<DollEditor
|
||||
isOpen={true}
|
||||
standalone={true}
|
||||
{mode}
|
||||
{initialName}
|
||||
{initialBodyColor}
|
||||
{initialOutlineColor}
|
||||
onSave={handleSave}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
<div class="h-full w-full p-4 flex flex-col">
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Name</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Doll Name"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={name}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center mt-4">
|
||||
<DollPreview {bodyColor} {outlineColor} />
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Body Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Outline Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto pt-4 flex justify-end gap-2">
|
||||
<button class="btn" on:click={handleCancel}>Cancel</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
on:click={handleSave}
|
||||
disabled={!name.trim()}
|
||||
>
|
||||
{#if mode === "create"}
|
||||
Create
|
||||
{:else}
|
||||
Save
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,181 +0,0 @@
|
||||
<script lang="ts">
|
||||
import DollPreview from "../DollPreview.svelte";
|
||||
|
||||
export let isOpen: boolean;
|
||||
export let mode: "create" | "edit";
|
||||
export let initialName = "";
|
||||
export let initialBodyColor = "#FFFFFF";
|
||||
export let initialOutlineColor = "#000000";
|
||||
export let onSave: (
|
||||
name: string,
|
||||
bodyColor: string,
|
||||
outlineColor: string,
|
||||
) => void;
|
||||
export let onCancel: () => void;
|
||||
export let standalone = false;
|
||||
|
||||
let name = initialName;
|
||||
let bodyColor = initialBodyColor;
|
||||
let outlineColor = initialOutlineColor;
|
||||
|
||||
$: if (isOpen) {
|
||||
name = initialName;
|
||||
bodyColor = initialBodyColor;
|
||||
outlineColor = initialOutlineColor;
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
if (!name.trim()) return;
|
||||
onSave(name, bodyColor, outlineColor);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if !standalone}
|
||||
{#if isOpen}
|
||||
<div class="modal modal-open">
|
||||
<div class="modal-box">
|
||||
<h3 class="font-bold text-lg">
|
||||
{#if mode === "create"}
|
||||
Create New Doll
|
||||
{:else}
|
||||
Edit Doll
|
||||
{/if}
|
||||
</h3>
|
||||
<div class="form-control w-full mt-4">
|
||||
<label class="label">
|
||||
<span class="label-text">Name</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Doll Name"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={name}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center mt-4">
|
||||
<DollPreview {bodyColor} {outlineColor} />
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Body Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Outline Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-action">
|
||||
<button class="btn" on:click={onCancel}>Cancel</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
on:click={handleSave}
|
||||
disabled={!name.trim()}
|
||||
>
|
||||
{#if mode === "create"}
|
||||
Create
|
||||
{:else}
|
||||
Save
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="h-full w-full bg-base-100 p-4 flex flex-col">
|
||||
<h3 class="font-bold text-lg">
|
||||
{#if mode === "create"}
|
||||
Create New Doll
|
||||
{:else}
|
||||
Edit Doll
|
||||
{/if}
|
||||
</h3>
|
||||
<div class="form-control w-full mt-4">
|
||||
<label class="label">
|
||||
<span class="label-text">Name</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Doll Name"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={name}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center mt-4">
|
||||
<DollPreview {bodyColor} {outlineColor} />
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Body Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={bodyColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control w-full mt-2">
|
||||
<label class="label">
|
||||
<span class="label-text">Outline Color</span>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="color"
|
||||
class="input input-bordered w-12 p-1 h-10"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
bind:value={outlineColor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto pt-4 flex justify-end gap-2">
|
||||
<button class="btn" on:click={onCancel}>Cancel</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
on:click={handleSave}
|
||||
disabled={!name.trim()}
|
||||
>
|
||||
{#if mode === "create"}
|
||||
Create
|
||||
{:else}
|
||||
Save
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -15,46 +15,56 @@
|
||||
// We still keep the focus listener as a fallback, but the websocket events should handle most updates
|
||||
onMount(() => {
|
||||
refreshDolls();
|
||||
|
||||
|
||||
// Set up listeners
|
||||
const unlistenCreated = listen("doll.created", (event) => {
|
||||
console.log("Received doll.created event", event);
|
||||
refreshDolls();
|
||||
const unlistenCreated = listen("doll_created", (event) => {
|
||||
console.log("Received doll_created event", event);
|
||||
refreshDolls();
|
||||
});
|
||||
|
||||
const unlistenUpdated = listen("doll.updated", (event) => {
|
||||
console.log("Received doll.updated event", event);
|
||||
refreshDolls();
|
||||
const unlistenUpdated = listen("doll_updated", (event) => {
|
||||
console.log("Received doll_updated event", event);
|
||||
refreshDolls();
|
||||
});
|
||||
|
||||
const unlistenDeleted = listen("doll.deleted", (event) => {
|
||||
console.log("Received doll.deleted event", event);
|
||||
refreshDolls();
|
||||
const unlistenDeleted = listen("doll_deleted", (event) => {
|
||||
console.log("Received doll_deleted event", event);
|
||||
refreshDolls();
|
||||
});
|
||||
|
||||
// Listen for focus events to refresh data when returning from editor window
|
||||
window.addEventListener("focus", refreshDolls);
|
||||
|
||||
return async () => {
|
||||
window.removeEventListener("focus", refreshDolls);
|
||||
(await unlistenCreated)();
|
||||
(await unlistenUpdated)();
|
||||
(await unlistenDeleted)();
|
||||
};
|
||||
});
|
||||
|
||||
let isRefreshing = false;
|
||||
let refreshQueued = false;
|
||||
|
||||
async function refreshDolls() {
|
||||
if (isRefreshing) {
|
||||
refreshQueued = true;
|
||||
return;
|
||||
}
|
||||
|
||||
isRefreshing = true;
|
||||
loading = true;
|
||||
|
||||
try {
|
||||
dolls = await invoke("get_dolls");
|
||||
// Use refresh_app_data to ensure we get the latest user state (including activeDollId)
|
||||
// from the server, as the local state might be stale after updates.
|
||||
const appData: AppData = await invoke("refresh_app_data");
|
||||
user = appData.user;
|
||||
} catch (e) {
|
||||
error = (e as Error)?.message ?? String(e);
|
||||
do {
|
||||
refreshQueued = false;
|
||||
try {
|
||||
dolls = await invoke("get_dolls");
|
||||
const appData: AppData = await invoke("refresh_app_data");
|
||||
user = appData.user;
|
||||
} catch (e) {
|
||||
error = (e as Error)?.message ?? String(e);
|
||||
}
|
||||
} while (refreshQueued);
|
||||
} finally {
|
||||
loading = false;
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user