fix: strip existing sso param from clientUrl, add aria roles to dropdowns, add x-pathname fallback, move .dropdown-menu into @layer components
This commit is contained in:
1 parent
7e616ca6b3
commit
187af2e147
4 files changed
+37
-37
No files matched your search
@@ -81,8 +81,9 @@ export default function ClientPage() {
|
|||||||
|
|
||||||
const getClientSrc = useCallback(() => {
|
const getClientSrc = useCallback(() => {
|
||||||
if (!ticket) return "";
|
if (!ticket) return "";
|
||||||
const sep = clientUrl.includes("?") ? "&" : "?";
|
const base = clientUrl.replace(/(\?|&)sso=[^&]*/, "");
|
||||||
return `${clientUrl}${sep}sso=${encodeURIComponent(ticket)}`;
|
const sep = base.includes("?") ? "&" : "?";
|
||||||
|
return `${base}${sep}sso=${encodeURIComponent(ticket)}`;
|
||||||
}, [clientUrl, ticket]);
|
}, [clientUrl, ticket]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|||||||
+22
-26
@@ -146,6 +146,28 @@ body {
|
|||||||
background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
background-color: var(--color-dropdown);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-text-muted) 14%, transparent);
|
||||||
|
box-shadow: 0 8px 32px color-mix(in srgb, rgb(0, 0, 0) 20%, transparent);
|
||||||
|
transform-origin: top right;
|
||||||
|
transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1),
|
||||||
|
transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-8px) scale(0.95);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
details[open] > .dropdown-menu {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
@starting-style {
|
||||||
|
details[open] > .dropdown-menu {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-8px) scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Atom icons / backgrounds (asset paths adapted to /assets) ── */
|
/* ── Atom icons / backgrounds (asset paths adapted to /assets) ── */
|
||||||
@@ -723,32 +745,6 @@ tbody tr:hover {
|
|||||||
border-color: #f97316;
|
border-color: #f97316;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Dropdown menu (solid color + animation) ─────────────────── */
|
|
||||||
.dropdown-menu {
|
|
||||||
background-color: var(--color-dropdown);
|
|
||||||
border: 1px solid color-mix(in srgb, var(--color-text-muted) 14%, transparent);
|
|
||||||
box-shadow: 0 8px 32px color-mix(in srgb, rgb(0, 0, 0) 20%, transparent);
|
|
||||||
transform-origin: top right;
|
|
||||||
transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1),
|
|
||||||
transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-8px) scale(0.95);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open] > .dropdown-menu {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0) scale(1);
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@starting-style {
|
|
||||||
details[open] > .dropdown-menu {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-8px) scale(0.95);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Radio sidebar ──────────────────────────────────────────── */
|
/* ── Radio sidebar ──────────────────────────────────────────── */
|
||||||
.radio-layout {
|
.radio-layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ export default async function RootLayout({ children }: { children: ReactNode })
|
|||||||
const defaultDark = await siteSettings.getBool("default_dark", false);
|
const defaultDark = await siteSettings.getBool("default_dark", false);
|
||||||
|
|
||||||
const headersList = await headers();
|
const headersList = await headers();
|
||||||
const pathname = headersList.get("x-pathname") || "";
|
const pathname = headersList.get("x-pathname") || headersList.get("next-url") || "";
|
||||||
const isClient = pathname === "/client" || pathname.startsWith("/client/");
|
const isClient = pathname === "/client" || pathname.startsWith("/client/");
|
||||||
return (
|
return (
|
||||||
<html lang={locale} className={`app ${nunito.variable}`}>
|
<html lang={locale} className={`app ${nunito.variable}`}>
|
||||||
|
|||||||
@@ -67,15 +67,16 @@ export async function TopHeader() {
|
|||||||
Administration
|
Administration
|
||||||
</summary>
|
</summary>
|
||||||
<div
|
<div
|
||||||
|
role="menu"
|
||||||
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[180px] rounded-xl z-50 py-2"
|
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[180px] rounded-xl z-50 py-2"
|
||||||
>
|
>
|
||||||
<Link href="/admin" className="dropdown-item">
|
<Link href="/admin" className="dropdown-item" role="menuitem">
|
||||||
Admin panel
|
Admin panel
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/admin/commandocentrum" className="dropdown-item">
|
<Link href="/admin/commandocentrum" className="dropdown-item" role="menuitem">
|
||||||
Commandocentrum
|
Commandocentrum
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/admin/logs" className="dropdown-item">
|
<Link href="/admin/logs" className="dropdown-item" role="menuitem">
|
||||||
Logs
|
Logs
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,21 +90,22 @@ export async function TopHeader() {
|
|||||||
<span className="-ml-2 font-semibold" style={{ color: "var(--color-navbar-text, var(--color-text))" }}>{session.user.name}</span>
|
<span className="-ml-2 font-semibold" style={{ color: "var(--color-navbar-text, var(--color-text))" }}>{session.user.name}</span>
|
||||||
</summary>
|
</summary>
|
||||||
<div
|
<div
|
||||||
|
role="menu"
|
||||||
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2"
|
className="dropdown-menu absolute right-0 top-full mt-0.5 min-w-[200px] rounded-xl z-50 py-2"
|
||||||
>
|
>
|
||||||
<Link href="/me" className="dropdown-item">
|
<Link href="/me" className="dropdown-item" role="menuitem">
|
||||||
My dashboard
|
My dashboard
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/u/${session.user.name}`} className="dropdown-item">
|
<Link href={`/u/${session.user.name}`} className="dropdown-item" role="menuitem">
|
||||||
My profile
|
My profile
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/settings" className="dropdown-item">
|
<Link href="/settings" className="dropdown-item" role="menuitem">
|
||||||
User settings
|
User settings
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/settings/2fa" className="dropdown-item">
|
<Link href="/settings/2fa" className="dropdown-item" role="menuitem">
|
||||||
Two-factor
|
Two-factor
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/settings/sessions" className="dropdown-item">
|
<Link href="/settings/sessions" className="dropdown-item" role="menuitem">
|
||||||
Login activity
|
Login activity
|
||||||
</Link>
|
</Link>
|
||||||
<div className="h-px my-1 mx-3" style={{ backgroundColor: "color-mix(in srgb, var(--color-text-muted) 12%, transparent)" }} />
|
<div className="h-px my-1 mx-3" style={{ backgroundColor: "color-mix(in srgb, var(--color-text-muted) 12%, transparent)" }} />
|
||||||
@@ -115,6 +117,7 @@ export async function TopHeader() {
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
role="menuitem"
|
||||||
className="dropdown-item w-full text-center mx-1 rounded-lg"
|
className="dropdown-item w-full text-center mx-1 rounded-lg"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "color-mix(in srgb, var(--button-danger-color) 12%, transparent)",
|
backgroundColor: "color-mix(in srgb, var(--button-danger-color) 12%, transparent)",
|
||||||
|
|||||||
Reference in new issue
Block a user