feat: Add search bar for formats

This commit is contained in:
Luis Canada 2024-08-20 14:59:25 -04:00
parent 7d2af46b0b
commit 53fff594fc
No known key found for this signature in database
GPG key ID: B36EE21907C0F591
4 changed files with 290 additions and 43 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -1,12 +1,12 @@
import { Database } from "bun:sqlite";
import { randomUUID } from "node:crypto";
import { rmSync } from "node:fs";
import { mkdir, unlink } from "node:fs/promises";
import cookie from "@elysiajs/cookie"; import cookie from "@elysiajs/cookie";
import { html } from "@elysiajs/html"; import { html } from "@elysiajs/html";
import { jwt } from "@elysiajs/jwt"; import { jwt } from "@elysiajs/jwt";
import { staticPlugin } from "@elysiajs/static"; import { staticPlugin } from "@elysiajs/static";
import { Database } from "bun:sqlite";
import { Elysia, t } from "elysia"; import { Elysia, t } from "elysia";
import { randomUUID } from "node:crypto";
import { rmSync } from "node:fs";
import { mkdir, unlink } from "node:fs/promises";
import { BaseHtml } from "./components/base"; import { BaseHtml } from "./components/base";
import { Header } from "./components/header"; import { Header } from "./components/header";
import { import {
@ -473,27 +473,101 @@ const app = new Elysia({
))} ))}
</select> */} </select> */}
</article> </article>
<form method="post" action="/convert"> <form
method="post"
action="/convert"
style={{ position: "relative" }}>
<input type="hidden" name="file_names" id="file_names" /> <input type="hidden" name="file_names" id="file_names" />
<article> <article>
<select name="convert_to" aria-label="Convert to" required> <input
<option selected disabled value=""> type="search"
Convert to name="convert_to_search"
</option> placeholder="Search for conversions"
{Object.entries(getAllTargets()).map( autocomplete="off"
([converter, targets]) => ( />
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<optgroup label={converter}> <div class="select_container">
{targets.map((target) => ( <article
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation> class="convert_to_popup"
<option value={`${target},${converter}`} safe> hidden
{target} style={{
</option> flexDirection: "column",
))} display: "flex",
</optgroup> zIndex: 2,
), position: "absolute",
)} maxHeight: "50vh",
</select> width: "90vw",
overflowY: "scroll",
margin: "0px",
overflowX: "hidden",
}}>
{Object.entries(getAllTargets()).map(
([converter, targets]) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<article
class="convert_to_group"
data-converter={converter}
style={{
borderColor: "gray",
padding: "2px",
}}>
<header
style={{ fontSize: "20px", fontWeight: "bold" }}>
{converter}
</header>
<ul
class="convert_to_target"
style={{
display: "flex",
flexDirection: "row",
gap: "5px",
flexWrap: "wrap",
}}>
{targets.map((target) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<button
// https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953
tabindex={0}
class="target"
data-value={`${target},${converter}`}
data-target={target}
data-converter={converter}
style={{ fontSize: "15px", padding: "5px" }}
type="button">
{target}
</button>
))}
</ul>
</article>
),
)}
</article>
{/* Hidden element which determines the format to convert the file too and the converter to use */}
<select
name="convert_to"
aria-label="Convert to"
required
hidden>
<option selected disabled value="">
Convert to
</option>
{Object.entries(getAllTargets()).map(
([converter, targets]) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<optgroup label={converter}>
{targets.map((target) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<option value={`${target},${converter}`} safe>
{target}
</option>
))}
</optgroup>
),
)}
</select>
</div>
</article> </article>
<input type="submit" value="Convert" /> <input type="submit" value="Convert" />
</form> </form>
@ -507,24 +581,82 @@ const app = new Elysia({
"/conversions", "/conversions",
({ body }) => { ({ body }) => {
return ( return (
<select name="convert_to" aria-label="Convert to" required> <>
<option selected disabled value=""> <article
Convert to class="convert_to_popup"
</option> hidden
{Object.entries(getPossibleTargets(body.fileType)).map( style={{
([converter, targets]) => ( flexDirection: "column",
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation> display: "flex",
<optgroup label={converter}> zIndex: 2,
{targets.map((target) => ( position: "absolute",
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation> maxHeight: "50vh",
<option value={`${target},${converter}`} safe> width: "90vw",
{target} overflowY: "scroll",
</option> margin: "0px",
))} overflowX: "hidden",
</optgroup> }}>
), {Object.entries(getPossibleTargets(body.fileType)).map(
)} ([converter, targets]) => (
</select> // biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<article
class="convert_to_group"
data-converter={converter}
style={{
borderColor: "gray",
padding: "2px",
}}>
<header style={{ fontSize: "20px", fontWeight: "bold" }}>
{converter}
</header>
<ul
class="convert_to_target"
style={{
display: "flex",
flexDirection: "row",
gap: "5px",
flexWrap: "wrap",
}}>
{targets.map((target) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<button
// https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953
tabindex={0}
class="target"
data-value={`${target},${converter}`}
data-target={target}
data-converter={converter}
style={{ fontSize: "15px", padding: "5px" }}
type="button">
{target}
</button>
))}
</ul>
</article>
),
)}
</article>
<select name="convert_to" aria-label="Convert to" required hidden>
<option selected disabled value="">
Convert to
</option>
{Object.entries(getPossibleTargets(body.fileType)).map(
([converter, targets]) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<optgroup label={converter}>
{targets.map((target) => (
// biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
<option value={`${target},${converter}`} safe>
{target}
</option>
))}
</optgroup>
),
)}
</select>
</>
); );
}, },
{ body: t.Object({ fileType: t.String() }) }, { body: t.Object({ fileType: t.String() }) },

