asciibird v1 review, good 2 release

This commit is contained in:
Hugh Bord 2021-12-30 14:25:07 +10:00
parent d437e7371e
commit 58e4cbf789
10 changed files with 198 additions and 95 deletions

View File

@ -1,4 +1,4 @@
# ASCIIBIRD
# ASCIIBIRD V1 - PRERELEASE BUILD
```
┏ ┰╛ ╔═━┉┈┉╼━━╌┈╍┅┉╌┄┉┉━═╾─┈═──┄┈╼╍═┈┄╍═╍╼━┈─┈╼┉╍┅╌╮
@ -25,6 +25,10 @@ A most latest production build to use is available at https://asciibird.jewbird.
> beenz, xartet, OfMonsters&Crime, mouse, funkpower, Charles, PP4L, octopus, addct, hotline, dingopride, skg, eraser, aaa, chz, L0j1k
## Greetz to Chat Pals
> darkmage, l0de, bex, blarf, sludg, shart, chode, corn, ralph, jrra, kuntz, moony, scd, aztec, astro, anji, b-rex, bengt, butth0le, canada420, clamkin, deakin, dumbguy, ElBurro, interdome, syn, darkness, vae, gowce, moneytree, Retarded, spoon, sylar, zen, bj0rn, stovepipe, morthrane, chrono, acidvegas, again, hgc, durendal, knio, mavericks, pyrex, sh, irie, seirdy, sq, stratum, WeEatnKid, dieforirc, tater, buttvomit, luldangs, MichealK, AnalMan, poccri, vap0r, kakama, fregyXin
# Current Features
* Tabbed ASCII editing
@ -65,8 +69,8 @@ A most latest production build to use is available at https://asciibird.jewbird.
* Brush history is set to a limit of 50
* Brush Preview
* Editable brush preview
* Clicking updates block
* Right clicking removes block
* Can use the brush tool inside the brush preview
* Can use the eraser tool inside the brush preview
* Hovering outside brush area will save brush to history
* Context menu available on all brushes preview areas
* Export any brush to PNG, mIRC clipboard or file by right clicking the brush preview
@ -75,23 +79,17 @@ A most latest production build to use is available at https://asciibird.jewbird.
## Features to Add
* Add about asciibird modal
* Warning on mirc export if ascii exceeds IRCs 512 per chat line limit.
* Review encodings check on file import - UTF8 vs Latin something
* Colors / chars panels wont open where toolbar is, if you scroll down a lot then try open them they will be at the top
* One of the mirror brushes might be bugged sometimes and leave undoable blocks, if the mirror paths cross over it seems to do this
* The layers and undo sometimes may have bugs, but seems hard to replicate.
## Bugs to fix
* Can't move toolbar, maybe related to after dialog or modal is open
* Colors / chars panels wont open where toolbar is, if you scroll down a lot then try open them they will be at the top
* Fill tool has too much recursion sometimes, mostly it is okay
* One of the mirror brushes might be bugged sometimes and leave undoable blocks, if the mirror paths cross over it seems to do this
* Strange sort of bug with remove layer and selecting layer after, scroll up and down to redraw the canvas if it goes blank
* Redo will cause errors on layers sometimes, mostly okay
* The edit dialog, even when code to save new data is commented out, will slow down everything if you open and save the modal a few times
* The current mIRC importer will fail on `C5,` type blocks by discarding the `,` character when it should preserve it. `art.txt` ascii is a good example of this. 98% of txt ascii imported should be fine.
## Mobile / Touch Screen support
`## Mobile / Touch Screen support
Doesn't exist at the moment. While the underlying functions and code is compatible with mobile browsers from *babel*, the touch canvas events and text will need to be reviewed to work better with touch screens. For example while you can brush once, you cannot move the brush around.
@ -120,7 +118,7 @@ Doesn't exist at the moment. While the underlying functions and code is compatib
* Alt + r - Flip FG and BG colours
* Ctrl + e - Edit ASCII
* Ctrl + q - Close ASCII
* Ctrl + r - Close ASCII
* Ctrl + m - New ASCII (can't use ctrl + n)
* Ctrl + o - Toggle Asciibird Options

View File

@ -1,39 +1,29 @@
<template>
<div id="app" @contextmenu.prevent>
<div v-show="menuBarVisible">
<vue-file-toolbar-menu :content="myMenu" />
<vue-file-toolbar-menu
:content="myMenu"
v-if="!(isModalOpen || isKeyboardDisabled)"
/>
</div>
<NewAscii />
<Options v-if="asciibirdMeta.length" />
<EditAscii v-if="asciibirdMeta.length" @updateAscii="updateAsciiDetails" />
<PasteAscii />
<ImageOverlay v-if="asciibirdMeta.length" />
<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"
:is-showing-dialog="isShowingDialog"
@updatecanvas="updatecanvas"
:is-inputting-brush-size="this.isInputtingBrushSize"
:canvas-x="canvasX"
:canvas-y="canvasY"
@triggerbrush="triggerbrush"
/>
<!-- <t-dialog
name="dialog-posthttp"
title="Enter URL"
text="Enter URL for POST command"
icon="question"
:clickToClose="false"
:showCloseButton="true"
:disableBodyScroll="true"
@closed="postHttp()"
>
<t-input v-model="lastPostURL" />
</t-dialog> -->
<context-menu ref="menu" class="z-50">
<ul>
<li
@ -158,7 +148,6 @@
:update-canvas="updateCanvas"
@selecting="updateSelecting"
:y-offset="scrollOffset"
:brush="drawBrush"
:updateascii="updateAscii"
:reset-select="resetSelect"
/>
@ -231,6 +220,7 @@ 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";
@ -286,6 +276,7 @@ export default {
Options,
ImageOverlay,
VueFileToolbarMenu,
About,
},
name: "Dashboard",
data: () => ({
@ -309,7 +300,6 @@ export default {
scrollOffset: 0,
toolbarString: "top: 0px;",
lastPostURL: "",
isShowingDialog: false,
drawBrush: false,
happy: false,
resetSelect: false,
@ -367,6 +357,12 @@ export default {
selectBlocks() {
return this.$store.getters.selectBlocks;
},
modalState() {
return this.$store.getters.modalState;
},
isModalOpen() {
return this.$store.getters.isModalOpen;
},
// Layers
asciiLayersMenu() {
@ -386,6 +382,7 @@ export default {
return menu.reverse();
},
isKeyboardDisabled() {
return this.$store.getters.isKeyboardDisabled;
},
selectedLayer() {
@ -481,10 +478,10 @@ export default {
for (let i in this.asciibirdMeta) {
let ascii = this.asciibirdMeta[i];
// let shortcutKey = Number.parseInt(1 + i);
menu.push({
text: ascii.title,
click: () => this.changeTab(i),
icon: "insert_drive_file",
hotkey: `ctrl+${i}`,
});
@ -517,7 +514,7 @@ export default {
text: "Close ASCII",
click: () => this.closeTab(this.currentTab),
icon: "close",
hotkey: "ctrl+q",
hotkey: "ctrl+r",
},
{
text: "Change ASCII",
@ -1097,6 +1094,28 @@ export default {
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",
},
],
}
);
}
@ -1109,6 +1128,16 @@ export default {
// 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) {
@ -1308,11 +1337,7 @@ export default {
downloadFile(ascii.output.join(""), ascii.filename, "text/plain");
break;
case "post":
console.log(hotkeys.getScope());
// hotkeys.deleteScope("all");
this.$store.commit("toggleDisableKeyboard", true);
this.isShowingDialog = true;
this.$dialog
.prompt({
title: "HTTP Post your Ascii",
@ -1327,10 +1352,8 @@ export default {
type: "error",
});
this.$store.commit("toggleDisableKeyboard", false);
// hotkeys.setScope("all");
return;
}
if (result.isOk) {
let ascii = exportMirc();
@ -1363,8 +1386,6 @@ export default {
}
this.$store.commit("toggleDisableKeyboard", false);
// hotkeys.setScope("all");
this.isShowingDialog = false;
});
break;

View File

@ -221,10 +221,10 @@ export const parseMircAscii = async (contents, filename) => {
.split('\u0003\u0003')
.join('\u0003')
.split('\u000F').join('')
.split('\u0003\n')
.join('\n')
.split('\u0002\u0003')
.join('\u0003');
.split('\u0003\n').join('\n')
.split('\u0002\u0003').join('\u0003')
.split('\u0002').join('') // bold
.split('\u001D').join(''); // italics
let asciiLines = contents.split("\n");
@ -485,11 +485,11 @@ export const exportMirc = (blocks = null) => {
output.push('\u0003');
} else {
if (curBlock.bg === undefined && (curBlock.fg !== undefined || curBlock.fg !== null)) {
if (curBlock.bg === undefined && (curBlock.fg !== undefined && curBlock.fg !== null)) {
pushString = `\u0003${zeroPad(curBlock.fg ?? 0, 2)}`;
}
if ((curBlock.bg !== undefined || curBlock.bg !== null) && (curBlock.fg !== undefined || curBlock.fg !== null)) {
if ((curBlock.bg !== undefined && curBlock.bg !== null) && (curBlock.fg !== undefined && curBlock.fg !== null)) {
// export will check if the next char is a number and add 0 padding to prevent clients eating characters
if (blocks[y][x + 1].char !== undefined && (Number.parseInt(blocks[y][x + 1].char) >= 0 && Number.parseInt(blocks[y][x + 1].char) <= 9)) {
pushString = `\u0003${curBlock.fg ?? 0},${zeroPad(curBlock.bg ?? 1, 2)}`;

View File

@ -0,0 +1,76 @@
<template>
<t-modal
name="about-modal"
:click-to-close="false"
:esc-to-close="true"
@closed="$store.commit('closeModal', 'about')"
>
<template v-slot:default>
<div class="mt-6 lg:mt-0 rounded shadow bg-white text-center ">
<BrushCanvas :blocks="aboutAscii" class="w-32 -right-40 relative" />
<h1 class="p-2 font-extrabold">Big Shout Outs to Patrons</h1>
<span>beenz, xartet, OfMonsters&Crime, mouse, funkpower, Charles, PP4L, octopus, addct, hotline, dingopride, skg, eraser, aaa, chz, L0j1k</span>
<h5 class="p-2 font-extrabold">Greetz to</h5>
<span class="text-xs">darkmage, l0de, bex, blarf, sludg, shart, chode, corn, ralph, jrra, kuntz, moony, scd, aztec, astro, anji, b-rex, bengt, butth0le, canada420, clamkin, deakin, dumbguy, ElBurro, interdome, syn, darkness, vae, gowce, moneytree, Retarded, spoon, sylar, zen, bj0rn, stovepipe, morthrane, chrono, acidvegas, again, hgc, durendal, knio, mavericks, pyrex, sh, irie, seirdy, sq, stratum, WeEatnKid, dieforirc, tater, buttvomit, luldangs, MichealK, AnalMan, poccri, vap0r</span>
</div>
</template>
<template v-slot:footer>
<div
class="flex justify-between"
@click="$store.commit('closeModal', 'about')"
>
<t-button type="button" class="p-2 w-full"> Ok </t-button>
</div>
</template>
</t-modal>
</template>
<script>
import LZString from 'lz-string';
import BrushCanvas from "./../../components/parts/BrushCanvas.vue";
export default {
name: "About",
components: {
BrushCanvas,
},
created() {},
mounted() {
if (this.showOptionsModal) {
this.open();
} else {
this.close();
}
},
data: () => ({}),
computed: {
showOptionsModal() {
return this.$store.getters.modalState.about;
},
aboutAscii() {
return JSON.parse(LZString.decompressFromEncodedURIComponent("NrDeF8BpQIgMwOYwFwAZIwMYAsCGAnFGAQRilkRXSz0ORgGUzp4k0McCiBhZit6pzowAkn1ZUOtImPIT2NLvQBC4ygqEy1AqUpgAlbZMXCAIn3KXolgLqQwViC3WDp9AG5GNbmAEYL1oFOwY6hdg5BjvKuegAKXjHChnIuusIAoglpRABqWSZaKToF9JlFxpr0AOoBIdbhwTAARmy+GKklMAAE4i0obdHZ9D1yfcgDHZXdva3txVMjkUHNs4Odi7BjE-M+Gyv9cxW7MwdrCyfjh956G7b2m6uTx6OPOze1L6dP75+XZ88sLZXRJEPZA-4-QGvI6QuqNcHfYRg6HXJEWBr7P6I0EfJYPL5vNG-bYwol40LkhoUuHU2mU+7lVFEAB6+XOjJB9AALmyfNheXoAJYC4QAZxFOI5QxgwqlnXFcvZzkJRFwCTCDPJytJRCaEvosu1TPohEVPgAJriaZEqVrrfa6RAbDYgA"));
}
},
watch: {
showOptionsModal(val) {
if (val === true) {
this.open();
}
if (val === false) {
this.close();
}
},
},
methods: {
open() {
this.$modal.show("about-modal");
},
close() {
this.$modal.hide("about-modal");
},
},
};
</script>

View File

@ -6,11 +6,11 @@
:esc-to-close="true"
@closed="$store.commit('closeModal', 'edit-ascii')"
>
Width
<!-- Width
<t-input type="number" name="width" v-model="layer.width" min="1" />
Height
<t-input type="number" name="height" v-model="layer.height" min="1" />
<t-input type="number" name="height" v-model="layer.height" min="1" /> -->
Title
<t-input type="text" name="title" v-model="layer.title" max="128" />

View File

@ -84,6 +84,7 @@ export default {
},
methods: {
open() {
this.$modal.show("new-ascii-modal");
this.forms.createAscii.title = `New ASCII ${
this.$store.getters.asciibirdMeta.length + 1

View File

@ -10,19 +10,20 @@ export default {
created() {
var _this = this;
hotkeys("Enter", function (event, handler) {
event.preventDefault();
// Enter events to confirm and close dialogs and modals
if (_this.isShowingDialog) {
_this.$dialog.hide("dialog-posthttp");
return;
}
});
// hotkeys("Enter", "editor", function (event, handler) {
// event.preventDefault();
// // Enter events to confirm and close dialogs and modals
// if (_this.isShowingDialog) {
// _this.$dialog.hide("dialog-posthttp");
// return;
// }
// });
hotkeys("*", "editor", function (event, handler) {
event.preventDefault();
if (_this.toolbarState.isChoosingChar && event.key.length === 1) {
if (_this.toolbarState.isChoosingChar && event.key.length === 1 && !_this.disableKeyboard) {
_this.$store.commit("changeChar", event.key);
return;
}
@ -60,7 +61,7 @@ export default {
}
});
hotkeys("Escape", function (event, handler) {
hotkeys("Escape", "editor", function (event, handler) {
if (
!_this.textEditing &&
(_this.toolbarState.isChoosingChar ||

View File

@ -267,8 +267,6 @@ export default {
this.$store.commit("toggleDisableKeyboard", false);
});
this.closeMenu();
},
updateLayerName(key, label) {
this.$store.commit("updateLayerName", {

View File

@ -29,6 +29,7 @@ export default new Vuex.Store({
pasteAscii: false,
options: false,
overlay: false,
about: false,
},
isKeyboardDisabled: false,
// The various options of ASCIIBIRD will eventually
@ -36,7 +37,7 @@ export default new Vuex.Store({
options: {
defaultBg: 1,
defaultFg: 0,
renderOffScreen: true,
renderOffScreen: false,
undoLimit: 50,
brushLimit: 50,
tabLimit: 12,
@ -569,9 +570,8 @@ export default new Vuex.Store({
let data = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
.history[historyIndex - 1].d));
console.log(data)
state.asciibirdMeta[state.tab].layers = LZString.compressToUTF16(JSON.stringify(data
state.asciibirdMeta[state.tab].layers = LZString.compressToUTF16(JSON.stringify(data
.old));
state.asciibirdMeta[state.tab].historyIndex--;
@ -631,7 +631,6 @@ export default new Vuex.Store({
let data = JSON.parse(LZString.decompressFromUTF16(state.asciibirdMeta[state.tab]
.history[historyIndex].d));
console.log(data)
state.asciibirdMeta[state.tab].layers = LZString.compressToUTF16(JSON.stringify(data
.old));
@ -794,6 +793,11 @@ export default new Vuex.Store({
state.modalState.overlay = true;
state.isKeyboardDisabled = true;
break;
case 'about':
state.modalState.about = true;
state.isKeyboardDisabled = true;
break;
}
},
closeModal(state, type) {
@ -823,6 +827,11 @@ export default new Vuex.Store({
state.modalState.overlay = false;
state.isKeyboardDisabled = false;
break;
case 'about':
state.modalState.about = false;
state.isKeyboardDisabled = false;
break;
}
},
closeTab(state, tab) {

View File

@ -110,7 +110,7 @@ export default {
});
var _this = this;
hotkeys("*", "editor", function (event, handler) {
hotkeys("*", "editor" , function (event, handler) {
event.preventDefault();
if (_this.isTextEditing) {
@ -386,7 +386,6 @@ export default {
}
},
resetSelect(val, old) {
console.log(val)
this.resetSelectTool();
},
currentSelectedLayer(val, old) {
@ -476,26 +475,26 @@ export default {
this.diffBlocks.l = val;
}
},
updateascii(val, old) {
if (val.width !== old.width || val.height !== old.height) {
let layers = fillNullBlocks(val.height, val.width);
// updateascii(val, old) {
// if (val.width !== old.width || val.height !== old.height) {
// let layers = fillNullBlocks(val.height, val.width);
this.canvas.width = val.width * blockWidth;
this.canvas.height = val.height * blockHeight;
// this.canvas.width = val.width * blockWidth;
// this.canvas.height = val.height * blockHeight;
this.$store.commit("changeAsciiWidthHeight", {
width: val.width,
height: val.height,
layers: [...layers],
});
// this.$store.commit("changeAsciiWidthHeight", {
// width: val.width,
// height: val.height,
// layers: [...layers],
// });
this.$refs.canvasdrag.width = val.width * blockWidth;
this.$refs.canvasdrag.height = val.height * blockHeight;
// this.$refs.canvasdrag.width = val.width * blockWidth;
// this.$refs.canvasdrag.height = val.height * blockHeight;
this.clearToolCanvas();
this.delayRedrawCanvas();
}
},
// this.clearToolCanvas();
// this.delayRedrawCanvas();
// }
// },
// Layers undo
currentAsciiLayers(val, old) {
this.delayRedrawCanvas(true);
@ -1942,9 +1941,9 @@ export default {
delete newColor["fg"];
}
if (!this.canText) {
delete newColor["char"];
}
// if (!this.canText) {
// delete newColor["char"];
// }
// If the newColor is same as the existing
// Then return the original image.
@ -1993,9 +1992,9 @@ export default {
return;
}
if (this.canText && targetBlock.char !== current.char) {
return;
}
// if (this.canText && targetBlock.char !== current.char) {
// return;
// }
// We can eraser or fill
let oldBlock = { ...targetBlock };