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();
+  }
+}