Vue initialization and FloatingMenu codebase refactoring and cleanup (#649)

* Clean up Vue initialization-related code

* Rename folder: dispatcher -> interop

* Rename folder: state -> providers

* Comments and clarification

* Rename JS dispatcher to subscription router

* Assorted cleanup and renaming

* Rename: js-messages.ts -> messages.ts

* Comments

* Remove unused Vue component injects

* Clean up coming soon and add warning about freezing the app

* Further cleanup

* Dangerous changes

* Simplify App.vue code

* Move more disparate init code from components into managers

* Rename folder: providers -> state-providers

* Other

* Move Document panel options bar separator to backend

* Add destructors to managers to fix HMR

* Comments and code style

* Rename variable: font -> font_file_url

* Fix async font loading; refactor janky floating menu openness and min-width measurement; fix Vetur errors

* Fix misaligned canvas in viewport until panning on page (re)load

* Add Vue bidirectional props documentation

* More folder renaming for better terminology; add some documentation
This commit is contained in:
Keavon Chambers
2022-05-21 19:46:15 -07:00
parent 4c3c925c2c
commit fc2d983bd7
73 changed files with 1572 additions and 1462 deletions
+23 -70
View File
@@ -2,7 +2,6 @@
<LayoutCol class="document">
<LayoutRow class="options-bar" :scrollableX="true">
<WidgetLayout :layout="documentModeLayout" />
<Separator :type="'Section'" />
<WidgetLayout :layout="toolOptionsLayout" />
<LayoutRow class="spacer"></LayoutRow>
@@ -37,12 +36,12 @@
<LayoutCol class="canvas-area">
<div
class="canvas"
data-canvas
ref="canvas"
:style="{ cursor: canvasCursor }"
@pointerdown="(e: PointerEvent) => canvasPointerDown(e)"
@dragover="(e) => e.preventDefault()"
@drop="(e) => pasteFile(e)"
ref="canvas"
data-canvas
>
<svg class="artboards" v-html="artboardSvg" :style="{ width: canvasSvgWidth, height: canvasSvgHeight }"></svg>
<svg
@@ -221,6 +220,7 @@
<script lang="ts">
import { defineComponent, nextTick } from "vue";
import { textInputCleanup } from "@/utility-functions/keyboard-entry";
import {
UpdateDocumentArtwork,
UpdateDocumentOverlays,
@@ -235,18 +235,10 @@ import {
UpdateDocumentBarLayout,
UpdateImageData,
TriggerTextCommit,
TriggerTextCopy,
TriggerViewportResize,
DisplayRemoveEditableTextbox,
DisplayEditableTextbox,
TriggerFontLoad,
TriggerFontLoadDefault,
TriggerVisitLink,
} from "@/dispatcher/js-messages";
import { textInputCleanup } from "@/lifetime/input";
import { loadDefaultFont, setLoadDefaultFontCallback } from "@/utilities/fonts";
} from "@/wasm-communication/messages";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue";
@@ -254,11 +246,10 @@ import IconButton from "@/components/widgets/buttons/IconButton.vue";
import SwatchPairInput from "@/components/widgets/inputs/SwatchPairInput.vue";
import CanvasRuler from "@/components/widgets/rulers/CanvasRuler.vue";
import PersistentScrollbar from "@/components/widgets/scrollbars/PersistentScrollbar.vue";
import Separator from "@/components/widgets/separators/Separator.vue";
import WidgetLayout from "@/components/widgets/WidgetLayout.vue";
export default defineComponent({
inject: ["editor", "dialog"],
inject: ["editor"],
methods: {
viewportResize() {
// Resize the canvas
@@ -275,11 +266,10 @@ export default defineComponent({
this.canvasSvgHeight = `${height}px`;
// Resize the rulers
const rulerHorizontal = this.$refs.rulerHorizontal as typeof CanvasRuler;
const rulerVertical = this.$refs.rulerVertical as typeof CanvasRuler;
rulerHorizontal?.handleResize();
rulerVertical?.handleResize();
rulerHorizontal?.resize();
rulerVertical?.resize();
},
pasteFile(e: DragEvent) {
const { dataTransfer } = e;
@@ -329,7 +319,7 @@ export default defineComponent({
},
},
mounted() {
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentArtwork, (UpdateDocumentArtwork) => {
this.artworkSvg = UpdateDocumentArtwork.svg;
nextTick((): void => {
@@ -365,50 +355,38 @@ export default defineComponent({
});
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentOverlays, (updateDocumentOverlays) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentOverlays, (updateDocumentOverlays) => {
this.overlaysSvg = updateDocumentOverlays.svg;
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentArtboards, (updateDocumentArtboards) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentArtboards, (updateDocumentArtboards) => {
this.artboardSvg = updateDocumentArtboards.svg;
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentScrollbars, (updateDocumentScrollbars) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentScrollbars, (updateDocumentScrollbars) => {
this.scrollbarPos = updateDocumentScrollbars.position;
this.scrollbarSize = updateDocumentScrollbars.size;
this.scrollbarMultiplier = updateDocumentScrollbars.multiplier;
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentRulers, (updateDocumentRulers) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentRulers, (updateDocumentRulers) => {
this.rulerOrigin = updateDocumentRulers.origin;
this.rulerSpacing = updateDocumentRulers.spacing;
this.rulerInterval = updateDocumentRulers.interval;
});
this.editor.dispatcher.subscribeJsMessage(UpdateMouseCursor, (updateMouseCursor) => {
this.editor.subscriptions.subscribeJsMessage(UpdateMouseCursor, (updateMouseCursor) => {
this.canvasCursor = updateMouseCursor.cursor;
});
this.editor.dispatcher.subscribeJsMessage(TriggerTextCommit, () => {
this.editor.subscriptions.subscribeJsMessage(TriggerTextCommit, () => {
if (this.textInput) {
const textCleaned = textInputCleanup(this.textInput.innerText);
this.editor.instance.on_change_text(textCleaned);
}
});
this.editor.dispatcher.subscribeJsMessage(TriggerFontLoad, async (triggerFontLoad) => {
const response = await fetch(triggerFontLoad.font);
const responseBuffer = await response.arrayBuffer();
this.editor.instance.on_font_load(triggerFontLoad.font, new Uint8Array(responseBuffer), false);
});
this.editor.dispatcher.subscribeJsMessage(TriggerFontLoadDefault, loadDefaultFont);
this.editor.dispatcher.subscribeJsMessage(TriggerVisitLink, async (triggerOpenLink) => {
window.open(triggerOpenLink.url, "_blank");
});
this.editor.dispatcher.subscribeJsMessage(TriggerTextCopy, (triggerTextCopy) => {
// If the Clipboard API is supported in the browser, copy text to the clipboard
navigator.clipboard?.writeText?.(triggerTextCopy.copy_text);
});
this.editor.dispatcher.subscribeJsMessage(DisplayEditableTextbox, (displayEditableTextbox) => {
this.editor.subscriptions.subscribeJsMessage(DisplayEditableTextbox, (displayEditableTextbox) => {
this.textInput = document.createElement("DIV") as HTMLDivElement;
if (displayEditableTextbox.text === "") this.textInput.textContent = "";
@@ -425,7 +403,7 @@ export default defineComponent({
};
});
this.editor.dispatcher.subscribeJsMessage(DisplayRemoveEditableTextbox, () => {
this.editor.subscriptions.subscribeJsMessage(DisplayRemoveEditableTextbox, () => {
this.textInput = undefined;
window.dispatchEvent(
new CustomEvent("modifyinputfield", {
@@ -434,25 +412,25 @@ export default defineComponent({
);
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentModeLayout, (updateDocumentModeLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentModeLayout, (updateDocumentModeLayout) => {
this.documentModeLayout = updateDocumentModeLayout;
});
this.editor.dispatcher.subscribeJsMessage(UpdateToolOptionsLayout, (updateToolOptionsLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdateToolOptionsLayout, (updateToolOptionsLayout) => {
this.toolOptionsLayout = updateToolOptionsLayout;
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentBarLayout, (updateDocumentBarLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentBarLayout, (updateDocumentBarLayout) => {
this.documentBarLayout = updateDocumentBarLayout;
});
this.editor.dispatcher.subscribeJsMessage(UpdateToolShelfLayout, (updateToolShelfLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdateToolShelfLayout, (updateToolShelfLayout) => {
this.toolShelfLayout = updateToolShelfLayout;
});
this.editor.dispatcher.subscribeJsMessage(TriggerViewportResize, this.viewportResize);
this.editor.subscriptions.subscribeJsMessage(TriggerViewportResize, this.viewportResize);
this.editor.dispatcher.subscribeJsMessage(UpdateImageData, (updateImageData) => {
this.editor.subscriptions.subscribeJsMessage(UpdateImageData, (updateImageData) => {
updateImageData.image_data.forEach(async (element) => {
// Using updateImageData.image_data.buffer returns undefined for some reason?
const blob = new Blob([new Uint8Array(element.image_data.values()).buffer], { type: element.mime });
@@ -464,30 +442,6 @@ export default defineComponent({
this.editor.instance.set_image_blob_url(element.path, url, image.width, image.height);
});
});
// Gets metadata populated in `frontend/vue.config.js`. We could potentially move this functionality in a build.rs file.
const loadBuildMetadata = (): void => {
const release = process.env.VUE_APP_RELEASE_SERIES;
let timestamp = "";
const hash = (process.env.VUE_APP_COMMIT_HASH || "").substring(0, 8);
const branch = process.env.VUE_APP_COMMIT_BRANCH;
{
const date = new Date(process.env.VUE_APP_COMMIT_DATE || "");
const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
const timeString = `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
const timezoneName = Intl.DateTimeFormat(undefined, { timeZoneName: "long" })
.formatToParts(new Date())
.find((part) => part.type === "timeZoneName");
const timezoneNameString = timezoneName?.value;
timestamp = `${dateString} ${timeString} ${timezoneNameString}`;
}
this.editor.instance.populate_build_metadata(release || "", timestamp, hash, branch || "");
};
setLoadDefaultFontCallback((font: string, data: Uint8Array) => this.editor.instance.on_font_load(font, data, true));
loadBuildMetadata();
},
data() {
return {
@@ -525,7 +479,6 @@ export default defineComponent({
LayoutRow,
LayoutCol,
SwatchPairInput,
Separator,
PersistentScrollbar,
CanvasRuler,
IconButton,
+4 -4
View File
@@ -263,7 +263,7 @@
<script lang="ts">
import { defineComponent } from "vue";
import { defaultWidgetLayout, UpdateDocumentLayerTreeStructure, UpdateDocumentLayerDetails, UpdateLayerTreeOptionsLayout, LayerPanelEntry } from "@/dispatcher/js-messages";
import { defaultWidgetLayout, UpdateDocumentLayerTreeStructure, UpdateDocumentLayerDetails, UpdateLayerTreeOptionsLayout, LayerPanelEntry } from "@/wasm-communication/messages";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue";
@@ -471,15 +471,15 @@ export default defineComponent({
},
},
mounted() {
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentLayerTreeStructure, (updateDocumentLayerTreeStructure) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerTreeStructure, (updateDocumentLayerTreeStructure) => {
this.rebuildLayerTree(updateDocumentLayerTreeStructure);
});
this.editor.dispatcher.subscribeJsMessage(UpdateLayerTreeOptionsLayout, (updateLayerTreeOptionsLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdateLayerTreeOptionsLayout, (updateLayerTreeOptionsLayout) => {
this.layerTreeOptionsLayout = updateLayerTreeOptionsLayout;
});
this.editor.dispatcher.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
this.editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
const targetPath = updateDocumentLayerDetails.data.path;
const targetLayer = updateDocumentLayerDetails.data;
+7 -11
View File
@@ -350,7 +350,6 @@ const GRID_COLLAPSE_SPACING = 10;
const GRID_SIZE = 24;
export default defineComponent({
inject: ["editor"],
data() {
return {
transform: { scale: 1, x: 0, y: 0 },
@@ -467,16 +466,13 @@ export default defineComponent({
},
},
mounted() {
{
const outputPort = document.querySelectorAll(".output.port")[4] as HTMLElement;
const inputPort = document.querySelectorAll(".input.port")[1] as HTMLElement;
this.createWirePath(outputPort, inputPort, true, true);
}
{
const outputPort = document.querySelectorAll(".output.port")[6] as HTMLElement;
const inputPort = document.querySelectorAll(".input.port")[3] as HTMLElement;
this.createWirePath(outputPort, inputPort, true, false);
}
const outputPort1 = document.querySelectorAll(".output.port")[4] as HTMLElement;
const inputPort1 = document.querySelectorAll(".input.port")[1] as HTMLElement;
this.createWirePath(outputPort1, inputPort1, true, true);
const outputPort2 = document.querySelectorAll(".output.port")[6] as HTMLElement;
const inputPort2 = document.querySelectorAll(".input.port")[3] as HTMLElement;
this.createWirePath(outputPort2, inputPort2, true, false);
},
components: {
LayoutRow,
@@ -42,7 +42,7 @@
<script lang="ts">
import { defineComponent } from "vue";
import { defaultWidgetLayout, UpdatePropertyPanelOptionsLayout, UpdatePropertyPanelSectionsLayout } from "@/dispatcher/js-messages";
import { defaultWidgetLayout, UpdatePropertyPanelOptionsLayout, UpdatePropertyPanelSectionsLayout } from "@/wasm-communication/messages";
import LayoutCol from "@/components/layout/LayoutCol.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue";
@@ -58,10 +58,11 @@ export default defineComponent({
};
},
mounted() {
this.editor.dispatcher.subscribeJsMessage(UpdatePropertyPanelOptionsLayout, (updatePropertyPanelOptionsLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdatePropertyPanelOptionsLayout, (updatePropertyPanelOptionsLayout) => {
this.propertiesOptionsLayout = updatePropertyPanelOptionsLayout;
});
this.editor.dispatcher.subscribeJsMessage(UpdatePropertyPanelSectionsLayout, (updatePropertyPanelSectionsLayout) => {
this.editor.subscriptions.subscribeJsMessage(UpdatePropertyPanelSectionsLayout, (updatePropertyPanelSectionsLayout) => {
this.propertiesSectionsLayout = updatePropertyPanelSectionsLayout;
});
},