remove search button from nav bar

Signed-off-by: Tobias Erbshäußer <tobias@tesoft.dev>
This commit is contained in:
2026-05-24 09:22:39 +02:00
parent 35d3211615
commit 51f07e0543
2 changed files with 41 additions and 65 deletions
+9 -14
View File
@@ -20,7 +20,7 @@
border-radius: 0.5rem; border-radius: 0.5rem;
display: grid; display: grid;
gap: 1rem; gap: 1rem;
grid-template-columns: auto 1fr auto; grid-template-columns: auto 1fr;
grid-template-rows: auto; grid-template-rows: auto;
padding: var(--small-padding) var(--medium-padding) var(--small-padding) var(--medium-padding); padding: var(--small-padding) var(--medium-padding) var(--small-padding) var(--medium-padding);
} }
@@ -70,14 +70,14 @@
width: 100%; width: 100%;
} }
dialog.search { dialog.exec {
position: absolute; position: absolute;
top: 30%; top: 30%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
dialog.search > div { dialog.exec > div {
color: var(--light-gray); color: var(--light-gray);
display: grid; display: grid;
gap: var(--medium-padding); gap: var(--medium-padding);
@@ -102,7 +102,7 @@
} }
@media (min-width: 860px) { @media (min-width: 860px) {
dialog.search > div { dialog.exec > div {
width: 80rem; width: 80rem;
} }
} }
@@ -116,15 +116,10 @@
<tesoft-button class="small-menu"> <tesoft-button class="small-menu">
<span></span> <span></span>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"> <svg xmlns="http://www.w3.org/2000/svg" height="2.4rem" viewBox="0 -960 960 960" width="2.4rem">
<path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/> <path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/>
</svg> </svg>
</tesoft-button> </tesoft-button>
<tesoft-button class="search">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px">
<path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/>
</svg>
</tesoft-button>
</div> </div>
</nav> </nav>
@@ -132,15 +127,15 @@
<div></div> <div></div>
</dialog> </dialog>
<dialog class="search" closedby="any"> <dialog class="exec" closedby="any">
<div> <div>
<tesoft-input> <tesoft-input>
<svg slot="left" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"> <svg slot="left" xmlns="http://www.w3.org/2000/svg" height="2.4rem" viewBox="0 -960 960 960"
<path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/> width="2.4rem">
<path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/>
</svg> </svg>
</tesoft-input> </tesoft-input>
<div class="results"> <div class="results">
<!-- TODO -->
</div> </div>
</div> </div>
</dialog> </dialog>
+32 -51
View File
@@ -1,4 +1,4 @@
import {Debouncer, sendApiPost, TesoftComponent} from "../scripts/main.ts"; import {sendApiPost, TesoftComponent} from "../scripts/main.ts";
import {TesoftButton} from "./button.ts"; import {TesoftButton} from "./button.ts";
import {TesoftInput} from "./input.ts"; import {TesoftInput} from "./input.ts";
@@ -7,11 +7,9 @@ export class TesoftNav extends TesoftComponent {
private readonly smallMenuButtonSpan: HTMLSpanElement; private readonly smallMenuButtonSpan: HTMLSpanElement;
private readonly smallMenuDialog: HTMLDialogElement; private readonly smallMenuDialog: HTMLDialogElement;
private readonly smallMenuDiv: HTMLDivElement; private readonly smallMenuDiv: HTMLDivElement;
private readonly searchButton: TesoftButton; private readonly execDialog: HTMLDialogElement;
private readonly searchDialog: HTMLDialogElement; private readonly execInput: TesoftInput;
private readonly searchInput: TesoftInput; private readonly execResultsDiv: HTMLDivElement;
private readonly searchResultsDiv: HTMLDivElement;
private readonly debouncedSearch: Debouncer<[string, boolean]>;
private readonly commands: Map<string, (text: string) => Promise<void>>; private readonly commands: Map<string, (text: string) => Promise<void>>;
constructor() { constructor() {
@@ -27,11 +25,9 @@ export class TesoftNav extends TesoftComponent {
this.smallMenuButtonSpan = shadowRoot.querySelector<HTMLSpanElement>("tesoft-button.small-menu span")!; this.smallMenuButtonSpan = shadowRoot.querySelector<HTMLSpanElement>("tesoft-button.small-menu span")!;
this.smallMenuDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.small-menu")!; this.smallMenuDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.small-menu")!;
this.smallMenuDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.small-menu > div")!; this.smallMenuDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.small-menu > div")!;
this.searchButton = shadowRoot.querySelector<TesoftButton>("tesoft-button.search")!; this.execDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.exec")!;
this.searchDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.search")!; this.execInput = shadowRoot.querySelector<TesoftInput>("dialog.exec tesoft-input")!;
this.searchInput = shadowRoot.querySelector<TesoftInput>("dialog.search tesoft-input")!; this.execResultsDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.exec .results")!;
this.searchResultsDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.search .results")!;
this.debouncedSearch = new Debouncer(this.applySearch.bind(this));
this.commands = new Map<string, (text: string) => Promise<void>>([ this.commands = new Map<string, (text: string) => Promise<void>>([
["login", this.login.bind(this)], ["login", this.login.bind(this)],
["logout", this.logout.bind(this)], ["logout", this.logout.bind(this)],
@@ -45,20 +41,9 @@ export class TesoftNav extends TesoftComponent {
this.smallMenuDialog.style.width = `${this.smallMenuButton.offsetWidth}px`; this.smallMenuDialog.style.width = `${this.smallMenuButton.offsetWidth}px`;
}); });
this.searchButton.addEventListener("click", async () => { this.execInput.addEventListener("keyup", async (event) => {
await this.applySearch("", false);
this.searchDialog.showModal();
this.searchInput.value = "";
this.searchInput.focus();
});
this.searchInput.addEventListener("input", () => {
this.debouncedSearch.run(this.searchInput.value, false);
});
this.searchInput.addEventListener("keyup", async (event) => {
if (event.key === "Enter") { if (event.key === "Enter") {
await this.applySearch(this.searchInput.value, true); await this.exec(this.execInput.value);
} }
}); });
@@ -68,6 +53,17 @@ export class TesoftNav extends TesoftComponent {
this.smallMenuButtonSpan.textContent = selected.textContent; this.smallMenuButtonSpan.textContent = selected.textContent;
} }
}); });
document.addEventListener("keyup", async (event) => {
if (event.ctrlKey && event.key === "p") {
event.preventDefault();
await this.exec("");
this.execDialog.showModal();
this.execInput.value = "";
this.execInput.focus();
}
});
} }
private updateSmallMenu() { private updateSmallMenu() {
@@ -85,37 +81,22 @@ export class TesoftNav extends TesoftComponent {
} }
} }
private async applySearch(text: string, confirmed: boolean) { private async exec(text: string) {
if (confirmed) { this.setResultText("Press enter to send command.");
this.debouncedSearch.stop();
}
this.setResultText(""); if (text) {
const spaceIndex = text.indexOf(" ");
const prefix = spaceIndex === -1 ? text : text.substring(0, spaceIndex);
if (text.startsWith(">")) { const command = this.commands.get(prefix);
if (confirmed) { if (command === undefined) {
await this.applyCommand(text.substring(1).trimStart()); this.setResultText("Unknown command.");
} else { return;
this.setResultText("Press enter to send command.");
} }
} else { await command(text.substring(prefix.length).trimStart());
console.log(text);
// TODO
} }
} }
private async applyCommand(text: string) {
const spaceIndex = text.indexOf(" ");
const prefix = spaceIndex === -1 ? text : text.substring(0, spaceIndex);
const command = this.commands.get(prefix);
if (command === undefined) {
this.setResultText("Unknown command.");
return;
}
await command(text.substring(prefix.length).trimStart());
}
private async login(text: string) { private async login(text: string) {
const response = await sendApiPost("login", { const response = await sendApiPost("login", {
password: text, password: text,
@@ -141,12 +122,12 @@ export class TesoftNav extends TesoftComponent {
} }
private setResultText(text: string) { private setResultText(text: string) {
this.searchResultsDiv.innerHTML = ""; this.execResultsDiv.innerHTML = "";
if (text) { if (text) {
const div = document.createElement("div"); const div = document.createElement("div");
div.textContent = text; div.textContent = text;
this.searchResultsDiv.appendChild(div); this.execResultsDiv.appendChild(div);
} }
} }
} }