Clean things up a bit before uploading to the web

This commit is contained in:
Jordan Goulder 2025-01-12 22:20:42 -05:00
parent 222743e60d
commit 721750e91e
9 changed files with 172 additions and 81 deletions

View File

@ -8,14 +8,13 @@ import PlaygroundView from '@/components/PlaygroundView.vue'
const routes: { [index: string]: Component } = { const routes: { [index: string]: Component } = {
'/': HomeView, '/': HomeView,
play: PlaygroundView, '/play': PlaygroundView,
} }
const currentPath = ref<string>(window.location.hash) const currentPath = ref<string>(window.location.hash)
window.addEventListener('hashchange', () => { window.addEventListener('hashchange', () => {
currentPath.value = window.location.hash currentPath.value = window.location.hash
console.log(currentPath.value)
}) })
</script> </script>

View File

@ -1,21 +1,30 @@
:root {
--bg-color: #141414;
--fg-color: #ff00ff;
--fg-color-header: #00ffff;
--fg-color-link: #ffff40;
--fg-color-link-visited: #ff8040;
}
html, html,
body { body {
font-family: monospace; font-family: 'Courier New', monospace;
background: black; background: var(--bg-color);
color: #ff00ff; color: var(--fg-color);
font-size: 12pt; font-size: 12pt;
margin: auto; margin: auto;
padding: 0.5em; padding: 0.5em;
} }
input,
button { button {
font: inherit; font-family: 'Courier New', monospace;
margin: 0.5em 0;
padding: 0.5em 0.75em;
} }
progress::-webkit-progress-bar, progress::-webkit-progress-bar,
progress::-moz-progress-bar { progress::-moz-progress-bar {
background: #ff00ff; background: var(--fg-color);
} }
h1, h1,
@ -24,13 +33,26 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
color: #00ffff; margin: 0 0 0.25em;
color: var(--fg-color-header);
} }
a { a {
color: #4040ff; color: var(--fg-color-link);
} }
a:visited { a:visited {
color: #ff4040; color: var(--fg-color-link-visited);
}
section {
margin-top: 2em;
}
section h2,
h3,
h4,
h5,
h6 {
border-bottom: 2px solid color(from var(--fg-color-header) srgb r g b / 30%);
} }

View File

@ -1,20 +1,20 @@
<script lang="ts" setup></script> <script lang="ts" setup></script>
<template> <template>
<span class="blink"> <span class="blink"><slot /></span>
<slot />
</span>
</template> </template>
<style scoped> <style scoped>
.blink { @media (prefers-reduced-motion: no-preference) {
display: inline-block; .blink {
animation: blinker 2s ease-in-out infinite;
}
@keyframes blinker {
50% {
opacity: 0; opacity: 0;
animation: blinker 2s ease-in-out 10;
}
@keyframes blinker {
50% {
opacity: 1;
}
} }
} }
</style> </style>

View File

@ -1,12 +1,22 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useTemplateRef } from 'vue'
const emit = defineEmits<{ const emit = defineEmits<{
start: [name: string] start: [name: string]
progress: [loaded: number, total: number] progress: [read: number, total: number]
load: [data: ArrayBuffer] success: [data: ArrayBuffer]
error: [message: string] error: [message: string]
}>() }>()
async function handleFiles(event: Event) { const MAX_FILE_SIZE = 1440 * 1024
const fileInput = useTemplateRef('file-input')
async function onOpenClick() {
fileInput.value?.click()
}
async function onFileChange(event: Event) {
const files = (event.target as HTMLInputElement).files const files = (event.target as HTMLInputElement).files
if (!files?.length) { if (!files?.length) {
return return
@ -14,18 +24,28 @@ async function handleFiles(event: Event) {
try { try {
const data = await readFile(files[0]) const data = await readFile(files[0])
emit('load', data) emit('success', data)
} catch (error) { } catch (e) {
emit('error', error as string) let error
if (!(e instanceof Error)) {
error = new Error('' + e)
} else {
error = e
}
emit('error', error.message)
} }
} }
async function readFile(file: File): Promise<ArrayBuffer> { function readFile(file: File): Promise<ArrayBuffer> {
return await new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (file.size > MAX_FILE_SIZE) {
reject(new Error('Maximum file size exceeded'))
return
}
const reader = new FileReader() const reader = new FileReader()
reader.onloadstart = () => { reader.onloadstart = (event: ProgressEvent) => {
emit('start', file.name) emit('progress', event.loaded, event.total)
} }
reader.onprogress = (event: ProgressEvent) => { reader.onprogress = (event: ProgressEvent) => {
@ -39,22 +59,28 @@ async function readFile(file: File): Promise<ArrayBuffer> {
} }
reader.onerror = () => { reader.onerror = () => {
reject('load error') reject(`read error`)
} }
reader.onabort = () => { reader.onabort = () => {
reject('load aborted') reject('read aborted')
} }
reader.readAsArrayBuffer(file) reader.readAsArrayBuffer(file)
emit('start', file.name)
}) })
} }
</script> </script>
<template> <template>
<form> <div>
<input id="disk-file" type="file" @change="handleFiles" /> <input id="disk-file" ref="file-input" type="file" @change="onFileChange" />
</form> <button type="button" @click="onOpenClick">Open a disk image...</button>
</div>
</template> </template>
<style scoped></style> <style scoped>
input[type='file'] {
display: none;
}
</style>

