Improve text-printing UI
- UI elements are now inside a form - ctrl+enter on textarea submits the form - UI becomes greyed-out while printing, as visual feedback
This commit is contained in:
parent
0dd973c5d6
commit
fe906d9242
1 changed files with 57 additions and 8 deletions
|
|
@ -1,11 +1,37 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { computed, ref, type StyleValue, useTemplateRef } from "vue";
|
||||||
|
|
||||||
|
const form = useTemplateRef<HTMLFormElement>("form");
|
||||||
|
const disabled = ref(false);
|
||||||
|
|
||||||
const text = ref("");
|
const text = ref("");
|
||||||
const forceWrap = ref(false);
|
const forceWrap = ref(false);
|
||||||
const feed = ref(true);
|
const feed = ref(true);
|
||||||
|
|
||||||
|
// Emulate how typst is wrapping text.
|
||||||
|
const textareaStyle = computed<StyleValue>(() =>
|
||||||
|
forceWrap.value ? { wordBreak: "break-all" } : { overflowWrap: "normal" },
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ctrl+Enter in textarea should submit form.
|
||||||
|
function textareaKeypress(ev: KeyboardEvent): void {
|
||||||
|
if (ev.ctrlKey && ev.key === "Enter") {
|
||||||
|
form.value?.requestSubmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitAtLeast(duration: number, since: number): Promise<void> {
|
||||||
|
const now = Date.now();
|
||||||
|
const wait = duration - (now - since);
|
||||||
|
if (wait > 0) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, wait));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function submit(): Promise<void> {
|
async function submit(): Promise<void> {
|
||||||
|
const start = Date.now();
|
||||||
|
disabled.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = new URLSearchParams();
|
const data = new URLSearchParams();
|
||||||
data.append("text", text.value);
|
data.append("text", text.value);
|
||||||
|
|
@ -16,28 +42,51 @@ async function submit(): Promise<void> {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("POST failed:", err);
|
console.log("POST failed:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await waitAtLeast(500, start);
|
||||||
|
disabled.value = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<form ref="form" @submit.prevent="submit">
|
||||||
<h2>Text</h2>
|
<h2>Text</h2>
|
||||||
<textarea v-model="text" rows="10"></textarea>
|
<!-- For some reason one col = 2 characters. -->
|
||||||
|
<textarea
|
||||||
|
v-model="text"
|
||||||
|
rows="10"
|
||||||
|
cols="24"
|
||||||
|
:style="textareaStyle"
|
||||||
|
:disabled
|
||||||
|
@keypress="textareaKeypress"
|
||||||
|
></textarea>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label><input v-model="forceWrap" type="checkbox" /> Force-Wrap</label>
|
<label>
|
||||||
<label><input v-model="feed" type="checkbox" /> Feed</label>
|
<input v-model="forceWrap" type="checkbox" :disabled />
|
||||||
|
Force-Wrap
|
||||||
|
</label>
|
||||||
|
<label><input v-model="feed" type="checkbox" :disabled /> Feed</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<button @click="submit">Print</button>
|
<button :disabled>Print</button>
|
||||||
</section>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
section {
|
form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
align-self: center;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
/* Prevent manual resizing from changing the width. */
|
||||||
|
min-width: fit-content;
|
||||||
|
max-width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue