asciibird/src/Dashboard.vue

1417 řádky
41 KiB
Vue

<template>
<div id="app" @contextmenu.prevent>
<div v-show="menuBarVisible">
<vue-file-toolbar-menu
:content="myMenu"
v-if="!(isModalOpen || isKeyboardDisabled)"
/>
</div>
<NewAscii v-if="modalState.newAscii" />
<Options v-if="asciibirdMeta.length && modalState.options" />
<About v-if="modalState.about" />
<EditAscii v-if="asciibirdMeta.length && modalState.editAscii" @updateAscii="updateAsciiDetails" />
<PasteAscii v-if="modalState.pasteAscii" />
<ImageOverlay v-if="asciibirdMeta.length && modalState.overlay" />
<KeyboardShortcuts
:selected-blocks="selectedBlocks"
:selecting="selecting"
@updatecanvas="updatecanvas"
:is-inputting-brush-size="this.isInputtingBrushSize"
:canvas-x="canvasX"
:canvas-y="canvasY"
/>
<context-menu ref="menu" class="z-50">
<ul>
<li
@click="$store.commit('openModal', 'new-ascii')"
class="ab-context-menu-item"
>
New ASCII
</li>
<li
@click="$store.commit('openModal', 'edit-ascii')"
class="ab-context-menu-item"
v-if="asciibirdMeta.length"
>
Edit Ascii
</li>
<li
@click="closeTab(currentTab)"
class="ab-context-menu-item border-b"
v-if="asciibirdMeta.length"
>
Close Ascii
</li>
<li
@click="$store.commit('openModal', 'options')"
class="ab-context-menu-item border-b"
v-if="asciibirdMeta.length"
>
Options
</li>
<li @click="startImport('mirc')" class="ab-context-menu-item">
Import mIRC from File
</li>
<li
@click="startExport('file')"
class="ab-context-menu-item border-b"
v-if="asciibirdMeta.length"
>
Export mIRC to File
</li>
<li
class="ab-context-menu-item"
@click="$store.commit('openModal', 'paste-ascii')"
>
Import mIRC from Clipboard
</li>
<li
class="ab-context-menu-item"
@click="startExport('clipboard')"
v-if="asciibirdMeta.length"
>
Export mIRC to Clipboard
</li>
<li
class="ab-context-menu-item border-b"
@click="startExport('post')"
v-if="asciibirdMeta.length"
>
Export mIRC to HTTP POST
</li>
<li
@click="exportAsciibirdState()"
class="ab-context-menu-item"
v-if="asciibirdMeta.length"
>
Save Asciibird State
</li>
<li @click="startImport('asb')" class="ab-context-menu-item">
Load Asciibird State
</li>
</ul>
</context-menu>
<span
@mouseup.right="openContextMenu"
style="width: 100%; height: 100%; position: absolute; z-index: -1"
/>
<input
type="file"
style="display: none"
ref="asciiInput"
@change="onImport()"
/>
<template v-if="asciibirdMeta.length">
<div
class="bg-gray-500 relative z-auto"
ref="tabbar"
:style="toolbarString"
v-if="tabsVisible"
>
<span
v-for="(value, key) in asciibirdMeta"
:key="key"
class="mr-2 z-40"
>
<t-button
class="p-1 z-40"
:class="buttonStyle(key)"
@click="changeTab(key, value)"
>
<span>
<span class="material-icons relative">insert_drive_file</span>
<span class="bottom-1 relative pl-1 pr-1">{{ value.title }}</span>
<t-button
class="relative bottom-1 z-40 rounded-3xl h-5"
@click="closeTab(key)"
><span class="material-icons" style="font-size: 16px"
>close</span
></t-button
>
</span>
</t-button>
</span>
</div>
<Editor
@coordsupdate="updateCoords"
@selectedblocks="selectedblocks"
@textediting="textediting"
:update-canvas="updateCanvas"
@selecting="updateSelecting"
:y-offset="scrollOffset"
:updateascii="updateAscii"
:reset-select="resetSelect"
/>
<Toolbar v-show="toolbarState.visible" :y-offset="scrollOffset" />
<DebugPanel
:canvas-x="canvasX"
:canvas-y="canvasY"
v-if="debugPanelState.visible"
:y-offset="scrollOffset"
/>
<BrushLibrary
v-show="brushLibraryState.visible"
:y-offset="scrollOffset"
/>
<BrushPreview
@inputtingbrush="inputtingbrush"
:y-offset="scrollOffset"
v-show="brushPreviewState.visible"
/>
<LayersLibrary
v-show="layersLibraryState.visible"
:y-offset="scrollOffset"
/>
<CharPicker
v-if="toolbarState.isChoosingChar"
class="z-50"
:y-offset="scrollOffset"
/>
<ColourPicker
v-if="toolbarState.isChoosingFg || toolbarState.isChoosingBg"
class="z-50"
:y-offset="scrollOffset"
/>
</template>
<template v-else>
<div
class="absolute left-1/2 transform -translate-x-1/2 text-center"
@mouseup.right="openContextMenu"
>
<BrushCanvas :blocks="this.splashAscii()" />
</div>
</template>
</div>
</template>
<script>
// top-1/2
// -translate-y-1/2
// these css classes can put back to center smaller asciis
import LZString from "lz-string";
import Toolbar from "./components/Toolbar.vue";
import DebugPanel from "./components/DebugPanel.vue";
import BrushLibrary from "./components/BrushLibrary.vue";
import LayersLibrary from "./components/LayersLibrary.vue";
import Editor from "./views/Editor.vue";
import CharPicker from "./components/parts/CharPicker.vue";
import ColourPicker from "./components/parts/ColourPicker.vue";
import ContextMenu from "./components/parts/ContextMenu.vue";
import NewAscii from "./components/modals/NewAscii.vue";
import Options from "./components/modals/Options.vue";
import ImageOverlay from "./components/modals/ImageOverlay.vue";
import EditAscii from "./components/modals/EditAscii.vue";
import PasteAscii from "./components/modals/PasteAscii.vue";
import About from "./components/modals/About.vue";
import BrushCanvas from "./components/parts/BrushCanvas.vue";
import BrushPreview from "./components/parts/BrushPreview.vue";
import KeyboardShortcuts from "./components/parts/KeyboardShortcuts.vue";
import {
parseMircAscii,
toolbarIcons,
exportMirc,
downloadFile,
checkForGetRequest,
splashAscii,
filterNullBlocks,
getBlocksWidth,
emptyBlock,
canvasToPng,
maxBrushSize,
} from "./ascii";
import VueFileToolbarMenu from "vue-file-toolbar-menu";
export default {
async created() {
// Load from irc watch if present in the URL bar
checkForGetRequest();
var isThis = this;
window.addEventListener("scroll", function (event) {
isThis.scrollOffset = this.scrollY;
});
this.mirror.x = this.toolbarState.mirrorX;
this.mirror.y = this.toolbarState.mirrorY;
},
destroyed() {
window.removeEventListener("scroll", function (event) {
isThis.scrollOffset = this.scrollY;
});
},
components: {
Toolbar,
DebugPanel,
Editor,
CharPicker,
ColourPicker,
ContextMenu,
NewAscii,
EditAscii,
PasteAscii,
BrushLibrary,
BrushCanvas,
BrushPreview,
KeyboardShortcuts,
LayersLibrary,
Options,
ImageOverlay,
VueFileToolbarMenu,
About,
},
name: "Dashboard",
data: () => ({
canvasX: null,
canvasY: null,
dashboardX: 0,
dashboardY: 0,
importType: null,
showContextMenu: false,
selectedBlocks: [],
textEditing: null,
updateCanvas: false,
selecting: {
startX: null,
startY: null,
endX: null,
endY: null,
canSelect: false,
},
isInputtingBrushSize: false,
scrollOffset: 0,
toolbarString: "top: 0px;",
lastPostURL: "",
drawBrush: false,
happy: false,
resetSelect: false,
mirror: {
x: false,
y: false,
},
diffBlocks: {
l: 0,
old: [],
new: [],
},
updateAscii: false,
}),
computed: {
isDefault() {
return this.currentTool.name === "default";
},
isSelecting() {
return this.currentTool.name === "select";
},
currentTool() {
return toolbarIcons[this.$store.getters.currentTool] ?? null;
},
icon() {
return [
this.currentTool.fa ?? "fas",
this.currentTool.icon ?? "mouse-pointer",
];
},
// options() {
// return this.$store.getters.options;
// },
asciibirdMeta() {
return this.$store.getters.asciibirdMeta;
},
debugPanelState() {
return this.$store.getters.debugPanel;
},
currentAscii() {
return this.$store.getters.currentAscii;
},
currentTab() {
return this.$store.getters.currentTab;
},
imageOverlay() {
return this.$store.getters.imageOverlay || false;
},
imageOverlayUrl() {
return this.imageOverlay.url
? this.imageOverlay.url.split("/").pop()
: "";
},
selectBlocks() {
return this.$store.getters.selectBlocks;
},
modalState() {
return this.$store.getters.modalState;
},
isModalOpen() {
return this.$store.getters.isModalOpen;
},
// Layers
asciiLayersMenu() {
let menu = [];
for (let i in [...this.currentAsciiLayers]) {
menu.push({
text: this.currentAsciiLayers[i].label,
click: () =>
this.$store.commit(
"changeLayer",
this.currentAsciiLayers.length - i
),
});
}
return menu.reverse();
},
isKeyboardDisabled() {
return this.$store.getters.isKeyboardDisabled;
},
selectedLayer() {
return this.$store.getters.selectedLayer;
},
canToggleLayer() {
return this.currentAsciiLayers.length > 1;
// We want to avoid hiding all the layers, so if there's only one
// visible left, we have to disable the buttons
},
brushSizeHeight() {
return this.$store.getters.brushSizeHeight;
},
brushSizeWidth() {
return this.$store.getters.brushSizeWidth;
},
brushSizeType() {
return this.$store.getters.brushSizeType;
},
// Toolbar related
gridView() {
return this.toolbarState.gridView;
},
canFg() {
return this.$store.getters.isTargettingFg;
},
canBg() {
return this.$store.getters.isTargettingBg;
},
canText() {
return this.$store.getters.isTargettingChar;
},
currentFg() {
return this.$store.getters.currentFg;
},
currentBg() {
return this.$store.getters.currentBg;
},
currentChar() {
return this.$store.getters.currentChar;
},
toolbarState() {
return this.$store.getters.toolbarState;
},
brushBlocks() {
return this.$store.getters.brushBlocks;
},
tabsVisible() {
return this.$store.getters.tabsVisible;
},
menuBarVisible() {
return this.$store.getters.menuBarVisible;
},
currentAsciiLayerBlocks() {
return this.currentSelectedLayer.data;
},
currentAsciiLayers() {
return this.$store.getters.currentAsciiLayers;
},
selectedLayerIndex() {
return this.currentAscii.selectedLayer || 0;
},
brushLibraryState() {
return this.$store.getters.brushLibraryState;
},
brushPreviewState() {
return this.$store.getters.brushPreviewState;
},
layersLibraryState() {
return this.$store.getters.layersLibraryState;
},
currentSelectedLayer() {
return this.currentAsciiLayers[this.currentAscii.selectedLayer];
},
isBrushing() {
return this.currentTool.name === "brush";
},
isErasing() {
return this.currentTool.name === "eraser";
},
isSelected() {
return (
this.selecting.startX !== null &&
this.selecting.startY !== null &&
this.selecting.endX !== null &&
this.selecting.endY !== null
);
},
changeAsciiMenu() {
let menu = [];
if (this.asciibirdMeta.length) {
for (let i in this.asciibirdMeta) {
let ascii = this.asciibirdMeta[i];
menu.push({
text: ascii.title,
click: () => this.changeTab(i),
icon: "insert_drive_file",
hotkey: `ctrl+${i}`,
});
}
}
return menu;
},
// Toolbar menu
myMenu() {
let menu = [];
menu.push({
text: "File",
hotkey: "0",
icon: "insert_drive_file",
menu: [
{
text: "New ASCII",
click: () => this.$store.commit("openModal", "new-ascii"),
icon: "fiber_new",
hotkey: "ctrl+m",
},
],
});
if (this.asciibirdMeta.length) {
menu[0].menu.push(
{
text: "Close ASCII",
click: () => this.closeTab(this.currentTab),
icon: "close",
hotkey: "ctrl+r",
},
{
text: "Change ASCII",
icon: "tab",
menu: this.changeAsciiMenu,
}
);
menu.push({
text: "Edit",
icon: "edit",
menu: [
{
text: "Edit ASCII",
click: () => this.$store.commit("openModal", "edit-ascii"),
icon: "edit",
hotkey: "ctrl+e",
},
{
is: "separator",
},
{
text: "Undo",
click: () => this.$store.commit("undoBlocks"),
icon: "undo",
hotkey: "ctrl+z",
},
{
text: "Redo",
click: () => this.$store.commit("redoBlocks"),
icon: "redo",
hotkey: "ctrl+y",
},
{
is: "separator",
},
{
text: "Copy Selection",
click: () => {
this.$store.commit(
"selectBlocks",
filterNullBlocks(this.selectedBlocks)
);
this.resetSelect = !this.resetSelect;
this.selectedBlocks = [];
this.$toasted.show("Copied blocks!", {
type: "success",
icon: "content_copy",
});
},
icon: "content_copy",
disabled: !this.isSelecting || !this.selectedBlocks.length,
hotkey: "ctrl+c",
},
{
text: "Cut Selection",
click: () => {
if (this.selectedBlocks.length) {
for (let y = 0; y < this.selectedBlocks.length + 1; y++) {
for (
let x = 0;
x < getBlocksWidth(this.selectedBlocks) + 1;
x++
) {
if (this.selectedBlocks[y] && this.selectedBlocks[y][x]) {
let oldBlock = this.currentAsciiLayerBlocks[y][x];
this.currentAsciiLayerBlocks[y][x] = { ...emptyBlock };
this.storeDiffBlocks(x, y, oldBlock, { ...emptyBlock });
}
}
}
this.$store.commit(
"selectBlocks",
filterNullBlocks(this.selectedBlocks)
);
this.resetSelect = !this.resetSelect;
this.selectedBlocks = [];
// Reset and hide the select after successful copy
this.dispatchBlocks();
this.$emit("updatecanvas");
this.$toasted.show("Cut blocks!", {
type: "success",
icon: "content_cut",
});
}
},
icon: "content_cut",
disabled: !this.isSelecting || !this.selectedBlocks.length,
hotkey: "ctrl+x",
},
{
text: "Paste Select as Brush",
click: () => {
this.$store.commit("pushBrushHistory", this.brushBlocks);
this.$store.commit("brushBlocks", this.selectBlocks);
this.$store.commit("changeTool", 4);
this.resetSelect = !this.resetSelect;
this.selectedBlocks = [];
this.$store.commit("selectBlocks", []);
},
icon: "content_paste",
disabled: !this.selectBlocks.length,
hotkey: "ctrl+v",
},
{
text: "Delete Selected Blocks",
click: () => {
if (this.selectedBlocks.length) {
for (let y = 0; y < this.selectedBlocks.length + 1; y++) {
for (
let x = 0;
x < getBlocksWidth(this.selectedBlocks) + 1;
x++
) {
if (this.selectedBlocks[y] && this.selectedBlocks[y][x]) {
let oldBlock = this.currentAsciiLayerBlocks[y][x];
this.currentAsciiLayerBlocks[y][x] = { ...emptyBlock };
this.storeDiffBlocks(x, y, oldBlock, { ...emptyBlock });
}
}
}
// Reset and hide the select after successful copy
this.dispatchBlocks();
this.$emit("updatecanvas");
this.resetSelect = !this.resetSelect;
this.selectedBlocks = [];
this.$store.commit("selectBlocks", []);
this.$toasted.show("Deleted blocks!", {
type: "success",
icon: "delete_sweep",
});
}
},
icon: "delete_sweep",
disabled: !this.isSelected && !this.selectedBlocks.length,
hotkey: "Delete",
},
],
});
menu.push({
text: "View",
icon: "preview",
menu: [
{
text: "Windows",
icon: "desktop",
// Show Hide Things
menu: [
{
text: `${this.tabsVisible ? "Hide" : "Show"} Tabs`,
icon: this.tabsVisible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+t",
click: (e) => {
this.$store.commit("changeTabsVisible", !this.tabsVisible);
},
},
{
text: `${this.menuBarVisible ? "Hide" : "Show"} Toolbar Menu`,
icon: this.menuBarVisible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+m",
click: (e) => {
this.$store.commit(
"changeMenuBarVisible",
!this.menuBarVisible
);
},
},
{
is: "separator",
},
{
text: `${
this.debugPanelState.visible ? "Hide" : "Show"
} Debug Panel`,
icon: this.debugPanelState.visible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+d",
click: (e) => {
this.$store.commit(
"toggleDebugPanel",
!this.debugPanelState.visible
);
},
},
{
text: `${
this.brushLibraryState.visible ? "Hide" : "Show"
} Brush Library`,
icon: this.brushLibraryState.visible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+b",
click: (e) => {
this.$store.commit(
"toggleBrushLibrary",
!this.brushLibraryState.visible
);
},
},
{
text: `${
this.layersLibraryState.visible ? "Hide" : "Show"
} Layers`,
icon: this.layersLibraryState.visible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+l",
click: (e) => {
this.layersLibraryState.visible =
!this.layersLibraryState.visible;
this.$store.commit(
"changeLayersLibraryState",
this.layersLibraryState
);
},
},
{
text: `${
this.toolbarState.visible ? "Hide" : "Show"
} Toolbar`,
icon: this.toolbarState.visible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+n",
click: (e) => {
this.toolbarState.visible = !this.toolbarState.visible;
this.$store.commit("changeToolBarState", this.toolbarState);
},
},
{
text: `${
this.brushPreviewState.visible ? "Hide" : "Show"
} Brush Preview`,
icon: this.brushPreviewState.visible
? "check_box"
: "check_box_outline_blank",
hotkey: "ctrl+alt+e",
click: (e) => {
this.brushPreviewState.visible =
!this.brushPreviewState.visible;
this.$store.commit(
"changeBrushPreviewState",
this.brushPreviewState
);
},
},
],
},
{
text: "Toggle Grid",
icon: this.gridView ? "check_box" : "check_box_outline_blank",
hotkey: "alt+g",
click: (e) => {
this.$store.commit("toggleGridView", !this.gridView);
this.$toasted.show(
`Grid view ${this.gridView ? "enabled" : "disabled"}`
);
},
},
{
text: "Mirror X",
hotkey: "alt+x",
icon: this.toolbarState.mirrorX
? "check_box"
: "check_box_outline_blank",
click: (e) => {
this.mirror.x = !this.toolbarState.mirrorX;
this.$store.commit("updateMirror", this.mirror);
this.$toasted.show(
`Mirror Y ${this.mirror.y ? "enabled" : "disabled"}`
);
},
},
{
text: "Mirror Y",
icon: this.toolbarState.mirrorY
? "check_box"
: "check_box_outline_blank",
hotkey: "alt+y",
click: (e) => {
this.mirror.y = !this.toolbarState.mirrorY;
this.$store.commit("updateMirror", this.mirror);
this.$toasted.show(
`Mirror Y ${this.mirror.y ? "enabled" : "disabled"}`
);
},
},
{
text: "Update Brush",
hotkey: "alt+u",
icon: this.toolbarState.updateBrush
? "check_box"
: "check_box_outline_blank",
click: (e) => {
this.$store.commit(
"toggleUpdateBrush",
!this.toolbarState.updateBrush
);
this.$toasted.show(
`Update Brush when colours or char changes ${
this.toolbarState.updateBrush ? "enabled" : "disabled"
}`
);
},
},
{
is: "separator",
},
{
text: "Flip Horizontal Brush",
hotkey: "e",
disabled: !this.isBrushing,
icon: "swap_horiz",
click: (e) => {
this.$store.commit("flipRotateBlocks", { type: "flip" });
},
},
{
text: "Flip Vertical Brush",
hotkey: "q",
disabled: !this.isBrushing,
icon: "swap_horiz",
click: (e) => {
this.$store.commit("flipRotateBlocks", { type: "rotate" });
},
},
{
text: "Increase Brush Size",
hotkey: "ctrl+]",
disabled: !this.isBrushing && !this.isErasing,
icon: "add",
click: (e) => {
if (
this.brushSizeHeight < maxBrushSize &&
this.brushSizeHeight >= 1 &&
this.brushSizeWidth < maxBrushSize &&
this.brushSizeWidth >= 1
) {
this.$store.commit("updateBrushSize", {
brushSizeHeight: parseInt(this.brushSizeHeight) + 1,
brushSizeWidth: parseInt(this.brushSizeWidth) + 1,
brushSizeType: this.brushSizeType,
});
}
},
},
{
text: "Decrease Brush Size",
hotkey: "ctrl+[",
disabled: !this.isBrushing && !this.isErasing,
icon: "remove",
click: (e) => {
if (
this.brushSizeHeight <= maxBrushSize &&
this.brushSizeHeight > 1 &&
this.brushSizeWidth <= maxBrushSize &&
this.brushSizeWidth > 1
) {
this.$store.commit("updateBrushSize", {
brushSizeHeight: parseInt(this.brushSizeHeight) - 1,
brushSizeWidth: parseInt(this.brushSizeWidth) - 1,
brushSizeType: this.brushSizeType,
});
}
},
},
{
is: "separator",
},
{
text: "Swap FG and BG",
hotkey: "alt+r",
icon: "swap_horiz",
click: (e) => {
let bg = this.currentBg;
let fg = this.currentFg;
this.$store.commit("changeColourFg", bg);
this.$store.commit("changeColourBg", fg);
},
},
{
text: "Change FG",
hotkey: "alt+f",
icon: "flip_to_front",
click: (e) => {
this.$store.commit(
"changeIsUpdatingFg",
!this.toolbarState.isChoosingFg
);
},
},
{
text: "Change BG",
hotkey: "alt+b",
icon: "flip_to_back",
click: (e) => {
this.$store.commit(
"changeIsUpdatingBg",
!this.toolbarState.isChoosingBg
);
},
},
{
text: "Change Char",
hotkey: "alt+c",
icon: "atm",
click: (e) => {
this.$store.commit(
"changeIsUpdatingChar",
!this.toolbarState.isChoosingChar
);
},
},
{
is: "separator",
},
{
text: "Options",
icon: "settings",
click: () => this.$store.commit("openModal", "options"),
disabled: !this.isDefault,
hotkey: "ctrl+o",
// menu: [
// {
// text: "Show Options",
// click: () => this.$store.commit("openModal", "options"),
// icon: "settings",
// },
// ],
},
],
});
}
menu.push({
text: "Import",
icon: "upload_file",
menu: [
{
text: "mIRC File",
click: () => this.startImport("mirc"),
icon: "upload_file",
hotkey: "ctrl+shift+o",
},
{
text: "mIRC Clipboard",
click: () => this.$store.commit("openModal", "paste-ascii"),
hotkey: "ctrl+shift+v",
icon: "copy_all",
},
{
text: "ASCIIBIRD State",
click: () => this.startImport("asb"),
icon: "save_alt",
},
],
});
if (this.asciibirdMeta.length) {
menu.push(
{
text: "Export",
icon: "save_alt",
menu: [
{
text: "mIRC File",
click: () => this.startExport("file"),
icon: "download_file",
hotkey: "ctrl+shift+f",
},
{
text: "mIRC Clipboard",
hotkey: "ctrl+shift+c",
click: () => this.startExport("clipboard"),
icon: "copy_all",
},
{
text: "PNG Image",
hotkey: "ctrl+shift+g",
click: () => {
canvasToPng(
document.getElementById("canvas"),
this.currentAscii.title
);
},
icon: "image",
},
{
text: "HTTP POST",
click: () => this.startExport("post"),
hotkey: "ctrl+shift+h",
icon: "post_add",
},
{
text: "ASCIIBIRD State",
click: () => this.exportAsciibirdState(),
icon: "save_alt",
},
],
},
{
text: "Layers",
icon: "layers",
menu: [
// {
// text: "Change Layers",
// menu: this.asciiLayersMenu,
// },
{
text: "Show/Hide Layer",
click: () =>
this.$store.commit("toggleLayer", this.selectedLayer),
icon: "panorama_fish_eye",
hotkey: "ctrl+shift+t",
disabled: !this.canToggleLayer,
},
{
text: "Rename Layer",
hotkey: "ctrl+shift+r",
click: () =>
this.showLayerRename(
this.selectedLayer,
this.currentAsciiLayers[this.selectedLayer].label
),
icon: "text_rotation_none",
},
{
text: "Add Layer",
hotkey: "ctrl+shift+a",
click: () => this.$store.commit("addLayer"),
icon: "playlist_add",
},
{
text: "Delete Layer",
hotkey: "ctrl+shift+d",
click: () =>
this.$store.commit("removeLayer", this.selectedLayer),
icon: "delete_sweep",
disabled: !this.canToggleLayer,
},
{
text: "Move Layer Down",
hotkey: "ctrl+shift+s",
click: () => this.$store.commit("upLayer", this.selectedLayer),
icon: "arrow_downward",
disabled: !this.canToggleLayer,
},
{
text: "Move Layer Up",
hotkey: "ctrl+shift+w",
click: () =>
this.$store.commit("downLayer", this.selectedLayer),
icon: "arrow_upward",
disabled: !this.canToggleLayer,
},
{
text: "Merge All Layers",
hotkey: "ctrl+shift+m",
click: () => this.$store.commit("mergeAllLayers"),
icon: "playlist_play",
disabled: !this.canToggleLayer,
},
],
},
{
text: "Help",
icon: "help",
menu: [
{
text: "ASCIIBIRD on GitHub",
click: () => window.open("https://github.com/hughbord/asciibird", "_blank"),
icon: "code",
},
{
text: "ASCIIBIRD on tcp.direct Git",
click: () => window.open("https://git.tcp.direct/jewbird/asciibird", "_blank"),
icon: "code",
},
{
text: "About ASCIIBIRD",
click: () => this.$store.commit("openModal", "about"),
hotkey: "F1",
icon: "help_outline",
},
],
}
);
}
return menu;
},
},
watch: {
// scrollOffset(val) {
// this.$refs.tabbar.style.top = val;
// this.toolbarString = `top: ${val}px`;
// },
isModalOpen(val, old) {
if (val) {
hotkeys.deleteScope("all");
}
},
isKeyboardDisabled(val, old) {
if (val) {
hotkeys.deleteScope("all");
}
}
},
methods: {
updateAsciiDetails(widthHeight) {
// From edit ascii modal to editor
this.updateAscii = widthHeight;
},
dispatchBlocks() {
this.diffBlocks.old = this.diffBlocks.old.flat();
this.diffBlocks.new = this.diffBlocks.new.flat();
this.$store.dispatch("updateAsciiBlocksAsync", {
blocks: this.currentAsciiLayerBlocks,
diff: { ...this.diffBlocks },
});
this.diffBlocks = {
l: this.selectedLayerIndex,
new: [],
old: [],
};
},
storeDiffBlocks(x, y, oldBlock, newBlock) {
// For undo
if (!this.diffBlocks.old[y]) {
this.diffBlocks.old[y] = [];
}
if (!this.diffBlocks.old[y][x]) {
this.diffBlocks.old[y][x] = {
x: x,
y: y,
b: { ...oldBlock },
};
}
if (!this.diffBlocks.new[y]) {
this.diffBlocks.new[y] = [];
}
if (!this.diffBlocks.new[y][x]) {
this.diffBlocks.new[y][x] = {
x: x,
y: y,
b: { ...newBlock },
};
}
},
splashAscii() {
return splashAscii;
},
showLayerRename(key, label) {
this.$store.commit("toggleDisableKeyboard", true);
this.$dialog
.prompt({
title: "Rename Layer",
text: "Please input your new layer name",
icon: "question",
inputValue: label,
clickToClose: false,
})
.then((result) => {
if (!result.input.length) {
this.$toasted.show("You must enter a layer name!", {
type: "error",
});
this.$store.commit("toggleDisableKeyboard", false);
return;
}
if (result.isOk) {
this.updateLayerName(key, result.input);
}
this.$store.commit("toggleDisableKeyboard", false);
});
},
updateLayerName(key, label) {
this.$store.commit("updateLayerName", {
key: key,
label: label,
});
},
triggerbrush() {
this.drawBrush = !this.drawBrush;
},
inputtingbrush(val) {
this.isInputtingBrushSize = val;
},
buttonStyle(key) {
return this.currentTab === key
? `text-sm pl-1 p-1 h-10 text-white border border-transparent shadow-sm hover:bg-blue-500 bg-gray-900`
: `text-sm pl-1 p-1 h-10 text-white border border-transparent shadow-sm hover:bg-blue-500 bg-gray-400`;
},
openContextMenu(e) {
e.preventDefault();
this.$refs.menu.open(e);
},
updateCoords(value) {
this.canvasX = value.x;
this.canvasY = value.y;
},
selectedblocks(value) {
this.selectedBlocks = value;
},
updateSelecting(value) {
this.selecting = value;
},
textediting(value) {
this.textEditing = value;
},
updatecanvas() {
this.updateCanvas = !this.updateCanvas;
},
async onImport() {
const { files } = this.$refs.asciiInput;
const filename = files[0].name;
const fileReader = new FileReader();
const fileType = this.importType;
fileReader.addEventListener("load", () => {
switch (fileType) {
case "asb":
this.importAsciibirdState(fileReader.result, filename);
break;
default:
case "mirc":
parseMircAscii(fileReader.result, filename);
break;
}
});
// This will fire the file reader 'load' event
fileReader.readAsText(files[0]);
},
startImport(type) {
// For ANSI we'll need to add back in the
// type cariable here
this.importType = type;
this.$refs.asciiInput.click();
},
importAsciibirdState(fileContents) {
const contents = JSON.parse(
LZString.decompressFromEncodedURIComponent(fileContents)
);
this.$store.commit("changeState", { ...contents });
},
exportAsciibirdState() {
let output;
try {
output = LZString.compressToEncodedURIComponent(
JSON.stringify(this.$store.getters.state)
);
// Default timestamp for filename
const today = new Date();
const y = today.getFullYear();
const m = today.getMonth() + 1; // JavaScript months are 0-based.
const d = today.getDate();
const h = today.getHours();
const mi = today.getMinutes();
const s = today.getSeconds();
downloadFile(
output,
`asciibird-${y}-${m}-${d}-${h}-${mi}-${s}.asb`,
"application/gzip"
);
} catch (err) {
this.$toasted.show(err, {
type: "error",
});
}
},
startExport(type) {
let ascii = exportMirc();
switch (type) {
case "clipboard":
this.$copyText(ascii.output.join("")).then(
(e) => {
this.$toasted.show("Copied mIRC to clipboard!", {
type: "success",
});
},
(e) => {
this.$toasted.show("Error when copying mIRC to clipboard!", {
type: "error",
});
}
);
break;
default:
case "file":
downloadFile(ascii.output.join(""), ascii.filename, "text/plain");
break;
case "post":
this.$store.commit("toggleDisableKeyboard", true);
this.$dialog
.prompt({
title: "HTTP Post your Ascii",
text: "Please input the URL for the HTTP Post sir",
icon: "question",
inputValue: this.lastPostURL,
clickToClose: false,
})
.then((result) => {
if (result.input === undefined) {
this.$toasted.show("Come on bro. Get it together.", {
type: "error",
});
this.$store.commit("toggleDisableKeyboard", false);
return;
}
if (result.isOk) {
let ascii = exportMirc();
this.lastPostURL = result.input;
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
body: ascii.output.join(""),
};
fetch(this.lastPostURL, requestOptions)
.then((response) => {
if (response.status === 200 || response.status === 201) {
this.$toasted.show("POSTed ascii!", {
type: "success",
});
} else {
this.$toasted.show(
`Error: ${response.status} ${response.statusText}`,
{
type: "error",
}
);
}
})
.catch((error) => {
this.$toasted.show(`Error: ${JSON.stringify(error)}`, {
type: "error",
});
});
}
this.$store.commit("toggleDisableKeyboard", false);
});
break;
}
},
changeTab(key) {
// Update the tab index in vuex store
this.$store.commit("changeTab", key);
},
closeTab(key) {
this.$dialog
.confirm({
title: `Close ${this.asciibirdMeta[key].title}?`,
text: "This action cannot be undone and the ASCII will be gone.",
icon: "info",
})
.then((result) => {
if (result.isOk) {
this.$store.commit("closeTab", key);
}
});
},
captureMouse(event) {
this.dashboardX = event.pageX;
this.dashboardY = event.pageY;
},
},
};
</script>