Use flex-based layout to reduce visual waste

This commit is contained in:
Florine W. Dekker 2022-11-23 13:47:48 +01:00
parent afcbf7f94e
commit 7789363797
Signed by: FWDekker
GPG Key ID: D3DCFAA8A4560BE0
6 changed files with 76 additions and 50 deletions

View File

@ -7,18 +7,21 @@ module.exports = grunt => {
default: ["dist/"], default: ["dist/"],
}, },
copy: { copy: {
css: {
files: [{expand: true, cwd: "src/main/", src: "**/*.css", dest: "dist/", flatten: true}],
},
html: { html: {
files: [{expand: true, cwd: "src/main/", src: "**/*.html", dest: "dist/", flatten: true}] files: [{expand: true, cwd: "src/main/", src: "**/*.html", dest: "dist/", flatten: true}],
}, },
}, },
focus: { focus: {
dev: { dev: {
include: ["html", "js"], include: ["css", "html", "js"],
}, },
}, },
replace: { replace: {
dev: { dev: {
src: ["./dist/*.html", "./dist/*.js"], src: ["./dist/**/*.html", "./dist/**/*.js"],
replacements: [ replacements: [
{ {
from: "%%VERSION_NUMBER%%", from: "%%VERSION_NUMBER%%",
@ -28,7 +31,7 @@ module.exports = grunt => {
overwrite: true overwrite: true
}, },
deploy: { deploy: {
src: ["./dist/*.html", "./dist/*.js"], src: ["./dist/**/*.html", "./dist/**/*.js"],
replacements: [ replacements: [
{ {
from: "%%VERSION_NUMBER%%", from: "%%VERSION_NUMBER%%",
@ -39,6 +42,10 @@ module.exports = grunt => {
}, },
}, },
watch: { watch: {
css: {
files: ["src/main/**/*.css"],
tasks: ["copy:css"],
},
html: { html: {
files: ["src/main/**/*.html"], files: ["src/main/**/*.html"],
tasks: ["copy:html"], tasks: ["copy:html"],
@ -88,6 +95,7 @@ module.exports = grunt => {
// Pre // Pre
"clean", "clean",
// Copy files // Copy files
"copy:css",
"copy:html", "copy:html",
// Compile JS // Compile JS
"webpack:dev", "webpack:dev",
@ -98,6 +106,7 @@ module.exports = grunt => {
// Pre // Pre
"clean", "clean",
// Copy files // Copy files
"copy:css",
"copy:html", "copy:html",
// Compile JS // Compile JS
"webpack:deploy", "webpack:deploy",

BIN
package-lock.json generated

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "converter", "name": "converter",
"version": "1.4.14", "version": "1.5.0",
"description": "Convert numbers to and from various bases.", "description": "Convert numbers to and from various bases.",
"author": "Florine W. Dekker", "author": "Florine W. Dekker",
"browser": "dist/bundle.js", "browser": "dist/bundle.js",

16
src/main/css/main.css Normal file
View File

@ -0,0 +1,16 @@
#inputs {
display: flex;
flex-wrap: wrap;
align-items: start;
justify-content: left;
/*noinspection CssUnresolvedCustomProperty*/
gap: var(--spacing);
}
#inputs article {
margin: 0;
}
#inputs textarea {
display: block;
}

View File

@ -8,6 +8,7 @@
<meta name="description" content="Convert numbers to and from various bases." /> <meta name="description" content="Convert numbers to and from various bases." />
<meta name="theme-color" content="#0033cc" /> <meta name="theme-color" content="#0033cc" />
<meta name="fwd:auto:show-main" />
<meta name="fwd:nav:target" content="#nav" /> <meta name="fwd:nav:target" content="#nav" />
<meta name="fwd:nav:highlight-path" content="/Tools/Converter/" /> <meta name="fwd:nav:highlight-path" content="/Tools/Converter/" />
<meta name="fwd:footer:target" content="#footer" /> <meta name="fwd:footer:target" content="#footer" />
@ -17,6 +18,8 @@
<title>Converter | FWDekker</title> <title>Converter | FWDekker</title>
<link rel="stylesheet" href="https://static.fwdekker.com/lib/template/3.x.x/template.css?v=%%VERSION_NUMBER%%" /> <link rel="stylesheet" href="https://static.fwdekker.com/lib/template/3.x.x/template.css?v=%%VERSION_NUMBER%%" />
<!--suppress HtmlUnknownTarget -->
<link rel="stylesheet" href="main.css?v=%%VERSION_NUMBER%%" />
<script async src="https://stats.fwdekker.com/count.js" <script async src="https://stats.fwdekker.com/count.js"
data-goatcounter="https://stats.fwdekker.com/count"></script> data-goatcounter="https://stats.fwdekker.com/count"></script>
</head> </head>
@ -31,19 +34,24 @@
</p> </p>
</noscript> </noscript>
<nav id="nav"></nav> <nav id="nav"></nav>
<main class="container hidden"> <main class="hidden">
<div role="document"> <div role="document">
<section> <section class="container">
<header class="fwd-header"> <header class="fwd-header">
<hgroup> <hgroup>
<h1><a href=".">Converter</a></h1> <h1><a href=".">Converter</a></h1>
<h2>Convert numbers to and from various bases.</h2> <h2>Convert numbers to and from various bases.</h2>
</hgroup> </hgroup>
</header> </header>
<form id="inputs"></form>
</section> </section>
<footer id="footer"></footer>
<section class="container-fluid">
<form id="inputs" class="grid"></form>
</section>
<section class="container">
<footer id="footer"></footer>
</section>
</div> </div>
</main> </main>

View File

@ -1,5 +1,5 @@
// noinspection JSUnresolvedVariable // noinspection JSUnresolvedVariable
const {$, doAfterLoad} = window.fwdekker; const {$, doAfterLoad, stringToHtml} = window.fwdekker;
import bigInt from "big-integer" import bigInt from "big-integer"
@ -11,8 +11,9 @@ import bigInt from "big-integer"
* @param replacement the replacement to insert into the string * @param replacement the replacement to insert into the string
* @returns {string} the input string with one character replaced * @returns {string} the input string with one character replaced
*/ */
const stringReplaceAt = (str, index, replacement) => function stringReplaceAt(str, index, replacement) {
str.substring(0, index) + replacement + str.substring(index + replacement.length); return str.substring(0, index) + replacement + str.substring(index + replacement.length);
}
/** /**
* Replaces all instances of the target with the replacement. * Replaces all instances of the target with the replacement.
@ -22,8 +23,9 @@ const stringReplaceAt = (str, index, replacement) =>
* @param replacement the replacement to insert into the string * @param replacement the replacement to insert into the string
* @returns {string} the input string with all instances of the target replaced * @returns {string} the input string with all instances of the target replaced
*/ */
const stringReplaceAll = (str, target, replacement) => function stringReplaceAll(str, target, replacement) {
str.split(target).join(replacement); return str.split(target).join(replacement);
}
/** /**
* Runs `stringReplaceAll` for each character in `targets` and `replacements`. * Runs `stringReplaceAll` for each character in `targets` and `replacements`.
@ -34,9 +36,10 @@ const stringReplaceAll = (str, target, replacement) =>
* in the targets string * in the targets string
* @returns {string} the input string with all instances of the targets replaced * @returns {string} the input string with all instances of the targets replaced
*/ */
const stringReplaceAlls = (str, targets, replacements) => function stringReplaceAlls(str, targets, replacements) {
Array.from(targets).reduce((output, target, index) => return Array.from(targets)
stringReplaceAll(output, target, replacements[index]), str); .reduce((output, target, index) => stringReplaceAll(output, target, replacements[index]), str);
}
class NumeralSystem { class NumeralSystem {
@ -71,26 +74,25 @@ class NumeralSystemInput {
this.name = name; this.name = name;
this.numeralSystem = numeralSystem; this.numeralSystem = numeralSystem;
this.label = document.createElement("label"); this.label = stringToHtml(`<label for="${this.name}-input">${this.name}</label>`);
this.label.setAttribute("for", `${this.name}Input`);
this.label.innerHTML = this.name;
this.textarea = document.createElement("textarea"); this.textarea = stringToHtml(`<textarea id="${this.name}-input" class="number-input"></textarea>`);
this.textarea.id = `${this.name}Input`;
this.textarea.className = "numberInput";
this.textarea.oninput = () => { this.textarea.oninput = () => {
if (this.textarea.value === undefined || this.textarea.value === null || this.textarea.value === "") if (this.textarea.value == null || this.textarea.value === "")
return; return;
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value); this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
updateAllInputs(this, this.numeralSystem.baseToDecimal(this.textarea.value)); updateAllInputs(this, this.numeralSystem.baseToDecimal(this.textarea.value));
}; };
this.wrapper = document.createElement("article");
this.wrapper.appendChild(this.label);
this.wrapper.appendChild(this.textarea);
} }
addToParent(parent) { addToParent(parent) {
parent.appendChild(this.label); parent.appendChild(this.wrapper);
parent.appendChild(this.textarea);
} }
update(decimalNumber) { update(decimalNumber) {
@ -98,6 +100,7 @@ class NumeralSystemInput {
} }
} }
class Base64NumeralSystem extends NumeralSystem { class Base64NumeralSystem extends NumeralSystem {
// TODO Convert static methods to static properties once supported by Firefox // TODO Convert static methods to static properties once supported by Firefox
static defaultAlphabet() { static defaultAlphabet() {
@ -148,20 +151,21 @@ class Base64NumeralSystemInput extends NumeralSystemInput {
constructor(name) { constructor(name) {
super(name, new Base64NumeralSystem(Base64NumeralSystem.defaultAlphabet())); super(name, new Base64NumeralSystem(Base64NumeralSystem.defaultAlphabet()));
this.dropdown = document.createElement("select"); this.dropdown = stringToHtml(`<select id="${this.name}-dropdown"></select>`);
this.dropdown.id = `${this.name}-dropdown`;
this.dropdown.onchange = () => { this.dropdown.onchange = () => {
const selectedOption = Base64NumeralSystemInput.dropdownOptions()[this.dropdown.value]; const selectedOption = Base64NumeralSystemInput.dropdownOptions()[this.dropdown.value];
this.setLastDigits(selectedOption[0], selectedOption[1]); this.setLastDigits(selectedOption[0], selectedOption[1]);
}; };
this.options = Object
Object.keys(Base64NumeralSystemInput.dropdownOptions()).map(key => { .keys(Base64NumeralSystemInput.dropdownOptions())
const option = document.createElement("option"); .forEach(key => {
option.value = key; const text = key + ": " + Base64NumeralSystemInput.dropdownOptions()[key].join("");
option.text = key + ": " + Base64NumeralSystemInput.dropdownOptions()[key].join(""); const option = stringToHtml(`<option value="${key}">${text}</option>`);
return option; this.dropdown.appendChild(option);
}); });
this.wrapper.appendChild(this.dropdown);
} }
@ -174,14 +178,6 @@ class Base64NumeralSystemInput extends NumeralSystemInput {
this.textarea.value = this.textarea.value =
stringReplaceAll(stringReplaceAll(this.textarea.value, oc62, c62), oc63, c63); stringReplaceAll(stringReplaceAll(this.textarea.value, oc62, c62), oc63, c63);
} }
addToParent(parent) {
this.options.forEach(option => this.dropdown.appendChild(option));
parent.appendChild(this.label);
parent.appendChild(this.dropdown);
parent.appendChild(this.textarea);
}
} }
@ -202,21 +198,18 @@ const inputs = [
), ),
]; ];
const updateAllInputs = (source, newValue) => { function updateAllInputs(source, newValue) {
for (const input of inputs) for (const input of inputs)
if (input !== source) if (input !== source)
input.update(newValue); input.update(newValue);
}; }
doAfterLoad(() => { doAfterLoad(() => {
const inputParent = $("#inputs"); const form = $("#inputs");
for (const input of inputs) for (const input of inputs)
input.addToParent(inputParent); input.addToParent(form);
updateAllInputs(undefined, bigInt(42)); updateAllInputs(undefined, bigInt(42));
inputs[0].textarea.focus(); inputs[0].textarea.focus();
$("main").classList.remove("hidden");
}); });