Mercurial > code > home > repos > sco-bot
diff web/src/main.ts @ 6:a4659594f2e5
add web page
author | drewp@bigasterisk.com |
---|---|
date | Sat, 06 Jul 2024 16:44:47 -0700 |
parents | |
children | f23b21bd0fce |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/src/main.ts Sat Jul 06 16:44:47 2024 -0700 @@ -0,0 +1,143 @@ +import { SlTextarea, setBasePath } from "@shoelace-style/shoelace"; +import "@shoelace-style/shoelace/dist/themes/light.css"; +import { LitElement, PropertyValueMap, css, html } from "lit"; +import { customElement, queryAsync, state } from "lit/decorators.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +setBasePath("@fs/opt/node_modules/@shoelace-style/shoelace/dist"); + +@customElement("sco-search-page") +export class ScoSearchPage extends LitElement { + static styles = [ + css` + :host { + display: flex; + flex-direction: column; + height: 100vh; + } + form { + display: flex; + flex-direction: row; + align-items: flex-end; + + margin: 0 10% 0 100px; + } + sl-textarea { + width: 100%; + } + :host > * { + padding: 5px; + } + section#results { + background-color: #ffffffde; + flex-grow: 1; + display: flex; + flex-direction: column; + overflow: hidden; + margin-bottom: 15px; + margin-left: 110px; + } + img.bot { + width: 237px; + position: absolute; + left: -33px; + top: -22px; + z-index: -1; + } + `, + ]; + @state() query: string = "climate"; + @state() results: Object[] = []; + @state() queryError: string = ""; + @queryAsync("sl-textarea") queryEl?: Promise<SlTextarea>; + protected async firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>) { + super.firstUpdated(_changedProperties); + + await this.pressingEnterSubmitsForm(); + + this.queryParamToProperty(); + + window.addEventListener("popstate", (event) => { + this.queryParamToProperty(); + }); + + this.submit().catch(console.error); + } + + private async pressingEnterSubmitsForm() { + const ta = (await this.queryEl)?.shadowRoot?.querySelector("textarea"); + ta?.addEventListener("keydown", (event: KeyboardEvent) => { + if (event.code == "Enter" && !event.shiftKey) { + event.preventDefault(); + this.submit(); + } + }); + } + + private queryParamToProperty() { + const urlParams = new URLSearchParams(window.location.search); + const qParam = urlParams.get("q"); + + if (qParam) { + this.query = qParam; + } + } + + private async propertyToQueryParam() { + const currentUrl = new URL(window.location.href); + + const q = await this.getCurrentQuery(); + if (currentUrl.searchParams.get("q") !== q) { + currentUrl.searchParams.set("q", q); + + const newUrl = currentUrl.toString(); + + history.pushState({}, document.title, newUrl); + } + } + + render() { + return html` + <section id="query"> + <img class="bot" src="sco-bot.jpg" /> + <form> + <sl-textarea .value=${this.query} rows="1" resize="auto" label="Query" enterkeyhint="search" autocapitalize="off" autofocus="true"></sl-textarea> + <sl-button variant="primary" @click=${this.submit}>Submit</sl-button> + <div>${this.queryError}</div> + </form> + </section> + <section id="results"> + ${this.results.map( + (r) => + html`<div>${r.title}</div> + <div>${unsafeHTML(r.snippetHtml)}</div>` + )} + <div>Matching results: ${this.results.length}</div> + </section> + `; + } + + async getCurrentQuery(): Promise<string> { + return (await this.queryEl)!.value || ""; + } + + async submit() { + await this.propertyToQueryParam(); + + this.results = []; + + const sentQ = await this.getCurrentQuery(); + + // const resp = await fetch("query", { + // method: "POST", + // body: "query=" + encodeURIComponent(sentQ), + // headers: { "Content-Type": "application/x-www-form-urlencoded" }, + // }); + // if (sentQ != (await this.getCurrentQuery())) { + // // old result- ignore + // return; + // } + this.results.push({ title: "doc1", snippetHtml: "<h1>hello</h1>" }); + console.log("ScoSearchPage ~ submit ~ this.results:", this.results); + this.requestUpdate(); + } +}