Graphite/frontend/src/state-providers/dialog.ts

99 lines
3.2 KiB
TypeScript

import { writable } from "svelte/store";
import { type Editor } from "@graphite/editor";
import { type IconName } from "@graphite/icons";
import { DisplayDialog, DisplayDialogDismiss, UpdateDialogButtons, UpdateDialogColumn1, UpdateDialogColumn2, patchLayout, TriggerDisplayThirdPartyLicensesDialog } from "@graphite/messages";
import type { Layout } from "@graphite/messages";
export function createDialogState(editor: Editor) {
const { subscribe, update } = writable({
visible: false,
title: "",
icon: "" as IconName,
buttons: [] as Layout,
column1: [] as Layout,
column2: [] as Layout,
// Special case for the crash dialog because we cannot handle button widget callbacks from Rust once the editor has panicked
panicDetails: "",
});
function dismissDialog() {
update((state) => {
// Disallow dismissing the crash dialog since it can confuse users why the app stopped responding if they dismiss it without realizing what it means
if (state.panicDetails === "") state.visible = false;
return state;
});
}
// Creates a crash dialog from JS once the editor has panicked.
// Normal dialogs are created in the Rust backend, but for the crash dialog, the editor has panicked so it cannot respond to widget callbacks.
function createCrashDialog(panicDetails: string) {
update((state) => {
state.visible = true;
state.icon = "Failure";
state.title = "Crash";
state.panicDetails = panicDetails;
state.column1 = [];
state.column2 = [];
state.buttons = [];
return state;
});
}
// Subscribe to process backend events
editor.subscriptions.subscribeJsMessage(DisplayDialog, (data) => {
update((state) => {
state.visible = true;
state.title = data.title;
state.icon = data.icon;
return state;
});
});
editor.subscriptions.subscribeJsMessage(UpdateDialogButtons, (data) => {
update((state) => {
patchLayout(state.buttons, data);
return state;
});
});
editor.subscriptions.subscribeJsMessage(UpdateDialogColumn1, (data) => {
update((state) => {
patchLayout(state.column1, data);
return state;
});
});
editor.subscriptions.subscribeJsMessage(UpdateDialogColumn2, (data) => {
update((state) => {
patchLayout(state.column2, data);
return state;
});
});
editor.subscriptions.subscribeJsMessage(DisplayDialogDismiss, dismissDialog);
editor.subscriptions.subscribeJsMessage(TriggerDisplayThirdPartyLicensesDialog, async () => {
const BACKUP_URL = "https://editor.graphite.art/third-party-licenses.txt";
let licenseText = `Content was not able to load. Please check your network connection and try again.\n\nOr visit ${BACKUP_URL} for the license notices.`;
if (editor.handle.inDevelopmentMode()) licenseText = `Third-party licenses are not available in development builds.\n\nVisit ${BACKUP_URL} for the license notices.`;
const response = await fetch("/third-party-licenses.txt");
if (response.ok && response.headers.get("Content-Type")?.includes("text/plain")) licenseText = await response.text();
editor.handle.requestLicensesThirdPartyDialogWithLicenseText(licenseText);
});
return {
subscribe,
dismissDialog,
createCrashDialog,
};
}
export type DialogState = ReturnType<typeof createDialogState>;