View File

@ -10,6 +10,10 @@ const hexDump = computed(() => {
let offset = 0 let offset = 0
const total = buffer.byteLength const total = buffer.byteLength
if (total === 0) {
return ''.padEnd(80, ' ')
}
while (offset < total) { while (offset < total) {
const values = [offset.toString(16).padStart(8, '0')] const values = [offset.toString(16).padStart(8, '0')]
const asciiValues: string[] = [] const asciiValues: string[] = []
@ -77,6 +81,7 @@ pre {
height: 20rem; height: 20rem;
max-height: 20rem; max-height: 20rem;
background: rgba(255, 255, 255, 0.15); background: rgba(255, 255, 255, 0.15);
color: #c0c0c0;
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
} }
</style> </style>

View File

@ -3,15 +3,29 @@
<template> <template>
<header> <header>
<h1>Floppy Drive</h1> <h1>Floppy Drive</h1>
<p>Coming soonish...</p> <p>Load floppy disk(images) right from your browser.</p>
</header> </header>
<section> <section>
<h2>The Idea</h2> <h2>What is it?</h2>
<p> <p>
Allow visitors to upload floppy disk images so that they can browse, view, and download the A website that lets you upload floppy disk images so you can browse, view, and download the
files stored on them. files stored on them.
</p> </p>
</section> </section>
<section>
<h2>Is is ready yet?</h2>
<p>Everything is still very much a work in progress.</p>
<p>
Feel free to <a href="/#/play">play around</a> with some of the things I am working on, but
understand that it is <strong>NOT</strong> working yet.
</p>
</section>
</template> </template>
<style scoped></style> <style scoped>
header p {
margin: 0;
font-style: italic;
font-size: 0.95em;
}
</style>

View File

@ -2,7 +2,7 @@
<template> <template>
<section> <section>
<h2>Page Not Found</h2> <h2>Oops... Page Not Found</h2>
<p>I couldn't seem to find that.</p> <p>I couldn't seem to find that.</p>
<p>You should probably just head back <a href="/">Home</a>.</p> <p>You should probably just head back <a href="/">Home</a>.</p>
</section> </section>

View File

@ -3,66 +3,89 @@ import { ref } from 'vue'
import DiskReader from '@/components/DiskReader.vue' import DiskReader from '@/components/DiskReader.vue'
import HexDump from '@/components/HexDump.vue' import HexDump from '@/components/HexDump.vue'
const loadName = ref('') type DiskReadyState = 'empty' | 'read-started' | 'read-success' | 'read-failed'
const loadTotal = ref(0)
const loadLoaded = ref(0)
const loadData = ref(new ArrayBuffer(0))
function handleStart(name: string) { const diskReadyState = ref<DiskReadyState>('empty')
console.log(`Loading file: ${name}`) const diskName = ref('')
loadName.value = name const diskTotalBytes = ref(0)
loadLoaded.value = 0 const diskReadBytes = ref(0)
loadTotal.value = -1 const diskReadError = ref('')
const diskData = ref(new ArrayBuffer(0))
function onReadStart(name: string) {
console.log(`Reading disk from ${name}`)
diskReadyState.value = 'read-started'
diskName.value = name
diskReadBytes.value = 0
diskTotalBytes.value = -1
} }
function handleLoad(data: ArrayBuffer) { function onReadSuccess(data: ArrayBuffer) {
console.log('File loaded') console.log('Disk read succeeded')
loadData.value = data diskReadyState.value = 'read-success'
diskData.value = data
} }
function handleError(message: string) { function onReadError(message: string) {
console.log('Error loading file' + message) console.log('Disk read failed: ' + message)
loadLoaded.value = -1 diskData.value = new ArrayBuffer(0)
loadTotal.value = -1 diskReadError.value = message
diskReadyState.value = 'read-failed'
diskReadBytes.value = -1
diskTotalBytes.value = -1
} }
function handleProgress(loaded: number, total: number) { function onReadProgress(read: number, total: number) {
loadLoaded.value = loaded diskReadBytes.value = read
loadTotal.value = total diskTotalBytes.value = total
} }
</script> </script>
<template> <template>
<nav>
<a href="/#/">Home</a>
</nav>
<section> <section>
<h2>Playground</h2> <h2>Playground</h2>
<p>This is my playground for testing out my code.</p> <p>This is my playground for testing out my code.</p>
<p>
<strong><em>WARNING!!!</em> Use at your own risk!</strong>
</p>
<section> <section>
<h3>Disk Upload</h3> <h3>Disk Read</h3>
<DiskReader <div class="cols">
@error="handleError" <DiskReader
@load="handleLoad" @error="onReadError"
@progress="handleProgress" @progress="onReadProgress"
@start="handleStart" @start="onReadStart"
/> @success="onReadSuccess"
<div v-if="loadName"> />
Loading {{ loadName }} <div v-if="diskReadyState === 'read-started'">
<progress :max="loadTotal" :value="loadLoaded"> {{ diskName }} reading
{{ ((loadLoaded / loadTotal) * 100.0).toFixed(2) }} % <progress :max="diskTotalBytes" :value="diskReadBytes">
</progress> {{ ((diskReadBytes / diskTotalBytes) * 100.0).toFixed(2) }} %
{{ ((loadLoaded / loadTotal) * 100.0).toFixed(2) }} % </progress>
{{ ((diskReadBytes / diskTotalBytes) * 100.0).toFixed(2) }} %
</div>
<div v-else-if="diskReadyState === 'read-success'">{{ diskName }} loaded</div>
<div v-else-if="diskReadyState === 'read-failed'">
error reading disk: {{ diskReadError }}
</div>
<div v-else>No disk loaded</div>
</div> </div>
</section> </section>
<section> <section>
<h3>Disk Hex Dump</h3> <h3>Disk Hex Dump</h3>
<HexDump :buffer="loadData" /> <HexDump :buffer="diskData" />
</section> </section>
</section> </section>
</template> </template>
<style scoped> <style scoped>
progress { .cols {
margin-top: 1em; display: flex;
margin-left: 1em; flex-direction: row;
margin-right: 0.25em; align-items: baseline;
gap: 1em;
} }
</style> </style>

View File

@ -5,8 +5,9 @@ import BlinkingText from '@/components/BlinkingText.vue'
<template> <template>
<header> <header>
<pre> <pre>
A:\> DIR Welcome to Floppy Drive!
A:\> DIR
General failure reading drive A General failure reading drive A
Abort, Retry, Fail? <BlinkingText>&block;</BlinkingText> Abort, Retry, Fail? <BlinkingText>&block;</BlinkingText>
</pre> </pre>
@ -17,7 +18,8 @@ Abort, Retry, Fail? <BlinkingText>&block;</BlinkingText>
pre { pre {
font-weight: bold; font-weight: bold;
transform: skewX(-3deg); transform: skewX(-3deg);
text-shadow: 0 0 5px #0f8; text-shadow: 0 0 5px #80ff80;
color: #0f0; color: #0f0;
font-size: 0.85em;
} }
</style> </style>