aboutsummaryrefslogtreecommitdiff
path: root/packages/web-util/src/components/Header.tsx
blob: 29f4a4949196e8d0d2c9ae247f63613b11e90b25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import { useState } from "preact/hooks";
import { LangSelector, useNotifications, useTranslationContext } from "../index.browser.js";
import { ComponentChildren, Fragment, VNode, h } from "preact";
import logo from "../assets/logo-2021.svg";

interface Props {
  title: string;
  iconLinkURL: string;
  profileURL?: string;
  notificationURL?: string;
  children?: ComponentChildren;
  onLogout: (() => void) | undefined;
  sites: Array<Array<string>>;
  supportedLangs: string[]
}

export function Header({ title, profileURL, notificationURL, iconLinkURL, sites, onLogout, children }: Props): VNode {
  const { i18n } = useTranslationContext();
  const [open, setOpen] = useState(false)
  const ns = useNotifications();

  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 ?? "#"} name="logo">
              <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="flex-1 ml-6 ">
          <div class="flex flex-1 space-x-4">
            {sites.map((site) => {
              if (site.length !== 2) return;
              const [name, url] = site
              return <a href={url} name={`site header ${name}`} class="hidden sm:block 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">
          {!notificationURL ? undefined :
            <a href={notificationURL} name="notifications" class="relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 mr-2 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">
              <span class="absolute -inset-0.5"></span>
              <span class="sr-only"><i18n.Translate>Show notifications</i18n.Translate></span>
              {ns.length > 0 ?
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-10 h-10">
                  <path d="M5.85 3.5a.75.75 0 0 0-1.117-1 9.719 9.719 0 0 0-2.348 4.876.75.75 0 0 0 1.479.248A8.219 8.219 0 0 1 5.85 3.5ZM19.267 2.5a.75.75 0 1 0-1.118 1 8.22 8.22 0 0 1 1.987 4.124.75.75 0 0 0 1.48-.248A9.72 9.72 0 0 0 19.266 2.5Z" />
                  <path fill-rule="evenodd" d="M12 2.25A6.75 6.75 0 0 0 5.25 9v.75a8.217 8.217 0 0 1-2.119 5.52.75.75 0 0 0 .298 1.206c1.544.57 3.16.99 4.831 1.243a3.75 3.75 0 1 0 7.48 0 24.583 24.583 0 0 0 4.83-1.244.75.75 0 0 0 .298-1.205 8.217 8.217 0 0 1-2.118-5.52V9A6.75 6.75 0 0 0 12 2.25ZM9.75 18c0-.034 0-.067.002-.1a25.05 25.05 0 0 0 4.496 0l.002.1a2.25 2.25 0 1 1-4.5 0Z" clip-rule="evenodd" />
                </svg>
                :
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-10 h-10">
                  <path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0" />
                </svg>
              }
            </a>
          }
          {!profileURL ? undefined :
            <a href={profileURL} name="profile" class="relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 mr-2 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">
              <span class="absolute -inset-0.5"></span>
              <span class="sr-only"><i18n.Translate>Open profile</i18n.Translate></span>
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-10 h-10">
                <path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
              </svg>
            </a>
          }
          <button type="button" name="toggle sidebar" 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" name="sidebar overlay" 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" name="close sidebar" 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="#"
                              name="logout"
                              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 />
                        </li>
                        {/* CHILDREN */}
                        {children}
                        {/* /CHILDREN */}
                        {sites.length > 0 ?
                          <li class="block 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} name={`site ${name}`} 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">&gt;</span>
                                    <span class="truncate">{name}</span>
                                  </a>
                                </li>
                              })}
                            </ul>
                          </li>
                          : undefined
                        }
                      </ul>
                    </nav>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    }
  </Fragment >
}