View file

@ -3,7 +3,75 @@ const fileInput = document.querySelector('input[type="file"]');
const fileNames = []; const fileNames = [];
let fileType; let fileType;
const selectContainer = document.querySelector("form > article"); const selectContainer = document.querySelector("form .select_container");
const updateSearchBar = () => {
const convertToInput = document.querySelector(
"input[name='convert_to_search']",
);
const convertToPopup = document.querySelector(".convert_to_popup");
const convertToGroupElements = document.querySelectorAll(".convert_to_group");
const convertToGroups = {};
const convertToElement = document.querySelector("select[name='convert_to']");
const showMatching = (search) => {
for (const [targets, groupElement] of Object.values(convertToGroups)) {
let matchingTargetsFound = 0;
for (const target of targets) {
if (target.dataset.target.includes(search)) {
matchingTargetsFound++;
target.hidden = false;
} else {
target.hidden = true;
}
}
if (matchingTargetsFound === 0) {
groupElement.hidden = true;
} else {
groupElement.hidden = false;
}
}
};
for (const groupElement of convertToGroupElements) {
const groupName = groupElement.dataset.converter;
const targetElements = groupElement.querySelectorAll(".target");
const targets = Array.from(targetElements);
for (const target of targets) {
target.onclick = () => {
convertToElement.value = target.dataset.value;
convertToInput.value = `${target.dataset.target} using ${target.dataset.converter}`;
showMatching("");
};
}
convertToGroups[groupName] = [targets, groupElement];
}
convertToInput.addEventListener("input", (e) => {
showMatching(e.target.value.toLowerCase());
});
convertToInput.addEventListener("blur", (e) => {
// Keep the popup open even when clicking on a target button
// for a split second to allow the click to go through
if (e?.relatedTarget?.classList?.contains("target")) {
setTimeout(() => {
convertToPopup.hidden = true;
}, 100);
return;
}
convertToPopup.hidden = true;
});
convertToInput.addEventListener("focus", () => {
convertToPopup.hidden = false;
});
};
// const convertFromSelect = document.querySelector("select[name='convert_from']"); // const convertFromSelect = document.querySelector("select[name='convert_from']");
@ -49,6 +117,7 @@ fileInput.addEventListener("change", (e) => {
.then((res) => res.text()) .then((res) => res.text())
.then((html) => { .then((html) => {
selectContainer.innerHTML = html; selectContainer.innerHTML = html;
updateSearchBar();
}) })
.catch((err) => console.log(err)); .catch((err) => console.log(err));
} }
@ -123,3 +192,5 @@ formConvert.addEventListener("submit", (e) => {
const hiddenInput = document.querySelector("input[name='file_names']"); const hiddenInput = document.querySelector("input[name='file_names']");
hiddenInput.value = JSON.stringify(fileNames); hiddenInput.value = JSON.stringify(fileNames);
}); });
updateSearchBar();

View file

@ -12,4 +12,48 @@ div.center {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
@media (max-width: 99999999999px) {
.convert_to_popup {
width: 50vw !important;
height: 50vh;
}
}
@media (max-width: 850px) {
.convert_to_popup {
width: 60vw !important;
height: 60vh;
}
}
@media (max-width: 575px) {
.convert_to_popup {
width: 80vw !important;
height: 75vh;
}
}
@media (max-height: 1000px) {
.convert_to_popup {
height: 40vh;
}
}
@media (max-height: 650px) {
.convert_to_popup {
height: 30vh;
}
}
@media (max-height: 500px) {
.convert_to_popup {
height: 25vh;
}
}
@media (max-height: 400px) {
.convert_to_popup {
height: 15vh;
}
}