Replace the Vue frontend with Svelte

This commit is contained in:
Keavon Chambers
2023-03-10 03:54:39 -08:00
parent e539e43483
commit 6e20ea538b
83 changed files with 10013 additions and 19687 deletions
@@ -1,194 +1,198 @@
<script lang="ts">
import { defineComponent, type PropType } from "vue";
import { createEventDispatcher } from "svelte";
import { platformIsMac } from "@/utility-functions/platform";
import { platformIsMac } from "@/utility-functions/platform";
import LayoutRow from "@/components/layout/LayoutRow.vue";
import LayoutRow from "@/components/layout/LayoutRow.svelte";
export default defineComponent({
emits: ["update:value", "textFocused", "textChanged", "cancelTextChange"],
props: {
value: { type: String as PropType<string>, required: true },
label: { type: String as PropType<string>, required: false },
spellcheck: { type: Boolean as PropType<boolean>, default: false },
disabled: { type: Boolean as PropType<boolean>, default: false },
textarea: { type: Boolean as PropType<boolean>, default: false },
tooltip: { type: String as PropType<string | undefined>, required: false },
sharpRightCorners: { type: Boolean as PropType<boolean>, default: false },
placeholder: { type: String as PropType<string>, required: false },
},
data() {
return {
id: `${Math.random()}`.substring(2),
macKeyboardLayout: platformIsMac(),
};
},
methods: {
// Select (highlight) all the text. For technical reasons, it is necessary to pass the current text.
selectAllText(currentText: string) {
const inputElement = this.$refs.input as HTMLInputElement | HTMLTextAreaElement | undefined;
if (!inputElement) return;
// emits: ["update:value", "textFocused", "textChanged", "cancelTextChange"],
const dispatch = createEventDispatcher<{
value: string;
textFocused: undefined;
textChanged: undefined;
cancelTextChange: undefined;
}>();
// Setting the value directly is required to make `inputElement.select()` work
inputElement.value = currentText;
let className = "";
export { className as class };
export let classes: Record<string, boolean> = {};
let styleName = "";
export { styleName as style };
export let styles: Record<string, string | number | undefined> = {};
export let value: string;
export let label: string | undefined = undefined;
export let spellcheck = false;
export let disabled = false;
export let textarea = false;
export let tooltip: string | undefined = undefined;
export let sharpRightCorners = false;
export let placeholder: string | undefined = undefined;
inputElement.select();
},
unFocus() {
(this.$refs.input as HTMLInputElement | HTMLTextAreaElement | undefined)?.blur();
},
getInputElementValue(): string | undefined {
return (this.$refs.input as HTMLInputElement | HTMLTextAreaElement | undefined)?.value;
},
setInputElementValue(value: string) {
const inputElement = this.$refs.input as HTMLInputElement | HTMLTextAreaElement | undefined;
if (inputElement) inputElement.value = value;
},
},
computed: {
inputValue: {
get() {
return this.value;
},
set(value: string) {
this.$emit("update:value", value);
},
},
},
components: { LayoutRow },
});
let inputOrTextarea: HTMLInputElement | HTMLTextAreaElement;
let id = `${Math.random()}`.substring(2);
let macKeyboardLayout = platformIsMac();
$: inputValue = value;
$: dispatch("value", inputValue);
// Select (highlight) all the text. For technical reasons, it is necessary to pass the current text.
export function selectAllText(currentText: string) {
// Setting the value directly is required to make the following `select()` call work
inputOrTextarea.value = currentText;
inputOrTextarea.select();
}
export function focus() {
inputOrTextarea.focus();
}
export function unFocus() {
inputOrTextarea.blur();
}
export function getValue(): string {
return inputOrTextarea.value;
}
export function setInputElementValue(value: string) {
inputOrTextarea.value = value;
}
export function element(): HTMLInputElement | HTMLTextAreaElement {
return inputOrTextarea;
}
</script>
<!-- This is a base component, extended by others like NumberInput and TextInput. It should not be used directly. -->
<template>
<LayoutRow class="field-input" :class="{ disabled, 'sharp-right-corners': sharpRightCorners }" :title="tooltip">
<LayoutRow class={`field-input ${className}`} classes={{ disabled, "sharp-right-corners": sharpRightCorners, ...classes }} style={styleName} {styles} {tooltip}>
{#if !textarea}
<input
type="text"
v-if="!textarea"
:class="{ 'has-label': label }"
:id="`field-input-${id}`"
ref="input"
v-model="inputValue"
:spellcheck="spellcheck"
:disabled="disabled"
:placeholder="placeholder"
@focus="() => $emit('textFocused')"
@blur="() => $emit('textChanged')"
@change="() => $emit('textChanged')"
@keydown.enter="() => $emit('textChanged')"
@keydown.esc="() => $emit('cancelTextChange')"
class:has-label={label}
id={`field-input-${id}`}
{spellcheck}
{disabled}
{placeholder}
bind:value={inputValue}
bind:this={inputOrTextarea}
on:focus={() => dispatch("textFocused")}
on:blur={() => dispatch("textChanged")}
on:change={() => dispatch("textChanged")}
on:keydown={(e) => e.key === "Enter" && dispatch("textChanged")}
on:keydown={(e) => e.key === "Escape" && dispatch("cancelTextChange")}
data-input-element
/>
{:else}
<textarea
v-else
:class="{ 'has-label': label }"
:id="`field-input-${id}`"
class:has-label={label}
id={`field-input-${id}`}
class="scrollable-y"
data-scrollable-y
ref="input"
v-model="inputValue"
:spellcheck="spellcheck"
:disabled="disabled"
@focus="() => $emit('textFocused')"
@blur="() => $emit('textChanged')"
@change="() => $emit('textChanged')"
@keydown.ctrl.enter="() => !macKeyboardLayout && $emit('textChanged')"
@keydown.meta.enter="() => macKeyboardLayout && $emit('textChanged')"
@keydown.esc="() => $emit('cancelTextChange')"
></textarea>
<label v-if="label" :for="`field-input-${id}`">{{ label }}</label>
<slot></slot>
</LayoutRow>
</template>
{spellcheck}
{disabled}
bind:value={inputValue}
bind:this={inputOrTextarea}
on:focus={() => dispatch("textFocused")}
on:blur={() => dispatch("textChanged")}
on:change={() => dispatch("textChanged")}
on:keydown={(e) => (macKeyboardLayout ? e.metaKey : e.ctrlKey) && e.key === "Enter" && dispatch("textChanged")}
on:keydown={(e) => e.key === "Escape" && dispatch("cancelTextChange")}
/>
{/if}
{#if label}
<label for={`field-input-${id}`}>{label}</label>
{/if}
<slot />
</LayoutRow>
<style lang="scss">
.field-input {
min-width: 80px;
height: auto;
position: relative;
border-radius: 2px;
background: var(--color-1-nearblack);
overflow: hidden;
flex-direction: row-reverse;
label {
flex: 0 0 auto;
line-height: 18px;
padding: 3px 0;
padding-right: 4px;
margin-left: 8px;
<style lang="scss" global>
.field-input {
min-width: 80px;
height: auto;
position: relative;
border-radius: 2px;
background: var(--color-1-nearblack);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
flex-direction: row-reverse;
&:not(.disabled) label {
cursor: text;
}
label {
flex: 0 0 auto;
line-height: 18px;
padding: 3px 0;
padding-right: 4px;
margin-left: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
input,
textarea {
flex: 1 1 100%;
width: 0;
min-width: 30px;
height: 18px;
line-height: 18px;
margin: 0 8px;
padding: 3px 0;
outline: none; // Ok for input/textarea element
border: none;
background: none;
color: var(--color-e-nearwhite);
caret-color: var(--color-e-nearwhite);
&:not(.disabled) label {
cursor: text;
}
&::selection {
background-color: var(--color-5-dullgray);
input,
textarea {
flex: 1 1 100%;
width: 0;
min-width: 30px;
height: 18px;
line-height: 18px;
margin: 0 8px;
padding: 3px 0;
outline: none; // Ok for input/textarea element
border: none;
background: none;
color: var(--color-e-nearwhite);
caret-color: var(--color-e-nearwhite);
// Target only Safari
@supports (background: -webkit-named-image(i)) {
& {
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
// https://stackoverflow.com/a/71753552/775283
background-color: rgba(var(--color-5-dullgray-rgb), calc(254 / 255));
&::selection {
background-color: var(--color-5-dullgray);
// Target only Safari
@supports (background: -webkit-named-image(i)) {
& {
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
// https://stackoverflow.com/a/71753552/775283
background-color: rgba(var(--color-5-dullgray-rgb), calc(254 / 255));
}
}
}
}
}
input {
text-align: center;
input {
// text-align: center;
&:not(:focus).has-label {
text-align: right;
margin-left: 0;
margin-right: 8px;
&:not(:focus).has-label {
text-align: right;
margin-left: 0;
margin-right: 8px;
}
&:focus {
text-align: left;
& + label {
display: none;
}
}
}
&:focus {
text-align: left;
textarea {
min-height: calc(18px * 3);
margin: 3px;
padding: 0 5px;
box-sizing: border-box;
resize: vertical;
}
& + label {
display: none;
&.disabled {
background: var(--color-2-mildblack);
label,
input,
textarea {
color: var(--color-8-uppergray);
}
}
}
textarea {
min-height: calc(18px * 3);
margin: 3px;
padding: 0 5px;
box-sizing: border-box;
resize: vertical;
}
&.disabled {
background: var(--color-2-mildblack);
label,
input,
textarea {
color: var(--color-8-uppergray);
}
}
}
</style>