225 lines
5.6 KiB
XML
225 lines
5.6 KiB
XML
/**
|
|
* 8-bit styled header/navbar component
|
|
*/
|
|
|
|
import { useStore } from '@nanostores/solid'
|
|
import { A, useLocation } from '@solidjs/router'
|
|
import type { JSX } from 'solid-js'
|
|
import { Show } from 'solid-js'
|
|
import {
|
|
$currentUser,
|
|
$isAuthenticated,
|
|
$sidebarOpen,
|
|
openModal,
|
|
toggleSidebar,
|
|
} from '../../stores'
|
|
import { Avatar } from '../UI/Avatar'
|
|
import { Badge } from '../UI/Badge'
|
|
import { IconButton } from '../UI/IconButton'
|
|
|
|
export function Header(): JSX.Element {
|
|
const isAuthenticated = useStore($isAuthenticated)
|
|
const sidebarOpen = useStore($sidebarOpen)
|
|
const currentUser = useStore($currentUser)
|
|
const location = useLocation()
|
|
|
|
return (
|
|
<header class="flex-shrink-0 bg-black border-b-4 border-orange">
|
|
<div class="flex items-center justify-between h-14 px-4">
|
|
<div class="flex items-center gap-3">
|
|
<Show when={isAuthenticated()}>
|
|
<IconButton
|
|
icon={sidebarOpen() ? <CloseMenuIcon /> : <MenuIcon />}
|
|
ariaLabel={sidebarOpen() ? 'Close menu' : 'Open menu'}
|
|
onClick={toggleSidebar}
|
|
size="sm"
|
|
/>
|
|
</Show>
|
|
|
|
<A href="/" class="flex items-center gap-2 hover:no-underline">
|
|
<LockIcon />
|
|
<h1 class="font-pixel text-sm text-orange uppercase hidden sm:block">
|
|
ENCRYPTED CHAT
|
|
</h1>
|
|
<h1 class="font-pixel text-sm text-orange uppercase sm:hidden">
|
|
E-CHAT
|
|
</h1>
|
|
</A>
|
|
|
|
<Badge variant="primary" size="xs">
|
|
E2EE
|
|
</Badge>
|
|
</div>
|
|
|
|
<nav class="flex items-center gap-2">
|
|
<Show
|
|
when={isAuthenticated()}
|
|
fallback={
|
|
<>
|
|
<A
|
|
href="/login"
|
|
class="font-pixel text-[10px] text-white hover:text-orange px-3 py-2"
|
|
>
|
|
LOGIN
|
|
</A>
|
|
<A
|
|
href="/register"
|
|
class="font-pixel text-[10px] bg-orange text-black px-3 py-2 hover:bg-white"
|
|
>
|
|
REGISTER
|
|
</A>
|
|
</>
|
|
}
|
|
>
|
|
<IconButton
|
|
icon={<SearchIcon />}
|
|
ariaLabel="Search"
|
|
size="sm"
|
|
onClick={() => openModal('new-conversation')}
|
|
/>
|
|
<Show when={currentUser()} keyed>
|
|
{(user) => (
|
|
<A
|
|
href="/settings"
|
|
class={`flex items-center gap-2 px-2 py-1 border-2 ${
|
|
location.pathname === '/settings'
|
|
? 'border-orange bg-orange text-black'
|
|
: 'border-transparent text-white hover:text-orange'
|
|
}`}
|
|
>
|
|
<Avatar
|
|
alt={user.display_name}
|
|
size="xs"
|
|
fallback={user.display_name.slice(0, 2)}
|
|
/>
|
|
<span class="font-pixel text-[10px] hidden sm:block">
|
|
{user.display_name}
|
|
</span>
|
|
</A>
|
|
)}
|
|
</Show>
|
|
</Show>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|
|
|
|
function MenuIcon(): JSX.Element {
|
|
return (
|
|
<svg
|
|
width="16"
|
|
height="16"
|
|
viewBox="0 0 16 16"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<rect x="2" y="3" width="12" height="2" />
|
|
<rect x="2" y="7" width="12" height="2" />
|
|
<rect x="2" y="11" width="12" height="2" />
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
function CloseMenuIcon(): JSX.Element {
|
|
return (
|
|
<svg
|
|
width="16"
|
|
height="16"
|
|
viewBox="0 0 16 16"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<rect x="3" y="3" width="2" height="2" />
|
|
<rect x="5" y="5" width="2" height="2" />
|
|
<rect x="7" y="7" width="2" height="2" />
|
|
<rect x="9" y="9" width="2" height="2" />
|
|
<rect x="11" y="11" width="2" height="2" />
|
|
<rect x="11" y="3" width="2" height="2" />
|
|
<rect x="9" y="5" width="2" height="2" />
|
|
<rect x="5" y="9" width="2" height="2" />
|
|
<rect x="3" y="11" width="2" height="2" />
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
function LockIcon(): JSX.Element {
|
|
return (
|
|
<svg
|
|
width="20"
|
|
height="20"
|
|
viewBox="0 0 20 20"
|
|
fill="none"
|
|
aria-hidden="true"
|
|
>
|
|
<rect
|
|
x="6"
|
|
y="3"
|
|
width="8"
|
|
height="2"
|
|
fill="currentColor"
|
|
class="text-orange"
|
|
/>
|
|
<rect
|
|
x="4"
|
|
y="5"
|
|
width="2"
|
|
height="4"
|
|
fill="currentColor"
|
|
class="text-orange"
|
|
/>
|
|
<rect
|
|
x="14"
|
|
y="5"
|
|
width="2"
|
|
height="4"
|
|
fill="currentColor"
|
|
class="text-orange"
|
|
/>
|
|
<rect
|
|
x="3"
|
|
y="9"
|
|
width="14"
|
|
height="2"
|
|
fill="currentColor"
|
|
class="text-orange"
|
|
/>
|
|
<rect
|
|
x="3"
|
|
y="11"
|
|
width="14"
|
|
height="6"
|
|
fill="currentColor"
|
|
class="text-orange"
|
|
/>
|
|
<rect
|
|
x="9"
|
|
y="12"
|
|
width="2"
|
|
height="4"
|
|
fill="currentColor"
|
|
class="text-black"
|
|
/>
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
function SearchIcon(): JSX.Element {
|
|
return (
|
|
<svg
|
|
width="16"
|
|
height="16"
|
|
viewBox="0 0 16 16"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<rect x="4" y="2" width="6" height="2" />
|
|
<rect x="2" y="4" width="2" height="6" />
|
|
<rect x="10" y="4" width="2" height="6" />
|
|
<rect x="4" y="10" width="6" height="2" />
|
|
<rect x="10" y="10" width="2" height="2" />
|
|
<rect x="12" y="12" width="2" height="2" />
|
|
</svg>
|
|
)
|
|
}
|