mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 17:48:11 +08:00
Implement artboards and document version enforcement (#466)
* - graphite document artboard implementation - autosave document load hitch fix - Autosave will delete saved files when graphite document version changes * formating * - top left 0,0 - fixed hitch on first document - vue calls first render * Revert * Merge branch 'master' into artboards * Small bug fixes and code review tweaks Co-authored-by: Oliver Davies <oliver@psyfer.io> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Oliver Davies
Keavon Chambers
parent
8fedfb603e
commit
effc8354d1
@@ -124,6 +124,7 @@
|
||||
</LayoutCol>
|
||||
<LayoutCol :class="'canvas-area'">
|
||||
<div class="canvas" ref="canvas">
|
||||
<svg class="artboards" v-html="artboardSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||
<svg class="artwork" v-html="artworkSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||
<svg class="overlays" v-html="overlaysSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
|
||||
</div>
|
||||
@@ -233,13 +234,12 @@
|
||||
// Fallback values if JS hasn't set these to integers yet
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// Allows dev tools to select the artwork without being blocked by the SVG containers
|
||||
pointer-events: none;
|
||||
|
||||
&.artwork {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
&.overlays {
|
||||
user-select: none;
|
||||
// Prevent inheritance from reaching the child elements
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
import { UpdateArtwork, UpdateOverlays, UpdateScrollbars, UpdateRulers, SetActiveTool, SetCanvasZoom, SetCanvasRotation, ToolName } from "@/dispatcher/js-messages";
|
||||
import { UpdateArtwork, UpdateOverlays, UpdateScrollbars, UpdateRulers, SetActiveTool, SetCanvasZoom, SetCanvasRotation, ToolName, UpdateArtboards } from "@/dispatcher/js-messages";
|
||||
|
||||
import LayoutCol from "@/components/layout/LayoutCol.vue";
|
||||
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
||||
@@ -338,6 +338,10 @@ export default defineComponent({
|
||||
this.overlaysSvg = updateOverlays.svg;
|
||||
});
|
||||
|
||||
this.editor.dispatcher.subscribeJsMessage(UpdateArtboards, (updateArtboards) => {
|
||||
this.artboardSvg = updateArtboards.svg;
|
||||
});
|
||||
|
||||
this.editor.dispatcher.subscribeJsMessage(UpdateScrollbars, (updateScrollbars) => {
|
||||
this.scrollbarPos = updateScrollbars.position;
|
||||
this.scrollbarSize = updateScrollbars.size;
|
||||
@@ -383,6 +387,7 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
artworkSvg: "",
|
||||
artboardSvg: "",
|
||||
overlaysSvg: "",
|
||||
canvasSvgWidth: "100%",
|
||||
canvasSvgHeight: "100%",
|
||||
|
||||
@@ -65,8 +65,16 @@ function makeMenuEntries(editor: EditorState): MenuListEntries {
|
||||
ref: undefined,
|
||||
children: [
|
||||
[
|
||||
{ label: "New", icon: "File", shortcut: ["KeyControl", "KeyN"], shortcutRequiresLock: true, action: async (): Promise<void> => editor.instance.new_document() },
|
||||
{ label: "Open…", shortcut: ["KeyControl", "KeyO"], action: async (): Promise<void> => editor.instance.open_document() },
|
||||
{ label: "New", icon: "File", shortcut: ["KeyControl", "KeyN"], shortcutRequiresLock: true, action: (): void => editor.instance.new_document() },
|
||||
{
|
||||
label: "New 1920x1080",
|
||||
icon: "File",
|
||||
action: (): void => {
|
||||
editor.instance.new_document();
|
||||
editor.instance.create_artboard(0, 0, 1920, 1080);
|
||||
},
|
||||
},
|
||||
{ label: "Open…", shortcut: ["KeyControl", "KeyO"], action: (): void => editor.instance.open_document() },
|
||||
{
|
||||
label: "Open Recent",
|
||||
shortcut: ["KeyControl", "KeyShift", "KeyO"],
|
||||
|
||||
@@ -175,6 +175,10 @@ export class UpdateOverlays extends JsMessage {
|
||||
readonly svg!: string;
|
||||
}
|
||||
|
||||
export class UpdateArtboards extends JsMessage {
|
||||
readonly svg!: string;
|
||||
}
|
||||
|
||||
const TupleToVec2 = Transform(({ value }) => ({ x: value[0], y: value[1] }));
|
||||
|
||||
export class UpdateScrollbars extends JsMessage {
|
||||
@@ -349,6 +353,8 @@ export class AutoSaveDocument extends JsMessage {
|
||||
|
||||
@Type(() => IndexedDbDocumentDetails)
|
||||
details!: IndexedDbDocumentDetails;
|
||||
|
||||
version!: string;
|
||||
}
|
||||
|
||||
export class RemoveAutoSaveDocument extends JsMessage {
|
||||
@@ -386,5 +392,6 @@ export const messageConstructors: Record<string, MessageMaker> = {
|
||||
DisplayAboutGraphiteDialog,
|
||||
AutoSaveDocument,
|
||||
RemoveAutoSaveDocument,
|
||||
UpdateArtboards,
|
||||
} as const;
|
||||
export type JsMessageType = keyof typeof messageConstructors;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { AutoSaveDocument, RemoveAutoSaveDocument } from "@/dispatcher/js-messages";
|
||||
import { DocumentsState } from "@/state/documents";
|
||||
import { EditorState } from "@/state/wasm-loader";
|
||||
import { EditorState, getWasmInstance } from "@/state/wasm-loader";
|
||||
|
||||
const GRAPHITE_INDEXED_DB_VERSION = 2;
|
||||
const GRAPHITE_INDEXED_DB_NAME = "graphite-indexed-db";
|
||||
const GRAPHITE_INDEXED_DB_VERSION = 1;
|
||||
const GRAPHITE_AUTO_SAVE_STORE = "auto-save-documents";
|
||||
const GRAPHITE_AUTO_SAVE_ORDER_KEY = "auto-save-documents-order";
|
||||
|
||||
@@ -12,9 +12,12 @@ const databaseConnection: Promise<IDBDatabase> = new Promise((resolve) => {
|
||||
|
||||
dbOpenRequest.onupgradeneeded = (): void => {
|
||||
const db = dbOpenRequest.result;
|
||||
if (!db.objectStoreNames.contains(GRAPHITE_AUTO_SAVE_STORE)) {
|
||||
db.createObjectStore(GRAPHITE_AUTO_SAVE_STORE, { keyPath: "details.id" });
|
||||
// Wipes out all auto-save data on upgrade
|
||||
if (db.objectStoreNames.contains(GRAPHITE_AUTO_SAVE_STORE)) {
|
||||
db.deleteObjectStore(GRAPHITE_AUTO_SAVE_STORE);
|
||||
}
|
||||
|
||||
db.createObjectStore(GRAPHITE_AUTO_SAVE_STORE, { keyPath: "details.id" });
|
||||
};
|
||||
|
||||
dbOpenRequest.onerror = (): void => {
|
||||
@@ -41,8 +44,13 @@ export function createAutoSaveManager(editor: EditorState, documents: DocumentsS
|
||||
const documentOrder: string[] = JSON.parse(window.localStorage.getItem(GRAPHITE_AUTO_SAVE_ORDER_KEY) || "[]");
|
||||
const orderedSavedDocuments = documentOrder.map((id) => previouslySavedDocuments.find((autoSave) => autoSave.details.id === id)).filter((x) => x !== undefined) as AutoSaveDocument[];
|
||||
|
||||
const currentDocumentVersion = getWasmInstance().graphite_version();
|
||||
orderedSavedDocuments.forEach((doc: AutoSaveDocument) => {
|
||||
editor.instance.open_auto_saved_document(BigInt(doc.details.id), doc.details.name, doc.details.is_saved, doc.document);
|
||||
if (doc.version === currentDocumentVersion) {
|
||||
editor.instance.open_auto_saved_document(BigInt(doc.details.id), doc.details.name, doc.details.is_saved, doc.document);
|
||||
} else {
|
||||
removeDocument(doc.details.id);
|
||||
}
|
||||
});
|
||||
resolve(undefined);
|
||||
};
|
||||
@@ -55,6 +63,13 @@ export function createAutoSaveManager(editor: EditorState, documents: DocumentsS
|
||||
window.localStorage.setItem(GRAPHITE_AUTO_SAVE_ORDER_KEY, JSON.stringify(documentOrder));
|
||||
};
|
||||
|
||||
const removeDocument = async (id: string): Promise<void> => {
|
||||
const db = await databaseConnection;
|
||||
const transaction = db.transaction(GRAPHITE_AUTO_SAVE_STORE, "readwrite");
|
||||
transaction.objectStore(GRAPHITE_AUTO_SAVE_STORE).delete(id);
|
||||
storeDocumentOrder();
|
||||
};
|
||||
|
||||
editor.dispatcher.subscribeJsMessage(AutoSaveDocument, async (autoSaveDocument) => {
|
||||
const db = await databaseConnection;
|
||||
const transaction = db.transaction(GRAPHITE_AUTO_SAVE_STORE, "readwrite");
|
||||
@@ -63,10 +78,7 @@ export function createAutoSaveManager(editor: EditorState, documents: DocumentsS
|
||||
});
|
||||
|
||||
editor.dispatcher.subscribeJsMessage(RemoveAutoSaveDocument, async (removeAutoSaveDocument) => {
|
||||
const db = await databaseConnection;
|
||||
const transaction = db.transaction(GRAPHITE_AUTO_SAVE_STORE, "readwrite");
|
||||
transaction.objectStore(GRAPHITE_AUTO_SAVE_STORE).delete(removeAutoSaveDocument.document_id);
|
||||
storeDocumentOrder();
|
||||
removeDocument(removeAutoSaveDocument.document_id);
|
||||
});
|
||||
|
||||
// On creation
|
||||
|
||||
@@ -57,7 +57,7 @@ function panicProxy<T extends object>(module: T): T {
|
||||
return new Proxy<T>(module, proxyHandler);
|
||||
}
|
||||
|
||||
function getWasmInstance(): WasmInstance {
|
||||
export function getWasmInstance(): WasmInstance {
|
||||
if (wasmImport) return wasmImport;
|
||||
throw new Error("Editor WASM backend was not initialized at application startup");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user