mirror of https://github.com/raftario/filite.git
Web UI advancements
This commit is contained in:
parent
1b2c1b1199
commit
e60e3d625f
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"quoteProps": "consistent",
|
||||
"jsxSingleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "always",
|
||||
"requirePragma": false,
|
||||
"insertPragma": false,
|
||||
"proseWrap": "never",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"endOfLine": "lf"
|
||||
}
|
|
@ -1,11 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style>
|
||||
{{ css }}
|
||||
</style>
|
||||
<title>filite</title>
|
||||
</head>
|
||||
<body>
|
||||
Hello world!
|
||||
<nav>
|
||||
<div id="files-tab" role="tab"><span>Files</span></div>
|
||||
<div id="links-tab" class="active" role="tab">
|
||||
<span>Links</span>
|
||||
</div>
|
||||
<div id="texts-tab" role="tab"><span>Texts</span></div>
|
||||
</nav>
|
||||
<main>
|
||||
<div id="files-form">
|
||||
<label for="files-url">URL</label>
|
||||
<input
|
||||
id="files-url"
|
||||
class="mb1"
|
||||
type="text"
|
||||
placeholder="a1b2c3"
|
||||
required
|
||||
/>
|
||||
<label for="files-file">File</label>
|
||||
<input id="files-file" type="file" hidden />
|
||||
<div class="mb2">
|
||||
<button id="files-browse">Browse</button
|
||||
><input id="files-value" type="text" required />
|
||||
</div>
|
||||
<button id="files-submit" disabled>Submit</button>
|
||||
</div>
|
||||
<div id="links-form" class="active">
|
||||
<label for="links-url">URL</label>
|
||||
<input
|
||||
id="links-url"
|
||||
class="mb1"
|
||||
type="text"
|
||||
placeholder="a1b2c3"
|
||||
required
|
||||
/>
|
||||
<label for="links-forward">Forward</label>
|
||||
<input
|
||||
id="links-forward"
|
||||
class="mb2"
|
||||
type="url"
|
||||
placeholder="http://example.com/"
|
||||
required
|
||||
/>
|
||||
<button id="links-submit" disabled>Submit</button>
|
||||
</div>
|
||||
<div id="texts-form">
|
||||
<label for="texts-url">URL</label>
|
||||
<input
|
||||
id="texts-url"
|
||||
class="mb1"
|
||||
type="text"
|
||||
placeholder="a1b2c3"
|
||||
required
|
||||
/>
|
||||
<label for="texts-contents">Contents</label>
|
||||
<textarea
|
||||
id="texts-contents"
|
||||
class="mb2"
|
||||
placeholder="Hello, World!"
|
||||
required
|
||||
></textarea>
|
||||
<button id="texts-submit" disabled>Submit</button>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
{{ js }}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
const tabs = {
|
||||
files: [
|
||||
document.querySelector("#files-tab"),
|
||||
document.querySelector("#files-form"),
|
||||
],
|
||||
links: [
|
||||
document.querySelector("#links-tab"),
|
||||
document.querySelector("#links-form"),
|
||||
],
|
||||
texts: [
|
||||
document.querySelector("#texts-tab"),
|
||||
document.querySelector("#texts-form"),
|
||||
],
|
||||
};
|
||||
|
||||
const inputs = {
|
||||
files: [
|
||||
document.querySelector("#files-url"),
|
||||
document.querySelector("#files-file"),
|
||||
document.querySelector("#files-submit"),
|
||||
],
|
||||
links: [
|
||||
document.querySelector("#links-url"),
|
||||
document.querySelector("#links-forward"),
|
||||
document.querySelector("#links-submit"),
|
||||
],
|
||||
texts: [
|
||||
document.querySelector("#texts-url"),
|
||||
document.querySelector("#texts-contents"),
|
||||
document.querySelector("#texts-submit"),
|
||||
],
|
||||
};
|
||||
|
||||
for (const group in tabs) {
|
||||
tabs[group][0].onclick = () => {
|
||||
const active = document.querySelectorAll(".active");
|
||||
for (const el of active) {
|
||||
el.classList.remove("active");
|
||||
}
|
||||
for (const el of tabs[group]) {
|
||||
el.classList.add("active");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (const group in inputs) {
|
||||
const checkValidity = () => {
|
||||
const submitButton = inputs[group][inputs[group].length - 1];
|
||||
submitButton.disabled = inputs[group].some(
|
||||
(input) => input.validity != undefined && !input.validity.valid
|
||||
);
|
||||
};
|
||||
|
||||
const urlInput = inputs[group][0];
|
||||
urlInput.addEventListener("input", () => {
|
||||
urlInput.value = urlInput.value
|
||||
.replace(/[^0-9A-Za-z]/g, "")
|
||||
.toLowerCase();
|
||||
if (parseInt(urlInput.value, 36) > 2147483647) {
|
||||
urlInput.setCustomValidity(
|
||||
"Base 36 integer below or equal to zik0zj"
|
||||
);
|
||||
} else {
|
||||
urlInput.setCustomValidity("");
|
||||
}
|
||||
});
|
||||
|
||||
for (const input of inputs[group].filter(
|
||||
(input) =>
|
||||
input instanceof HTMLInputElement ||
|
||||
input instanceof HTMLTextAreaElement
|
||||
)) {
|
||||
input.addEventListener("input", () => checkValidity());
|
||||
input.addEventListener("change", () => checkValidity());
|
||||
}
|
||||
|
||||
if (group === "files") {
|
||||
const filesFileInput = inputs.files[1];
|
||||
const filesBrowseButton = document.querySelector("#files-browse");
|
||||
const filesValueInput = document.querySelector("#files-value");
|
||||
filesFileInput.addEventListener("change", () => {
|
||||
filesValueInput.value = filesFileInput.files[0].name || "";
|
||||
});
|
||||
filesBrowseButton.onclick = () => {
|
||||
filesFileInput.click();
|
||||
};
|
||||
filesValueInput.onfocus = (e) => {
|
||||
e.preventDefault();
|
||||
filesValueInput.blur();
|
||||
return false;
|
||||
};
|
||||
} else if (group === "links") {
|
||||
} else if (group === "texts") {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
html,
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: grid;
|
||||
grid-template:
|
||||
[r1s] "nav" 2rem [r1e]
|
||||
[r2s] "main" auto [r2e]
|
||||
/ auto;
|
||||
background-color: #002b36;
|
||||
color: #839496;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #586e75;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
grid-area: nav;
|
||||
background-color: #073642;
|
||||
}
|
||||
|
||||
nav div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
font-size: 1rem;
|
||||
border-bottom: 0.0625rem solid #586e75;
|
||||
}
|
||||
|
||||
nav div:hover {
|
||||
background-color: #002b36;
|
||||
color: #93a1a1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
nav div.active {
|
||||
background-color: #002b36;
|
||||
color: #93a1a1;
|
||||
border-top: 0.0625rem solid #586e75;
|
||||
border-right: 0.0625rem solid #586e75;
|
||||
border-left: 0.0625rem solid #586e75;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
grid-area: main;
|
||||
}
|
||||
|
||||
main div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
main div.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
main div label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-left: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
main div input[type="text"],
|
||||
main div input[type="url"] {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
width: calc(75vw - 2rem);
|
||||
background-color: #073642;
|
||||
color: #839496;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
main div textarea {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
width: calc(75vw - 2rem);
|
||||
height: 25vh;
|
||||
background-color: #073642;
|
||||
color: #839496;
|
||||
font-family: monospace;
|
||||
font-size: 0.5rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
main div input[type="text"]:invalid,
|
||||
main div input[type="url"]:invalid,
|
||||
main div textarea:invalid {
|
||||
border: 0.0625rem solid #dc322f;
|
||||
}
|
||||
|
||||
main div button {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
width: 75vw;
|
||||
background-color: #073642;
|
||||
color: #839496;
|
||||
font-size: 1rem;
|
||||
border: 0.0625rem solid #586e75;
|
||||
}
|
||||
|
||||
main div button:hover,
|
||||
main div button:focus {
|
||||
background-color: #002b36;
|
||||
color: #93a1a1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
main div button:disabled {
|
||||
background-color: #073642;
|
||||
color: #586e75;
|
||||
border: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
main div div {
|
||||
display: flex;
|
||||
width: 75vw;
|
||||
}
|
||||
|
||||
main div div button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
main div div input {
|
||||
flex: 1;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #073642;
|
||||
}
|
||||
|
||||
.mb1 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.mb2 {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 720px) {
|
||||
.mb1 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mb2 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue