From 51bbf08d241f0eff8847f6656accee03c0626d88 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 6 Dec 2022 11:28:56 -0300 Subject: implement web-utils in web-extension --- packages/taler-wallet-webextension/src/stories.tsx | 499 +-------------------- 1 file changed, 24 insertions(+), 475 deletions(-) (limited to 'packages/taler-wallet-webextension/src/stories.tsx') diff --git a/packages/taler-wallet-webextension/src/stories.tsx b/packages/taler-wallet-webextension/src/stories.tsx index 02cc15393..8834b8084 100644 --- a/packages/taler-wallet-webextension/src/stories.tsx +++ b/packages/taler-wallet-webextension/src/stories.tsx @@ -18,516 +18,65 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { setupI18n } from "@gnu-taler/taler-util"; -import { styled } from "@linaria/react"; -import { - ComponentChild, - ComponentChildren, - Fragment, - FunctionComponent, - h, - render, - VNode, -} from "preact"; -import { useEffect, useErrorBoundary, useState } from "preact/hooks"; +import { Fragment, FunctionComponent, h } from "preact"; import { LogoHeader } from "./components/LogoHeader.js"; import { PopupBox, WalletBox } from "./components/styled/index.js"; -import * as mui from "./mui/index.stories.js"; +import { strings } from "./i18n/strings.js"; import { PopupNavBar, WalletNavBar } from "./NavigationBar.js"; + +import * as components from "./components/index.stories.js"; +import * as cta from "./cta/index.stories.js"; +import * as mui from "./mui/index.stories.js"; import * as popup from "./popup/index.stories.js"; import * as wallet from "./wallet/index.stories.js"; -import * as cta from "./cta/index.stories.js"; -import * as components from "./components/index.stories.js"; -import { strings } from "./i18n/strings.js"; -import { setupPlatform } from "./platform/api.js"; -import chromeAPI from "./platform/chrome.js"; -import firefoxAPI from "./platform/firefox.js"; -const url = new URL(window.location.href); -const lang = url.searchParams.get("lang") || "en"; +import { renderStories } from "@gnu-taler/web-util/lib/index.browser"; -setupI18n(lang, strings); - -const Page = styled.div` - * { - font-family: Arial, Helvetica, sans-serif; - } - p:not([class]) { - margin-bottom: 1em; - margin-top: 1em; - } - width: 100%; - display: flex; - flex-direction: row; -`; - -const SideBar = styled.div` - min-width: var(--with-size); - height: calc(100vh - 20px); - overflow-y: visible; - overflow-x: hidden; - scroll-behavior: smooth; - - * { - margin: 0px; - padding: 0px; - } - - & > { - ol { - padding: 4px; - div:first-child { - background-color: lightcoral; - cursor: pointer; - } - div[data-hide="true"] { - display: none; - } - dd { - margin-left: 1em; - padding: 4px; - cursor: pointer; - border-radius: 4px; - margin-bottom: 4px; - } - dd:nth-child(even) { - background-color: lightgray; - } - dd:nth-child(odd) { - background-color: lightblue; - } - a { - color: black; - } - dd[data-selected] { - background-color: green; - } - } - } -`; - -const ResizeHandleDiv = styled.div` - width: 10px; - background: #ddd; - cursor: ew-resize; -`; - -function ResizeHandle({ onUpdate }: { onUpdate: (x: number) => void }): VNode { - const [start, setStart] = useState(undefined); - return ( - { - setStart(e.pageX); - console.log("active", e.pageX); - return false; - }} - onMouseMove={(e: any) => { - if (start !== undefined) { - onUpdate(e.pageX - start); - } - return false; - }} - onMouseUp={() => { - setStart(undefined); - return false; - }} - /> - ); -} - -const Content = styled.div` - width: 100%; - padding: 20px; -`; - -function parseExampleImport(group: string, im: any): ComponentItem { - const component = im.default.title; - return { - name: component, - examples: Object.entries(im) - .filter(([k]) => k !== "default") - .map( - ([name, render]) => - ({ - group, - component, - name, - render, - } as ExampleItem), - ), - }; -} - -const allExamples = Object.entries({ popup, wallet, cta, mui, components }).map( - ([title, value]) => ({ - title, - list: value.default.map((s) => parseExampleImport(title, s)), - }), -); - -interface ComponentItem { - name: string; - examples: ExampleItem[]; -} - -interface ExampleItem { - group: string; - component: string; - name: string; - render: { - (args: any): VNode; - args: any; - }; -} - -function findByGroupComponentName( - group: string, - component: string, - name: string, -): ExampleItem | undefined { - const gl = allExamples.filter((e) => e.title === group); - if (gl.length === 0) { - return undefined; - } - const cl = gl[0].list.filter((l) => l.name === component); - if (cl.length === 0) { - return undefined; - } - const el = cl[0].examples.filter((c) => c.name === name); - if (el.length === 0) { - return undefined; - } - return el[0]; -} - -function getContentForExample(item: ExampleItem | undefined): () => VNode { - if (!item) - return function SelectExampleMessage() { - return
select example from the list on the left
; - }; - const example = findByGroupComponentName( - item.group, - item.component, - item.name, - ); - if (!example) { - return function ExampleNotFoundMessage() { - return
example not found
; - }; - } - return () => example.render(example.render.args); -} - -function ExampleList({ - name, - list, - selected, - onSelectStory, -}: { - name: string; - list: { - name: string; - examples: ExampleItem[]; - }[]; - selected: ExampleItem | undefined; - onSelectStory: (i: ExampleItem, id: string) => void; -}): VNode { - const [isOpen, setOpen] = useState(selected && selected.group === name); - return ( -
    -
    setOpen(!isOpen)}>{name}
    -
    - {list.map((k) => ( -
  1. -
    -
    {k.name.substring(k.name.indexOf("/") + 1)}
    - {k.examples.map((r) => { - const e = encodeURIComponent; - const eId = `${e(r.group)}-${e(r.component)}-${e(r.name)}`; - const isSelected = - selected && - selected.component === r.component && - selected.group === r.group && - selected.name === r.name; - return ( -
    - { - e.preventDefault(); - location.hash = `#${eId}`; - onSelectStory(r, eId); - history.pushState({}, "", `#${eId}`); - }} - > - {r.name} - -
    - ); - })} -
    -
  2. - ))} -
    -
