Redesign beta Magent UI
This commit is contained in:
@@ -22,6 +22,7 @@ export default function AdminShell({ title, subtitle, actions, rail, children }:
|
||||
<main className="card admin-card">
|
||||
<div className="admin-header">
|
||||
<div>
|
||||
<span className="section-kicker">Beta stream</span>
|
||||
<h1>{title}</h1>
|
||||
{subtitle && <p className="lede">{subtitle}</p>}
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
const NAV_GROUPS = [
|
||||
{
|
||||
title: 'Operations',
|
||||
items: [
|
||||
{ href: '/admin', label: 'Overview' },
|
||||
{ href: '/', label: 'Health' },
|
||||
{ href: '/portal/requests', label: 'Request portal' },
|
||||
{ href: '/admin/issues', label: 'Issue tracking' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Services',
|
||||
items: [
|
||||
@@ -21,6 +30,7 @@ const NAV_GROUPS = [
|
||||
{ href: '/admin/requests', label: 'Request sync' },
|
||||
{ href: '/admin/requests-all', label: 'All requests' },
|
||||
{ href: '/admin/cache', label: 'Cache Control' },
|
||||
{ href: '/admin/artwork', label: 'Artwork cache' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,14 +1,44 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
type BrandingLogoProps = {
|
||||
className?: string
|
||||
alt?: string
|
||||
}
|
||||
|
||||
export default function BrandingLogo({ className, alt = 'Magent logo' }: BrandingLogoProps) {
|
||||
const [loaded, setLoaded] = useState(false)
|
||||
const [failed, setFailed] = useState(false)
|
||||
|
||||
return (
|
||||
<img
|
||||
className={className}
|
||||
src="/api/branding/logo.png"
|
||||
alt={alt}
|
||||
/>
|
||||
<span className={`${className ?? ''} branding-logo-shell`} role="img" aria-label={alt}>
|
||||
{!failed ? (
|
||||
<img
|
||||
className={loaded ? 'is-loaded' : undefined}
|
||||
src="/api/branding/logo.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
onLoad={() => setLoaded(true)}
|
||||
onError={() => setFailed(true)}
|
||||
/>
|
||||
) : null}
|
||||
{!loaded ? (
|
||||
<svg aria-hidden="true" viewBox="0 0 64 64" focusable="false">
|
||||
<defs>
|
||||
<linearGradient id="magentLogoGlow" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stopColor="#7ed7ff" />
|
||||
<stop offset="100%" stopColor="#c6c1ff" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="64" height="64" rx="12" fill="#0b1328" />
|
||||
<rect x="6" y="6" width="52" height="52" rx="9" fill="#111a33" />
|
||||
<path
|
||||
d="M16 48V16h8l8 13 8-13h8v32h-8V30l-8 12-8-12v18h-8z"
|
||||
fill="url(#magentLogoGlow)"
|
||||
/>
|
||||
</svg>
|
||||
) : null}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { authFetch, clearToken, getApiBase, getToken } from '../lib/auth'
|
||||
|
||||
export default function HeaderActions() {
|
||||
const [signedIn, setSignedIn] = useState(false)
|
||||
const [role, setRole] = useState<string | null>(null)
|
||||
const pathname = usePathname()
|
||||
|
||||
useEffect(() => {
|
||||
const token = getToken()
|
||||
@@ -19,9 +22,11 @@ export default function HeaderActions() {
|
||||
if (!response.ok) {
|
||||
clearToken()
|
||||
setSignedIn(false)
|
||||
setRole(null)
|
||||
return
|
||||
}
|
||||
await response.json()
|
||||
const data = await response.json()
|
||||
setRole(data?.role ?? null)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
@@ -33,18 +38,45 @@ export default function HeaderActions() {
|
||||
return null
|
||||
}
|
||||
|
||||
const items = [
|
||||
{ href: '/', label: 'Health', icon: '01', match: (path: string) => path === '/' },
|
||||
{
|
||||
href: '/portal/requests',
|
||||
label: 'Requests',
|
||||
icon: '02',
|
||||
match: (path: string) => path === '/portal/requests' || path.startsWith('/requests/'),
|
||||
},
|
||||
{
|
||||
href: '/portal/issues',
|
||||
label: 'Issues',
|
||||
icon: '03',
|
||||
match: (path: string) => path === '/portal/issues' || path === '/admin/issues',
|
||||
},
|
||||
{
|
||||
href: role === 'admin' ? '/users' : '/profile',
|
||||
label: role === 'admin' ? 'Users' : 'Profile',
|
||||
icon: '04',
|
||||
match: (path: string) => path.startsWith('/users') || path.startsWith('/profile'),
|
||||
},
|
||||
{
|
||||
href: role === 'admin' ? '/admin' : '/profile/invites',
|
||||
label: role === 'admin' ? 'Config' : 'Invites',
|
||||
icon: '05',
|
||||
match: (path: string) => path.startsWith('/admin') || path.startsWith('/profile/invites'),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="header-actions">
|
||||
<a className="header-cta header-cta--left" href="/feedback">Send feedback</a>
|
||||
<div className="header-actions-center">
|
||||
<a href="/how-it-works">How it works</a>
|
||||
</div>
|
||||
<div className="header-actions-right">
|
||||
<a href="/">Requests</a>
|
||||
<a href="/profile/invites">Invites</a>
|
||||
<a href="/portal/requests">Portal</a>
|
||||
<a href="/portal/issues">Issues</a>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="header-actions" aria-label="Primary">
|
||||
{items.map((item) => {
|
||||
const active = item.match(pathname)
|
||||
return (
|
||||
<a key={item.href} href={item.href} className={active ? 'is-active' : undefined}>
|
||||
<span aria-hidden="true">{item.icon}</span>
|
||||
{item.label}
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user