feat: Add user display in navigation
misc: styling/css cleanup
This commit is contained in:
126
src/assets/styles/nav.css
Normal file
126
src/assets/styles/nav.css
Normal file
@@ -0,0 +1,126 @@
|
||||
/* Desktop navigation - visible on medium screens and up */
|
||||
.desktop-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-nav {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile navigation - visible below medium screens */
|
||||
.mobile-nav {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile menu dropdown */
|
||||
.mobile-menu-dropdown {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mobile-menu-dropdown.open {
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-menu-dropdown {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-bar-row {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-nav {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
margin-left: 2rem;
|
||||
gap: clamp(0.75rem, 1.5vw, 1.25rem);
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-nav-list {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: clamp(0.75rem, 1.5vw, 1.25rem);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.desktop-nav-list li {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.desktop-nav-list a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-user-inline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.3rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.4);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
color: #1e293b;
|
||||
background: linear-gradient(120deg, rgba(255, 255, 255, 0.9), rgba(226, 232, 240, 0.85));
|
||||
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .nav-user-inline {
|
||||
color: #f1f5f9;
|
||||
border-color: rgba(59, 130, 246, 0.25);
|
||||
background: linear-gradient(120deg, rgba(15, 23, 42, 0.85), rgba(30, 41, 59, 0.7));
|
||||
box-shadow: 0 14px 35px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.nav-user-inline__icon {
|
||||
display: inline-flex;
|
||||
width: 0.95rem;
|
||||
height: 0.95rem;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.nav-user-inline__icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nav-user-inline__label {
|
||||
text-transform: uppercase;
|
||||
font-size: 0.65rem;
|
||||
letter-spacing: 0.08em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.nav-user-inline__name {
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-user-inline--mobile {
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { AutoComplete } from "primereact/autocomplete";
|
||||
import { authFetch } from "@/utils/authFetch";
|
||||
import BreadcrumbNav from "./BreadcrumbNav";
|
||||
import { API_URL, ENVIRONMENT } from "@/config";
|
||||
import "./MediaRequestForm.css";
|
||||
|
||||
export default function MediaRequestForm() {
|
||||
const [type, setType] = useState("artist");
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
---
|
||||
import { metaData, API_URL } from "../config";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import { requireAuthHook } from "@/hooks/requireAuthHook";
|
||||
import { padlockIconSvg, userIconSvg, externalLinkIconSvg } from "@/utils/navAssets";
|
||||
import "@/assets/styles/nav.css";
|
||||
|
||||
const isLoggedIn = Boolean(Astro.cookies.get('access_token') || Astro.cookies.get('refresh_token'));
|
||||
const user = await requireAuthHook(Astro);
|
||||
const isLoggedIn = Boolean(user);
|
||||
const userDisplayName = user?.user ?? null;
|
||||
const userInitial = userDisplayName ? String(userDisplayName).charAt(0).toUpperCase() : '?';
|
||||
|
||||
const padlockIconSvg = `
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.5 11V9a3.5 3.5 0 1 1 7 0v2" />
|
||||
<rect x="7" y="11" width="10" height="8.5" rx="1.8" />
|
||||
<circle cx="12" cy="15" r="1.2" fill="currentColor" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
const externalLinkIconSvg = `
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
const navItems = [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Radio", href: "/radio" },
|
||||
{ label: "Memes", href: "/memes" },
|
||||
{ label: "TRip", href: "/TRip", auth: true, icon: "pirate" },
|
||||
{ label: "Lighting", href: "/lighting", auth: true },
|
||||
{ label: "TRip", href: "/TRip", auth: true, icon: "pirate" },
|
||||
{ label: "Status", href: "https://status.boatson.boats", icon: "external" },
|
||||
{ label: "Git", href: "https://kode.boatson.boats", icon: "external" },
|
||||
{ label: "Login", href: "/login", guestOnly: true },
|
||||
@@ -102,6 +95,13 @@ const currentPath = Astro.url.pathname;
|
||||
})}
|
||||
</ul>
|
||||
|
||||
{isLoggedIn && userDisplayName && (
|
||||
<div class="nav-user-inline" title={`Logged in as ${userDisplayName}`}>
|
||||
<span class="nav-user-inline__icon" aria-hidden="true" set:html={userIconSvg}></span>
|
||||
<span class="nav-user-inline__name">{userDisplayName}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- Theme Toggle Desktop -->
|
||||
<button
|
||||
aria-label="Toggle theme"
|
||||
@@ -152,6 +152,12 @@ const currentPath = Astro.url.pathname;
|
||||
id="mobile-menu"
|
||||
class="mobile-menu-dropdown md:hidden"
|
||||
>
|
||||
{isLoggedIn && userDisplayName && (
|
||||
<div class="nav-user-inline nav-user-inline--mobile" title={`Logged in as ${userDisplayName}`}>
|
||||
<span class="nav-user-inline__icon" aria-hidden="true" set:html={userIconSvg}></span>
|
||||
<span class="nav-user-inline__name">{userDisplayName}</span>
|
||||
</div>
|
||||
)}
|
||||
<ul class="flex flex-col gap-1 py-4">
|
||||
{visibleNavItems.map((item) => {
|
||||
const isExternal = item.href?.startsWith("http");
|
||||
@@ -195,84 +201,3 @@ const currentPath = Astro.url.pathname;
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
/* Desktop navigation - visible on medium screens and up */
|
||||
.desktop-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-nav {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile navigation - visible below medium screens */
|
||||
.mobile-nav {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile menu dropdown */
|
||||
.mobile-menu-dropdown {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mobile-menu-dropdown.open {
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-menu-dropdown {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-bar-row {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-nav {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
margin-left: 2rem;
|
||||
gap: clamp(0.75rem, 1.5vw, 1.25rem);
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-nav-list {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: clamp(0.75rem, 1.5vw, 1.25rem);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.desktop-nav-list li {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.desktop-nav-list a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@ if (!user || !user.roles.includes('lighting')) {
|
||||
<Base>
|
||||
<section>
|
||||
<div class="prose prose-neutral dark:prose-invert">
|
||||
<Root child="Lighting" user={user} client:only="react" />
|
||||
<Root child="Lighting" user?={user} client:only="react" />
|
||||
</div>
|
||||
</section>
|
||||
</Base>
|
||||
|
||||
20
src/utils/navAssets.js
Normal file
20
src/utils/navAssets.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export const padlockIconSvg = `
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.5 11V9a3.5 3.5 0 1 1 7 0v2" />
|
||||
<rect x="7" y="11" width="10" height="8.5" rx="1.8" />
|
||||
<circle cx="12" cy="15" r="1.2" fill="currentColor" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const userIconSvg = `
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="9" r="3.2" />
|
||||
<path d="M5.5 19.5a6.5 6.5 0 0 1 13 0" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
export const externalLinkIconSvg = `
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||
</svg>
|
||||
`;
|
||||
Reference in New Issue
Block a user