+function main(): void { + renderStories( + { popup, wallet, cta, mui, components }, + { + strings, + getWrapperForGroup, + }, ); } -/** - * Prevents the UI from redirecting and inform the dev - * where the should have redirected - * @returns - */ -function PreventLinkNavigation({ - children, -}: { - children: ComponentChildren; -}): VNode { - return ( -
{ - let t: any = e.target; - do { - if (t.localName === "a" && t.getAttribute("href")) { - alert(`should navigate to: ${t.attributes.href.value}`); - e.stopImmediatePropagation(); - e.stopPropagation(); - e.preventDefault(); - return false; - } - } while ((t = t.parentNode)); - }} - > - {children} -
- ); +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", main); +} else { + main(); } - function getWrapperForGroup(group: string): FunctionComponent { switch (group) { case "popup": return function PopupWrapper({ children }: any) { return ( - + {children} - + ); }; case "wallet": return function WalletWrapper({ children }: any) { return ( - + {children} - + ); }; case "cta": return function WalletWrapper({ children }: any) { return ( - + {children} - + ); }; default: return Fragment; } } - -function ErrorReport({ - children, - selected, -}: { - children: ComponentChild; - selected: ExampleItem | undefined; -}): VNode { - const [error, resetError] = useErrorBoundary(); - //if there is an error, reset when unloading this component - useEffect(() => (error ? resetError : undefined)); - if (error) { - return ( -
-

Error was thrown trying to render

- {selected && ( -
    -
  • - group: {selected.group} -
  • -
  • - component: {selected.component} -
  • -
  • - example: {selected.name} -
  • -
  • - args:{" "} -
    {JSON.stringify(selected.render.args, undefined, 2)}
    -
  • -
- )} -

{error.message}

-
{error.stack}
-
- ); - } - return {children}; -} - -function getSelectionFromLocationHash(hash: string): ExampleItem | undefined { - if (!hash) return undefined; - const parts = hash.substring(1).split("-"); - if (parts.length < 3) return undefined; - return findByGroupComponentName( - decodeURIComponent(parts[0]), - decodeURIComponent(parts[1]), - decodeURIComponent(parts[2]), - ); -} - -function Application(): VNode { - const initialSelection = getSelectionFromLocationHash(location.hash); - const [selected, updateSelected] = useState( - initialSelection, - ); - useEffect(() => { - if (location.hash) { - const hash = location.hash.substring(1); - const found = document.getElementById(hash); - if (found) { - setTimeout(() => { - found.scrollIntoView({ - block: "center", - }); - }, 10); - } - } - }, []); - - const ExampleContent = getContentForExample(selected); - - const GroupWrapper = getWrapperForGroup(selected?.group || "default"); - const [sidebarWidth, setSidebarWidth] = useState(200); - - return ( - - - - {allExamples.map((e) => ( - { - document.getElementById(htmlId)?.scrollIntoView({ - block: "center", - }); - updateSelected(item); - }} - /> - ))} -
-
- { - setSidebarWidth((s) => s + x); - }} - /> - - - - - - - -
- ); -} - -if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", main); -} else { - main(); -} -function main(): void { - try { - const container = document.getElementById("container"); - if (!container) { - throw Error("container not found, can't mount page contents"); - } - render(, container); - } catch (e) { - console.error("got error", e); - if (e instanceof Error) { - document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; - } - } -} - -let liveReloadMounted = false; -function LiveReload({ port = 8002 }: { port?: number }): VNode { - const [isReloading, setIsReloading] = useState(false); - useEffect(() => { - if (!liveReloadMounted) { - setupLiveReload(port, () => { - setIsReloading(true); - window.location.reload(); - }); - liveReloadMounted = true; - } - }); - - if (isReloading) { - return ( -
-

reloading...

-
- ); - } - return ; -} - -function setupLiveReload(port: number, onReload: () => void): void { - const protocol = location.protocol === "https:" ? "wss:" : "ws:"; - const host = location.hostname; - const socketPath = `${protocol}//${host}:${port}/socket`; - - const ws = new WebSocket(socketPath); - ws.onmessage = (message) => { - const event = JSON.parse(message.data); - if (event.type === "LOG") { - console.log(event.message); - } - if (event.type === "RELOAD") { - onReload(); - } - }; - ws.onerror = (error) => { - console.error(error); - }; -} - -const isFirefox = typeof (window as any)["InstallTrigger"] !== "undefined"; - -//FIXME: create different entry point for any platform instead of -//switching in runtime -if (isFirefox) { - console.log("Wallet setup for Firefox API"); - setupPlatform(firefoxAPI); -} else { - console.log("Wallet setup for Chrome API"); - setupPlatform(chromeAPI); -} -- cgit v1.2.3