diff options
author | Sebastian <sebasjm@gmail.com> | 2023-11-06 11:53:43 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-11-06 11:53:43 -0300 |
commit | 3d1ab082d4a66df08fcb468d04198c055d00b8c5 (patch) | |
tree | 721e1e81a72e13aef87b711061ffcaafd41f9848 /packages/web-util/src/components | |
parent | 61563d1b4844caa3ac7d5d532b51309edd42101b (diff) | |
download | wallet-core-3d1ab082d4a66df08fcb468d04198c055d00b8c5.tar.xz |
share header and footer in web utils
Diffstat (limited to 'packages/web-util/src/components')
-rw-r--r-- | packages/web-util/src/components/Footer.tsx | 44 | ||||
-rw-r--r-- | packages/web-util/src/components/GlobalNotificationBanner.tsx | 28 | ||||
-rw-r--r-- | packages/web-util/src/components/Header.tsx | 143 | ||||
-rw-r--r-- | packages/web-util/src/components/Loading.tsx | 4 | ||||
-rw-r--r-- | packages/web-util/src/components/LocalNotificationBanner.tsx (renamed from packages/web-util/src/components/ShowLocalNotification.tsx) | 2 | ||||
-rw-r--r-- | packages/web-util/src/components/index.ts | 5 |
6 files changed, 222 insertions, 4 deletions
diff --git a/packages/web-util/src/components/Footer.tsx b/packages/web-util/src/components/Footer.tsx new file mode 100644 index 000000000..8fdf6b8f0 --- /dev/null +++ b/packages/web-util/src/components/Footer.tsx @@ -0,0 +1,44 @@ +import { useTranslationContext } from "../index.browser.js"; +import { h } from "preact"; + +export function Footer({ testingUrl, VERSION, GIT_HASH }: { VERSION?: string, GIT_HASH?: string, testingUrl?: string }) { + const { i18n } = useTranslationContext() + const versionText = VERSION + ? GIT_HASH + ? <a href={`https://git.taler.net/wallet-core.git/tree/?id=${GIT_HASH}`} target="_blank" rel="noreferrer noopener"> + Version {VERSION} ({GIT_HASH.substring(0, 8)}) + </a> + : VERSION + : ""; + return ( + <footer class="bottom-4 my-4 mx-8 bg-slate-200"> + <div> + <p class="text-xs leading-5 text-gray-400"> + <i18n.Translate> + Learn more about <a target="_blank" rel="noreferrer noopener" class="font-semibold text-gray-500 hover:text-gray-400" href="https://taler.net">GNU Taler</a> + </i18n.Translate> + </p> + </div> + <div style="flex-grow:1" /> + <p class="text-xs leading-5 text-gray-400"> + Copyright © 2014—2023 Taler Systems SA. {versionText}{" "} + </p> + {testingUrl && + + <p class="text-xs leading-5 text-gray-300"> + Testing with {testingUrl}{" "} + <a + href="" + onClick={(e) => { + e.preventDefault(); + localStorage.removeItem("bank-base-url"); + window.location.reload(); + }} + > + stop testing + </a> + </p> + } + </footer> + ); +} diff --git a/packages/web-util/src/components/GlobalNotificationBanner.tsx b/packages/web-util/src/components/GlobalNotificationBanner.tsx new file mode 100644 index 000000000..c8049acc3 --- /dev/null +++ b/packages/web-util/src/components/GlobalNotificationBanner.tsx @@ -0,0 +1,28 @@ +import { Fragment, VNode, h } from "preact" +import { Attention, useNotifications } from "../index.browser.js" + +export function GlobalNotificationsBanner(): VNode { + const notifs = useNotifications() + if (notifs.length === 0) return <Fragment /> + return <div class="fixed z-20 w-full p-4"> { + notifs.map(n => { + switch (n.message.type) { + case "error": + return <Attention type="danger" title={n.message.title} onClose={() => { + n.remove() + }}> + {n.message.description && + <div class="mt-2 text-sm text-red-700"> + {n.message.description} + </div> + } + {/* <MaybeShowDebugInfo info={n.message.debug} /> */} + </Attention> + case "info": + return <Attention type="success" title={n.message.title} onClose={() => { + n.remove(); + }} /> + } + })} + </div> +} diff --git a/packages/web-util/src/components/Header.tsx b/packages/web-util/src/components/Header.tsx new file mode 100644 index 000000000..bde0688dc --- /dev/null +++ b/packages/web-util/src/components/Header.tsx @@ -0,0 +1,143 @@ +import { useState } from "preact/hooks"; +import { LangSelector, useTranslationContext } from "../index.browser.js"; +import { ComponentChildren, Fragment, VNode, h } from "preact"; +import logo from "../assets/logo-2021.svg"; + +export function Header({ title, iconLinkURL, sites, supportedLangs, onLogout, children }: { title: string, iconLinkURL: string, children?: ComponentChildren, onLogout: (() => void) | undefined, sites: [string, string][], supportedLangs: string[] }): VNode { + const { i18n } = useTranslationContext(); + const [open, setOpen] = useState(false) + return <Fragment> + <header class="bg-indigo-600 w-full mx-auto px-2 border-b border-opacity-25 border-indigo-400"> + <div class="flex flex-row h-16 items-center "> + <div class="flex px-2 justify-start"> + <div class="flex-shrink-0 bg-white rounded-lg"> + <a href={iconLinkURL ?? "#"}> + <img + class="h-8 w-auto" + src={logo} + alt="GNU Taler" + style={{ height: "1.5rem", margin: ".5rem" }} + /> + </a> + </div> + <span class="flex items-center text-white text-lg font-bold ml-4"> + {title} + </span> + </div> + <div class="block flex-1 ml-6 "> + {sites.length !== 0 && + <div class="flex flex-1 space-x-4"> + {/* <!-- Current: "bg-indigo-700 text-white", Default: "text-white hover:bg-indigo-500 hover:bg-opacity-75" --> */} + {sites.map(([name, url]) => { + return <a href={url} class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md py-2 px-3 text-sm font-medium">{name}</a> + })} + </div> + } + </div> + <div class="flex justify-end"> + <button type="button" class="relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600" aria-controls="mobile-menu" aria-expanded="false" + onClick={(e) => { + setOpen(!open) + }}> + <span class="absolute -inset-0.5"></span> + <span class="sr-only"><i18n.Translate>Open settings</i18n.Translate></span> + <svg class="block h-10 w-10" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> + </svg> + </button> + </div> + </div> + </header> + + {open && + <div class="relative z-10" aria-labelledby="slide-over-title" role="dialog" aria-modal="true" + onClick={() => { + setOpen(false) + }}> + <div class="fixed inset-0"></div> + + <div class="fixed inset-0 overflow-hidden"> + <div class="absolute inset-0 overflow-hidden"> + <div class="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10"> + <div class="pointer-events-auto w-screen max-w-md" > + <div class="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl" onClick={(e) => { + //do not trigger close if clicking inside the sidebar + e.stopPropagation(); + }}> + <div class="px-4 sm:px-6" > + <div class="flex items-start justify-between" > + <h2 class="text-base font-semibold leading-6 text-gray-900" id="slide-over-title"> + <i18n.Translate>Menu</i18n.Translate> + </h2> + <div class="ml-3 flex h-7 items-center"> + <button type="button" class="relative rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" + onClick={(e) => { + setOpen(false) + }} + + > + <span class="absolute -inset-2.5"></span> + <span class="sr-only"> + <i18n.Translate>Close panel</i18n.Translate> + </span> + <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> + </svg> + </button> + </div> + </div> + </div> + <div class="relative mt-6 flex-1 px-4 sm:px-6"> + <nav class="flex flex-1 flex-col" aria-label="Sidebar"> + <ul role="list" class="flex flex-1 flex-col gap-y-7"> + {onLogout ? + <li> + <a href="#" + class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold" + onClick={() => { + onLogout(); + setOpen(false) + }} + > + <svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" /> + </svg> + <i18n.Translate>Log out</i18n.Translate> + </a> + </li> + : undefined} + <li> + <LangSelector supportedLangs={supportedLangs} /> + </li> + {/* CHILDREN */} + {children} + {/* /CHILDREN */} + {sites.length !== 0 && + <li class="sm:hidden"> + <div class="text-xs font-semibold leading-6 text-gray-400"> + <i18n.Translate>Sites</i18n.Translate> + </div> + <ul role="list" class="space-y-1"> + {sites.map(([name, url]) => { + return <li> + <a href={url} target="_blank" rel="noopener noreferrer" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-100 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"> + <span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600">></span> + <span class="truncate">{name}</span> + </a> + </li> + })} + </ul> + </li> + } + </ul> + </nav> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + } + </Fragment> +} diff --git a/packages/web-util/src/components/Loading.tsx b/packages/web-util/src/components/Loading.tsx index b567e9056..c5dcd90c1 100644 --- a/packages/web-util/src/components/Loading.tsx +++ b/packages/web-util/src/components/Loading.tsx @@ -33,9 +33,9 @@ export function Loading(): VNode { ); } -export function Spinner(): VNode { +function Spinner(): VNode { return ( - <div class="lds-ring" style={{margin:"auto"}}> + <div class="lds-ring" style={{ margin: "auto" }}> <div /> <div /> <div /> diff --git a/packages/web-util/src/components/ShowLocalNotification.tsx b/packages/web-util/src/components/LocalNotificationBanner.tsx index cb947e536..ab46703cb 100644 --- a/packages/web-util/src/components/ShowLocalNotification.tsx +++ b/packages/web-util/src/components/LocalNotificationBanner.tsx @@ -3,7 +3,7 @@ import { Attention } from "./Attention.js"; import { Notification } from "../index.browser.js"; // import { useSettings } from "../hooks/settings.js"; -export function ShowLocalNotification({ notification }: { notification?: Notification }): VNode { +export function LocalNotificationBanner({ notification }: { notification?: Notification }): VNode { if (!notification) return <Fragment /> switch (notification.message.type) { case "error": diff --git a/packages/web-util/src/components/index.ts b/packages/web-util/src/components/index.ts index 8344d4a7a..d94502b48 100644 --- a/packages/web-util/src/components/index.ts +++ b/packages/web-util/src/components/index.ts @@ -4,5 +4,8 @@ export * from "./CopyButton.js"; export * from "./ErrorLoading.js"; export * from "./LangSelector.js"; export * from "./Loading.js"; +export * from "./Header.js"; +export * from "./Footer.js"; export * from "./ShowInputErrorLabel.js"; -export * from "./ShowLocalNotification.js"; +export * from "./LocalNotificationBanner.js"; +export * from "./GlobalNotificationBanner.js"; |