PASSING BEXMARK, WIDTH FIXED

This commit is contained in:
Hugh Bord 2021-04-17 11:36:44 +10:00
父節點 a1cbf1ecc1
當前提交 2c7725684e
共有 3 個檔案被更改,包括 209 行新增94 行删除

查看文件

@ -5,9 +5,11 @@ ASCIIBIRD DEVELOPMENT - TAKING FLIGHT
# FOCUSING ON NOW
* Toolbar stuff / Brush Size
* Context Menus (right click menu)
* Keyboard shortcuts
* Undo feature
* BLOCK BUG WITH WHITE CHARS
* COMPRESSION inside the localStorage

查看文件

@ -1,6 +1,5 @@
<template>
<div id="app">
<t-modal
name="create-ascii-modal"
header="Create new ASCII"
@ -8,7 +7,6 @@
:escToClose="false"
@before-closed="closeNewASCII"
>
Width
<t-input
type="number"
@ -44,29 +42,43 @@
</template>
</t-modal>
<div>
<t-button @click="createClick()" class="ml-1">New ASCII</t-button>
<t-button @click="clearCache()" class="ml-1"
>Clear and Refresh</t-button
>
<t-button @click="startImport('mirc')" class="ml-1">Import mIRC</t-button>
<t-button @click="exportMirc()" class="ml-1" v-if="this.$store.getters.asciibirdMeta.length"
>Export ASCII to mIRC</t-button
>
<t-button @click="exportAsciibirdState()" class="ml-1" v-if="this.$store.getters.asciibirdMeta.length"
>Save Asciibird State</t-button
>
<t-button @click="startImport('asb')" class="ml-1"
>Load Asciibird State</t-button
>
<!-- <t-button @click="startImport('ansi')" class="ml-1">Import ANSI</t-button> -->
<input
type="file"
style="display: none"
ref="asciiInput"
@change="onImport()"
/>
<context-menu :display="showContextMenu" ref="menu">
<ul>
<li @click="createClick()" class="ml-1">New ASCII</li>
<li @click="clearCache()" class="ml-1">Clear and Refresh</li>
<li @click="startImport('mirc')" class="ml-1">Import mIRC</li>
<li
@click="exportMirc()"
class="ml-1"
v-if="this.$store.getters.asciibirdMeta.length"
>
Export ASCII to mIRC
</li>
<li
@click="exportAsciibirdState()"
class="ml-1"
v-if="this.$store.getters.asciibirdMeta.length"
>
Save Asciibird State
</li>
<li @click="startImport('asb')" class="ml-1">Load Asciibird State</li>
</ul>
</context-menu>
<span
@mouseup.right="openContextMenu"
@contextmenu.prevent
style="width: 100%; height: 100%; position: absolute; z-index: -1"
></span>
<input
type="file"
style="display: none"
ref="asciiInput"
@change="onImport()"
/>
<template v-if="this.$store.getters.asciibirdMeta.length">
<t-button
v-for="(value, key) in this.$store.getters.asciibirdMeta"
v-bind:key="key"
@ -77,17 +89,9 @@
{{ value.title }}
</t-button>
<Toolbar
:canvas-x="canvasX"
:canvas-y="canvasY"
v-if="this.$store.getters.asciibirdMeta.length"
/>
<DebugPanel
:canvas-x="canvasX"
:canvas-y="canvasY"
v-if="this.$store.getters.asciibirdMeta.length"
/>
<Editor @coordsupdate="updateCoords" v-if="this.$store.getters.asciibirdMeta.length" />
<Toolbar :canvas-x="canvasX" :canvas-y="canvasY" />
<DebugPanel :canvas-x="canvasX" :canvas-y="canvasY" />
<Editor @coordsupdate="updateCoords" />
<CharPicker v-if="$store.getters.getToolbarState.isChoosingChar" />
<ColourPicker
@ -96,8 +100,15 @@
$store.getters.getToolbarState.isChoosingBg
"
/>
</div>
</template>
<template v-else>
<div style="left: 35%; top: 15%; position: absolute; z-index: -2">
<h1 style="font-size: 72px; text-align: center">ASCIIBIRD</h1>
<h1 style="font-size: 13px; text-align: center">
Right click to start
</h1>
</div>
</template>
</div>
</template>
@ -105,43 +116,45 @@
/* html {
cursor: url('assets/mouse-pointer-solid.svg'), auto;
} */
</style>
<script>
import Toolbar from './components/Toolbar.vue';
import DebugPanel from './components/DebugPanel.vue';
import Editor from './views/Editor.vue';
import Toolbar from "./components/Toolbar.vue";
import DebugPanel from "./components/DebugPanel.vue";
import Editor from "./views/Editor.vue";
// import * as Anser from "anser";
import CharPicker from './components/parts/CharPicker.vue';
import ColourPicker from './components/parts/ColourPicker.vue';
import CharPicker from "./components/parts/CharPicker.vue";
import ColourPicker from "./components/parts/ColourPicker.vue";
import ContextMenu from "./components/parts/ContextMenu.vue";
// import AsciiCursor from './components/parts/AsciiCursor.vue';
// import pako from 'pako';
export default {
async created() {
// Load from irc watch if present in the URL bar
const asciiUrl = new URL(location.href).searchParams.get('ircwatch');
if (asciiUrl) {
const res = await fetch(`https://irc.watch/ascii/txt/${asciiUrl}`);
const asciiData = await res.text();
this.mircAsciiImport(asciiData, asciiUrl);
window.location.href = '/';
}
// console.log(this.currentTool.svgPath)
// document.getElementsByTagName("html")[0].style.setProperty('cursor', "url('assets/fill-drip-solid.svg'), auto")
// const asciiUrl = new URL(location.href).searchParams.get("ircwatch");
// if (asciiUrl) {
// const res = await fetch(`https://irc.watch/ascii/txt/${asciiUrl}`);
// const asciiData = await res.text();
// this.mircAsciiImport(asciiData, asciiUrl);
// window.location.href = "/";
// }
},
components: {
Toolbar, DebugPanel, Editor, CharPicker, ColourPicker,
Toolbar,
DebugPanel,
Editor,
CharPicker,
ColourPicker,
ContextMenu,
},
name: 'Dashboard',
name: "Dashboard",
data: () => ({
forms: {
createAscii: {
width: 5,
height: 5,
title: 'ascii',
title: "ascii",
},
},
currentTab: 1,
@ -150,16 +163,27 @@ export default {
dashboardX: 0,
dashboardY: 0,
importType: null,
showContextMenu: false,
}),
computed: {
currentTool() {
return this.$store.getters.getToolbarIcons[this.$store.getters.getCurrentTool] ?? null;
return (
this.$store.getters.getToolbarIcons[
this.$store.getters.getCurrentTool
] ?? null
);
},
icon() {
return [this.currentTool.fa ?? 'fas', this.currentTool.icon ?? 'mouse-pointer'];
return [
this.currentTool.fa ?? "fas",
this.currentTool.icon ?? "mouse-pointer",
];
},
},
methods: {
openContextMenu(e) {
this.$refs.menu.open(e);
},
updateCoords(value) {
this.canvasX = value.x;
this.canvasY = value.y;
@ -170,13 +194,13 @@ export default {
const fileReader = new FileReader();
const _importType = this.importType;
fileReader.addEventListener('load', () => {
fileReader.addEventListener("load", () => {
switch (_importType) {
case 'asb':
case "asb":
this.importAsciibirdState(fileReader.result, filename);
break;
case 'mirc':
case "mirc":
this.mircAsciiImport(fileReader.result, filename);
break;
}
@ -286,23 +310,23 @@ export default {
};
// set asciiImport as the entire file contents as a string
const asciiImport = contents.split('\u0003\u0003').join('\u0003');
const asciiImport = contents.split("\u0003\u0003").join("\u0003");
// This will end up in the asciibirdMeta
const finalAscii = {
width: false, // defined in: switch (curChar) case "\n":
height: asciiImport.split('\n').length,
height: asciiImport.split("\n").length,
title: filename,
key: this.$store.getters.nextTabValue,
blockWidth: 8 * this.$store.getters.blockSizeMultiplier,
blockHeight: 13 * this.$store.getters.blockSizeMultiplier,
blocks: this.create2DArray(asciiImport.split('\n').length),
blocks: this.create2DArray(asciiImport.split("\n").length),
x: 247, // the dragable ascii canvas x
y: 24, // the dragable ascii canvas y
};
// Turn the entire ascii string into an array
let asciiStringArray = asciiImport.split('');
let asciiStringArray = asciiImport.split("");
// The proper X and Y value of the block inside the ASCII
let asciiX = 0;
@ -323,7 +347,7 @@ export default {
// Defining a small finite state machine
// to detect the colour code
switch (curChar) {
case '\n':
case "\n":
// Reset the colours here on a new line
curBlock = {
fg: null,
@ -338,7 +362,8 @@ export default {
// If for some reason like in aphex.txt the first line is
// trimmed it will trim the entire ascii!
if (!finalAscii.width) {
finalAscii.width = asciiImport.split('\n')[0].length - 1 - widthOfColCodes; // minus \n for the proper width
finalAscii.width =
asciiImport.split("\n")[0].length - 1 - widthOfColCodes; // minus \n for the proper width
}
// Resets the X value
@ -347,7 +372,7 @@ export default {
asciiStringArray.shift();
break;
case '\u0003':
case "\u0003":
// Remove the colour char
asciiStringArray.shift();
widthOfColCodes++;
@ -360,7 +385,6 @@ export default {
// Work out the 01, 02 double digit codes
if (parseInt(colourChar1) === 0 && parseInt(colourChar2) >= 0) {
asciiStringArray.shift();
widthOfColCodes += 1;
}
if (isNaN(parsedColour)) {
@ -373,15 +397,16 @@ export default {
asciiStringArray = asciiStringArray.slice(
parsedColour.toString().length,
asciiStringArray.length,
asciiStringArray.length
);
}
// No background colour
if (asciiStringArray[0] !== ',') {
if (asciiStringArray[0] !== ",") {
break;
} else {
// Remove , from array
widthOfColCodes += 1;
asciiStringArray.shift();
}
@ -391,16 +416,31 @@ export default {
parsedColour = parseInt(`${colourChar1}${colourChar2}`);
if (
!isNaN(colourChar1)
&& !isNaN(colourChar2)
&& parseInt(colourChar2) > parseInt(colourChar1)
&& !isNaN(parsedColour)
&& parseInt(parsedColour) < 10
!isNaN(colourChar1) &&
!isNaN(colourChar2) &&
parseInt(colourChar2) > parseInt(colourChar1) &&
!isNaN(parsedColour) &&
parseInt(parsedColour) < 10
) {
parsedColour = parseInt(colourChar2);
widthOfColCodes += 1;
asciiStringArray.shift();
}
if (
parseInt(colourChar2) === parseInt(colourChar1) &&
parseInt(parsedColour) < 10
) {
parsedColour = parseInt(colourChar1);
asciiStringArray.shift();
asciiStringArray.shift();
widthOfColCodes += 2;
curBlock.bg = parseInt(colourChar1);
break;
}
if (isNaN(parsedColour)) {
curBlock.bg = parseInt(colourChar1);
widthOfColCodes += 1;
@ -411,7 +451,7 @@ export default {
asciiStringArray = asciiStringArray.slice(
parsedColour.toString().length,
asciiStringArray.length,
asciiStringArray.length
);
break;
@ -430,7 +470,7 @@ export default {
} // End loop charPos
// Store the ASCII
this.$store.commit('newAsciibirdMeta', finalAscii);
this.$store.commit("newAsciibirdMeta", finalAscii);
// To show the ASCII after importing we get the last key
// from the asciiBirdMeta array
@ -440,7 +480,7 @@ export default {
// Set the current tab and pop the array for the last value
this.currentTab = keys.pop();
this.$store.commit('changeTab', this.currentTab);
this.$store.commit("changeTab", this.currentTab);
// Update the browsers title to the ASCII filename
document.title = `asciibird - ${this.$store.getters.currentAscii.title}`;
@ -467,7 +507,7 @@ export default {
// console.log(fileContents)
// No gz for now unless can get the above working
this.$store.commit('changeState', { ...JSON.parse(fileContents) });
this.$store.commit("changeState", { ...JSON.parse(fileContents) });
},
exportAsciibirdState() {
// Download to a gzipped json file
@ -488,7 +528,11 @@ export default {
const mi = today.getMinutes();
const s = today.getSeconds();
this.downloadToFile(output, `asciibird-${y}-${m}-${d}-${h}-${mi}-${s}.asb`, 'application/json');
this.downloadToFile(
output,
`asciibird-${y}-${m}-${d}-${h}-${mi}-${s}.asb`,
"application/json"
);
} catch (err) {
console.log(err);
}
@ -507,12 +551,20 @@ export default {
// we'll put a colour codes and continue as normal
if (curBlock.bg !== prevBlock.bg || curBlock.fg !== prevBlock.fg) {
Object.assign(curBlock, currentAscii.blocks[y][x]);
const zeroPad = (num, places) => String(num).padStart(places, '0');
output.push(`\u0003${zeroPad(curBlock.fg ?? this.$store.getters.getOptions.defaultFg, 2)},${zeroPad(curBlock.bg ?? this.$store.getters.getOptions.defaultBg, 2)}`);
const zeroPad = (num, places) => String(num).padStart(places, "0");
output.push(
`\u0003${zeroPad(
curBlock.fg ?? this.$store.getters.getOptions.defaultFg,
2
)},${zeroPad(
curBlock.bg ?? this.$store.getters.getOptions.defaultBg,
2
)}`
);
}
// null .chars will end up as space
output.push(curBlock.char ?? ' ');
output.push(curBlock.char ?? " ");
prevBlock = currentAscii.blocks[y][x];
}
@ -522,18 +574,21 @@ export default {
// New line except for the very last line
if (y < currentAscii.blocks.length - 1) {
output.push('\n');
output.push("\n");
}
}
// Download to a txt file
// Check if txt already exists and append it
const filename = currentAscii.title.slice(currentAscii.title.length - 3) === 'txt' ? currentAscii.title : `${currentAscii.title}.txt`;
this.downloadToFile(output.join(''), filename, 'text/plain');
const filename =
currentAscii.title.slice(currentAscii.title.length - 3) === "txt"
? currentAscii.title
: `${currentAscii.title}.txt`;
this.downloadToFile(output.join(""), filename, "text/plain");
},
downloadToFile(content, filename, contentType) {
const downloadToFile = (content, filename, contentType) => {
const a = document.createElement('a');
const a = document.createElement("a");
const file = new Blob([content], { type: contentType });
a.href = URL.createObjectURL(file);
@ -547,16 +602,16 @@ export default {
},
createClick() {
this.forms.createAscii.title = `New ASCII ${this.$store.getters.asciibirdMeta.length}`;
this.$modal.show('create-ascii-modal');
this.$modal.show("create-ascii-modal");
},
changeTab(key, value) {
// Update the tab index in vuex store
this.currentTab = key;
this.$store.commit('changeTab', key);
this.$store.commit("changeTab", key);
},
clearCache() {
localStorage.clear();
window.location.href = '/';
window.location.href = "/";
},
createNewASCII() {
const payload = {
@ -582,13 +637,13 @@ export default {
}
}
this.$store.commit('newAsciibirdMeta', payload);
this.$modal.hide('create-ascii-modal');
this.$store.commit("newAsciibirdMeta", payload);
this.$modal.hide("create-ascii-modal");
},
closeNewASCII({ params, cancel }) {
this.forms.createAscii.width = 5;
this.forms.createAscii.height = 5;
this.forms.createAscii.title = 'New ASCII';
this.forms.createAscii.title = "New ASCII";
},
create2DArray(rows) {
const arr = [];

查看文件

@ -0,0 +1,58 @@
<template>
<div class="context-menu" v-show="show" :style="style" ref="context" tabindex="0" @blur="close">
<slot></slot>
</div>
</template>
<script>
import Vue from 'vue';
export default {
name: 'ContextMenu',
props: {
display: Boolean, // prop detect if we should show context menu
},
data() {
return {
left: 0, // left position
top: 0, // top position
show: false, // affect display of context menu
};
},
computed: {
// get position of context menu
style() {
return {
top: this.top + 'px',
left: this.left + 'px',
};
},
},
methods: {
// closes context menu
close() {
this.show = false;
this.left = 0;
this.top = 0;
},
open(evt) {
// updates position of context menu
this.left = evt.pageX || evt.clientX;
this.top = (evt.pageY || evt.clientY) - window.pageYOffset;
// make element focused
// @ts-ignore
Vue.nextTick(() => this.$el.focus());
this.show = true;
},
},
};
</script>
<style>
.context-menu {
position: fixed;
background: white;
z-index: 999;
outline: none;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
cursor: pointer;
}
</style>