- LyricSearch: misc/field focus, validation
- Nav: further improvements
This commit is contained in:
BIN
public/images/zim.png
Normal file
BIN
public/images/zim.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -195,6 +195,11 @@ blockquote p:first-of-type::after {
|
|||||||
Custom
|
Custom
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.logo-auth {
|
||||||
|
height: 64px;
|
||||||
|
width: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ export default function LoginPage() {
|
|||||||
<div className="flex items-start justify-center bg-gray-50 dark:bg-[#121212] px-4 pt-20 py-10">
|
<div className="flex items-start justify-center bg-gray-50 dark:bg-[#121212] px-4 pt-20 py-10">
|
||||||
<div className="max-w-md w-full bg-white dark:bg-[#1E1E1E] rounded-2xl shadow-xl px-10 pb-6">
|
<div className="max-w-md w-full bg-white dark:bg-[#1E1E1E] rounded-2xl shadow-xl px-10 pb-6">
|
||||||
<h2 className="flex flex-col items-center text-3xl font-semibold text-gray-900 dark:text-white mb-8 font-sans">
|
<h2 className="flex flex-col items-center text-3xl font-semibold text-gray-900 dark:text-white mb-8 font-sans">
|
||||||
<img className="logo-auth mb-4" src="/images/kode.png" alt="Logo" />
|
<img className="logo-auth mb-4" src="/images/zim.png" alt="Logo" />
|
||||||
Authentication Required
|
Log In
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form className="space-y-6 relative" onSubmit={handleSubmit} noValidate>
|
<form className="space-y-6 relative" onSubmit={handleSubmit} noValidate>
|
||||||
|
|||||||
@@ -324,6 +324,16 @@ export function LyricSearchInputField({ id, placeholder, setShowLyrics }) {
|
|||||||
const statusTitle = statusLabels[inputStatus];
|
const statusTitle = statusLabels[inputStatus];
|
||||||
const StatusIcon = statusIcons[inputStatus] || RemoveRoundedIcon;
|
const StatusIcon = statusIcons[inputStatus] || RemoveRoundedIcon;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const inputEl = autoCompleteInputRef.current;
|
||||||
|
if (!inputEl) return;
|
||||||
|
if (statusTitle) {
|
||||||
|
inputEl.setAttribute("title", statusTitle);
|
||||||
|
} else {
|
||||||
|
inputEl.removeAttribute("title");
|
||||||
|
}
|
||||||
|
}, [statusTitle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="lyric-search-input-wrapper">
|
<div className="lyric-search-input-wrapper">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { metaData, API_URL } from "../config";
|
import { metaData, API_URL } from "../config";
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
const isLoggedIn = Astro.cookies.get('access_token') || Astro.cookies.get('refresh_token');
|
const isLoggedIn = Boolean(Astro.cookies.get('access_token') || Astro.cookies.get('refresh_token'));
|
||||||
|
|
||||||
const padlockIconSvg = `
|
const padlockIconSvg = `
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
||||||
@@ -21,14 +21,27 @@ const externalLinkIconSvg = `
|
|||||||
const navItems = [
|
const navItems = [
|
||||||
{ label: "Home", href: "/" },
|
{ label: "Home", href: "/" },
|
||||||
{ label: "Radio", href: "/radio" },
|
{ label: "Radio", href: "/radio" },
|
||||||
{ label: "Memes", href: "/memes" },
|
{ label: "Memes", href: "/memes" },
|
||||||
{ label: "Lighting", href: "/lighting", auth: true, icon: "padlock" },
|
{ label: "Lighting", href: "/lighting", auth: true },
|
||||||
{ label: "TRip", href: "/TRip", auth: true, icon: "padlock" },
|
{ label: "TRip", href: "/TRip", auth: true, icon: "pirate" },
|
||||||
{ label: "Status", href: "https://status.boatson.boats", icon: "external" },
|
{ label: "Status", href: "https://status.boatson.boats", icon: "external" },
|
||||||
{ label: "Git", href: "https://kode.boatson.boats", icon: "external" },
|
{ label: "Git", href: "https://kode.boatson.boats", icon: "external" },
|
||||||
|
{ label: "Login", href: "/login", guestOnly: true },
|
||||||
...(isLoggedIn ? [{ label: "Logout", href: "#logout", onclick: "handleLogout()" }] : []),
|
...(isLoggedIn ? [{ label: "Logout", href: "#logout", onclick: "handleLogout()" }] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const visibleNavItems = navItems.filter((item) => {
|
||||||
|
if (item.auth && !isLoggedIn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.guestOnly && isLoggedIn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
const currentPath = Astro.url.pathname;
|
const currentPath = Astro.url.pathname;
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -37,7 +50,7 @@ const currentPath = Astro.url.pathname;
|
|||||||
|
|
||||||
<nav class="w-full px-4 sm:px-6 py-4 bg-transparent sticky top-0 z-50 backdrop-blur-sm bg-white/80 dark:bg-[#121212]/80 border-b border-neutral-200/50 dark:border-neutral-800/50">
|
<nav class="w-full px-4 sm:px-6 py-4 bg-transparent sticky top-0 z-50 backdrop-blur-sm bg-white/80 dark:bg-[#121212]/80 border-b border-neutral-200/50 dark:border-neutral-800/50">
|
||||||
<div class="max-w-7xl mx-auto">
|
<div class="max-w-7xl mx-auto">
|
||||||
<div class="flex items-center justify-between">
|
<div class="nav-bar-row flex items-center gap-4 justify-between">
|
||||||
<!-- Logo/Brand -->
|
<!-- Logo/Brand -->
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
@@ -47,9 +60,9 @@ const currentPath = Astro.url.pathname;
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Desktop Navigation -->
|
<!-- Desktop Navigation -->
|
||||||
<div class="desktop-nav flex items-center gap-0.5">
|
<div class="desktop-nav flex items-center">
|
||||||
<ul class="flex items-center gap-0.5">
|
<ul class="desktop-nav-list">
|
||||||
{navItems.map((item) => {
|
{visibleNavItems.map((item) => {
|
||||||
const isExternal = item.href?.startsWith("http");
|
const isExternal = item.href?.startsWith("http");
|
||||||
const isAuthedPath = item.auth ?? false;
|
const isAuthedPath = item.auth ?? false;
|
||||||
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
|
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
|
||||||
@@ -80,6 +93,9 @@ const currentPath = Astro.url.pathname;
|
|||||||
{item.icon === "padlock" && (
|
{item.icon === "padlock" && (
|
||||||
<span class="inline-flex" aria-hidden="true" set:html={padlockIconSvg}></span>
|
<span class="inline-flex" aria-hidden="true" set:html={padlockIconSvg}></span>
|
||||||
)}
|
)}
|
||||||
|
{item.icon === "pirate" && (
|
||||||
|
<span class="inline-flex ml-1" role="img" aria-label="Pirate flag">🏴☠️</span>
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@@ -90,7 +106,7 @@ const currentPath = Astro.url.pathname;
|
|||||||
<button
|
<button
|
||||||
aria-label="Toggle theme"
|
aria-label="Toggle theme"
|
||||||
type="button"
|
type="button"
|
||||||
class="flex items-center justify-center w-8 h-8 ml-1 rounded-md hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
|
class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
|
||||||
onclick="toggleTheme()"
|
onclick="toggleTheme()"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
@@ -137,7 +153,7 @@ const currentPath = Astro.url.pathname;
|
|||||||
class="mobile-menu-dropdown md:hidden"
|
class="mobile-menu-dropdown md:hidden"
|
||||||
>
|
>
|
||||||
<ul class="flex flex-col gap-1 py-4">
|
<ul class="flex flex-col gap-1 py-4">
|
||||||
{navItems.map((item) => {
|
{visibleNavItems.map((item) => {
|
||||||
const isExternal = item.href?.startsWith("http");
|
const isExternal = item.href?.startsWith("http");
|
||||||
const isAuthedPath = item.auth ?? false;
|
const isAuthedPath = item.auth ?? false;
|
||||||
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
|
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
|
||||||
@@ -168,6 +184,9 @@ const currentPath = Astro.url.pathname;
|
|||||||
{item.icon === "padlock" && (
|
{item.icon === "padlock" && (
|
||||||
<span class="inline-flex" aria-hidden="true" set:html={padlockIconSvg}></span>
|
<span class="inline-flex" aria-hidden="true" set:html={padlockIconSvg}></span>
|
||||||
)}
|
)}
|
||||||
|
{item.icon === "pirate" && (
|
||||||
|
<span class="inline-flex ml-1" role="img" aria-label="Pirate flag">🏴☠️</span>
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@@ -222,4 +241,38 @@ const currentPath = Astro.url.pathname;
|
|||||||
nav {
|
nav {
|
||||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user