Added Dashboard page back
This commit is contained in:
parent
8e15b1793b
commit
a84a70fdc2
12 changed files with 166 additions and 197 deletions
|
@ -1,104 +1,99 @@
|
|||
'use client';
|
||||
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { UserContext } from '@/context/user';
|
||||
import Card from '@/ui/Card';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export default function Page() {
|
||||
const { data: me, isLoading } = useContext(UserContext);
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col space-y-4">
|
||||
<div className="w-full">
|
||||
<section className="flex flex-col space-y-4">
|
||||
<section className="w-full flex-col space-y-4">
|
||||
<header>
|
||||
<h3 className="text-xl font-semibold">Tableau de bord</h3>
|
||||
<p className="text-muted">Ceci est la page d'accueil du dashboard</p>
|
||||
<h1 className="text-xl font-semibold">Tableau de bord</h1>
|
||||
<p className="text-highlight-secondary">Ceci est la page d'accueil du dashboard</p>
|
||||
</header>
|
||||
<main className="flex-col justify-between space-x-0 space-y-4 md:flex md:flex-row md:space-x-6 md:space-y-0">
|
||||
<main className="flex-col space-y-4">
|
||||
<div className="w-full flex-col justify-between space-x-0 space-y-4 md:flex md:flex-row md:space-x-6 md:space-y-0">
|
||||
<Card
|
||||
isLoading={isLoading}
|
||||
icon="pie-chart-line"
|
||||
title="Puzzles résolus"
|
||||
data={me?.completions || 0}
|
||||
data={me?.completions ?? 0}
|
||||
link="/dashboard/puzzles"
|
||||
/>
|
||||
<Card
|
||||
isLoading={isLoading}
|
||||
icon="award-line"
|
||||
title="Badges obtenus"
|
||||
data={me?.badges?.length || 'Aucun'}
|
||||
data={me?.badges?.length ?? 'Aucun'}
|
||||
link="/dashboard/badges"
|
||||
/>
|
||||
<Card
|
||||
isLoading={isLoading}
|
||||
icon="bar-chart-line"
|
||||
title="Rang actuel"
|
||||
data={me?.rank || 'Non classé'}
|
||||
data={me?.rank ?? 'Non classé'}
|
||||
link="/dashboard/leaderboard"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<div className="flex flex-col space-y-4">
|
||||
<header>
|
||||
<h2 className="text-lg font-semibold">Derniers puzzles</h2>
|
||||
<p className="text-highlight-secondary">
|
||||
Voici les derniers puzzles que vous avez résolus ou essayer de résoudres
|
||||
</p>
|
||||
</header>
|
||||
<div className="h-full max-h-96 overflow-y-scroll rounded-lg border-2 border-highlight-primary bg-primary-700 p-4 shadow-md">
|
||||
<ul className="flex flex-col space-y-2">
|
||||
{me?.completionsList && me.completionsList.length > 0 ? (
|
||||
me?.completionsList
|
||||
.sort(
|
||||
(a, b) =>
|
||||
a.score - b.score ||
|
||||
a.tries - b.tries ||
|
||||
a.puzzleName.localeCompare(b.puzzleName)
|
||||
)
|
||||
.map((completion, key) => {
|
||||
return (
|
||||
<li key={key} className="flex justify-between space-x-2">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-lg">{completion.puzzleName}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold">
|
||||
Essai{completion.tries > 1 ? 's' : ''}
|
||||
</span>
|
||||
<span className="text-right text-lg text-highlight-secondary">
|
||||
{completion.tries}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold">Score</span>
|
||||
<span className="text-right text-lg text-highlight-secondary">
|
||||
{completion.score}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<li className="m-auto flex items-center justify-center">
|
||||
<span className="text-lg text-highlight-secondary">
|
||||
{isLoading ? 'Chargement en cours...' : 'Aucun puzzles'}
|
||||
</span>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
<div className="h-full w-full flex-col justify-between space-x-0 space-y-4 md:flex md:flex-row md:space-x-6 md:space-y-0">
|
||||
<section className="flex h-full w-full flex-col space-y-4">
|
||||
<header>
|
||||
<h3 className="text-xl font-semibold">Guides</h3>
|
||||
</header>
|
||||
<main className="h-full w-full flex-col justify-between space-x-0 space-y-4 rounded-lg border border-highlight-primary bg-primary-700 md:flex md:flex-row md:space-x-6 md:space-y-0">
|
||||
Work in progress
|
||||
</main>
|
||||
</section>
|
||||
<section className="flex h-full w-full flex-col space-y-4">
|
||||
<header>
|
||||
<h3 className="text-xl font-semibold">Historiques</h3>
|
||||
</header>
|
||||
<main className="h-full w-full flex-col justify-between space-x-0 space-y-4 rounded-lg border border-highlight-primary bg-primary-700 md:flex md:flex-row md:space-x-6 md:space-y-0">
|
||||
Work in progress
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
{/* TODO fix ça c'est pas responsive */}
|
||||
{/* <section className="flex-col space-y-4">
|
||||
<header>
|
||||
<h3 className="text-xl font-semibold">Statistiques</h3>
|
||||
<p className="text-muted">Ceci est la page d'accueil du dashboard</p>
|
||||
</header>
|
||||
<main className="flex-col justify-between space-x-0 space-y-4 sm:flex sm:flex-row sm:space-x-6 sm:space-y-0">
|
||||
<CardTable
|
||||
puzzles={[
|
||||
{ name: 'Jour 0 | Save Conway Gadgetski', id: 1', content: '' },
|
||||
{ name: 'Jour 1 | Next', id: 2', content: '' },
|
||||
{ name: 'Jour 2 | Previous', id: '3', content: '' },
|
||||
{ name: 'Jour 3 | Next 1 loop', id: '4', content: '' },
|
||||
{ name: 'Jour 4 | Next no loop + recursion', id: '5', content: '' },
|
||||
{ name: 'Jour 5 | N first rows', id: '6', content: '' },
|
||||
{ name: 'Week-end | Game of Life', id: '7', content: '' },
|
||||
{ name: 'Jour 0 | Save Conway Gadgetski', id: '1', content: '' },
|
||||
{ name: 'Jour 1 | Next', id: '2', content: '' },
|
||||
{ name: 'Jour 2 | Previous', id: '3', content: '' },
|
||||
{ name: 'Jour 3 | Next 1 loop', id: '4', content: '' },
|
||||
{ name: 'Jour 4 | Next no loop + recursion', id: '5', content: '' },
|
||||
{ name: 'Jour 5 | N first rows', id: '6', content: '' },
|
||||
{ name: 'Week-end | Game of Life', id: '7', content: '' },
|
||||
{ name: 'Jour 0 | Save Conway Gadgetski', id: '1', content: '' },
|
||||
{ name: 'Jour 1 | Next', id: '2', content: '' },
|
||||
{ name: 'Jour 2 | Previous', id: '3', content: '' },
|
||||
{ name: 'Jour 3 | Next 1 loop', id: '4', content: '' },
|
||||
{ name: 'Jour 4 | Next no loop + recursion', id: '5', content: '' },
|
||||
{ name: 'Jour 5 | N first rows', id: '6', content: '' },
|
||||
{ name: 'Week-end | Game of Life', id: '7', content: '' }
|
||||
]}
|
||||
/>
|
||||
<CardTable
|
||||
puzzles={[
|
||||
{ name: 'Jour 0 | Save Conway Gadgetski', id: '1', content: '' },
|
||||
{ name: 'Jour 1 | Next', id: '2', content: '' },
|
||||
{ name: 'Jour 2 | Previous', id: '3', content: '' },
|
||||
{ name: 'Jour 3 | Next 1 loop', id: '4', content: '' },
|
||||
{ name: 'Jour 4 | Next no loop + recursion', id: '5', content: '' },
|
||||
{ name: 'Jour 5 | N first rows', id: '6', content: '' },
|
||||
{ name: 'Week-end | Game of Life', id: '7', content: '' }
|
||||
]}
|
||||
/>
|
||||
</main>
|
||||
</section> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export default function Page() {
|
|||
|
||||
useEffect(() => {
|
||||
router.push('/');
|
||||
}, []);
|
||||
}, [router]);
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import axios from 'axios';
|
||||
|
||||
const fetcher = axios.create({
|
||||
baseURL: process.env.NEXT_PUBLIC_API_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
},
|
||||
insecureHTTPParser: true
|
||||
});
|
||||
|
||||
export default fetcher;
|
|
@ -20,33 +20,33 @@ export type NavItem = {
|
|||
* @type {NavItem[]}
|
||||
*/
|
||||
export const navItems: NavItem[] = [
|
||||
// {
|
||||
// name: 'Dashboard',
|
||||
// slug: '',
|
||||
// icon: 'dashboard-line',
|
||||
// disabled: false
|
||||
// },
|
||||
{
|
||||
name: 'Dashboard',
|
||||
slug: 'dashboard',
|
||||
icon: 'dashboard-line',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: 'Classement',
|
||||
slug: 'leaderboard',
|
||||
slug: 'dashboard/leaderboard',
|
||||
icon: 'line-chart-line',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: 'Puzzles',
|
||||
slug: 'puzzles',
|
||||
slug: 'dashboard/puzzles',
|
||||
icon: 'code-s-slash-line',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: 'Badges',
|
||||
slug: 'badges',
|
||||
slug: 'dashboard/badges',
|
||||
icon: 'award-fill',
|
||||
disabled: false
|
||||
},
|
||||
{
|
||||
name: 'Paramètres',
|
||||
slug: 'settings',
|
||||
slug: 'dashboard/settings',
|
||||
icon: 'equalizer-line',
|
||||
disabled: false
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ export type Player = {
|
|||
tries: number;
|
||||
completions: number;
|
||||
rank: number;
|
||||
completionsList: Completion[];
|
||||
badges: Badge[] | null;
|
||||
};
|
||||
|
||||
|
@ -46,3 +47,9 @@ export type Badge = {
|
|||
level: number;
|
||||
logo?: string;
|
||||
};
|
||||
|
||||
export type Completion = {
|
||||
puzzleName: string;
|
||||
tries: number;
|
||||
score: number;
|
||||
};
|
||||
|
|
25
ui/Card.tsx
25
ui/Card.tsx
|
@ -1,23 +1,28 @@
|
|||
import { getURL } from '@/lib/utils';
|
||||
|
||||
import AppLink from './AppLink';
|
||||
import Icon from './Icon';
|
||||
|
||||
export default function Card({
|
||||
isLoading,
|
||||
icon,
|
||||
title,
|
||||
data
|
||||
data,
|
||||
link
|
||||
}: {
|
||||
isLoading: boolean;
|
||||
icon: string;
|
||||
title: string;
|
||||
data: any;
|
||||
link?: string;
|
||||
}) {
|
||||
if (isLoading)
|
||||
return (
|
||||
<div className="flex w-full items-center space-x-4 rounded-lg border-2 border-highlight-primary bg-primary-700 p-4 shadow-md">
|
||||
<Icon name={icon} className="text-2xl text-muted" />
|
||||
<div className="flex flex-col space-y-4">
|
||||
<span className="h-4 w-32 animate-pulse rounded bg-highlight-primary" />
|
||||
<span className="h-4 w-24 animate-pulse rounded bg-highlight-primary" />
|
||||
<span className="h-[18px] w-32 animate-pulse rounded bg-highlight-primary" />
|
||||
<span className="h-[18px] w-24 animate-pulse rounded bg-highlight-primary" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -25,10 +30,20 @@ export default function Card({
|
|||
return (
|
||||
<div className="flex w-full items-center space-x-4 rounded-lg border-2 border-highlight-primary bg-primary-700 p-4 shadow-md">
|
||||
<Icon name={icon} className="text-2xl text-muted" />
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-xl font-semibold">{data}</h3>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="flex-col">
|
||||
<h2 className="text-xl font-semibold">{data}</h2>
|
||||
<p className="text-muted">{title}</p>
|
||||
</div>
|
||||
{link && (
|
||||
<AppLink
|
||||
className="text-highlight-secondary transition-colors duration-150 hover:text-brand"
|
||||
href={getURL(link)}
|
||||
>
|
||||
<Icon name="arrow-right-line" />
|
||||
</AppLink>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import { type Puzzle } from '@/lib/puzzles';
|
||||
|
||||
import AppLink from './AppLink';
|
||||
|
||||
export default function CardTable({ puzzles }: { puzzles: Puzzle[] }) {
|
||||
return (
|
||||
<></>
|
||||
// <div className="relative flex h-96 w-full overflow-scroll">
|
||||
// <table className="w-full table-auto border-collapse rounded-lg border-2 border-highlight-primary bg-primary-700 text-left text-sm text-muted shadow-md">
|
||||
// {/* <thead className="z-1 sticky -top-1 bg-primary-600 text-xs uppercase text-white ">
|
||||
// <tr>
|
||||
// <th className="px-6 py-3">Exercice</th>
|
||||
// <th className="px-6 py-3">Tentative</th>
|
||||
// <th className="px-6 py-3">Score</th>
|
||||
// <th className="px-6 py-3">Dernier essai</th>
|
||||
// <th className="px-6 py-3">
|
||||
// <span className="sr-only">Reprendre</span>
|
||||
// </th>
|
||||
// </tr>
|
||||
// </thead> */}
|
||||
// <tbody className="overflow-scroll">
|
||||
// {puzzles.length &&
|
||||
// puzzles.map((puzzle) => (
|
||||
// <tr key={puzzle.id} className="bg-primary-700 hover:bg-primary-800 ">
|
||||
// <th scope="row" className="whitespace-nowrap px-6 py-4 font-medium text-white">
|
||||
// {puzzle.name}
|
||||
// </th>
|
||||
// <td className="px-6 py-4">30</td>
|
||||
// <td className="px-6 py-4">300</td>
|
||||
// <td className="px-6 py-4">10/10/2010</td>
|
||||
// <td className="px-6 py-4 text-right">
|
||||
// <AppLink
|
||||
// href={`dashboard/puzzles/${puzzle.id}`}
|
||||
// className="font-medium text-brand hover:underline"
|
||||
// >
|
||||
// Reprendre
|
||||
// </AppLink>
|
||||
// </td>
|
||||
// </tr>
|
||||
// ))}
|
||||
// </tbody>
|
||||
// </table>
|
||||
// </div>
|
||||
);
|
||||
}
|
|
@ -1,37 +1,40 @@
|
|||
'use client';
|
||||
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import useSWRSubscription, { type SWRSubscription } from 'swr/subscription';
|
||||
|
||||
import { type ScoreEvent } from '@/lib/leaderboard';
|
||||
import { useLeaderboardEvent } from '@/lib/hooks/use-leaderboard';
|
||||
import { cn } from '@/lib/utils';
|
||||
import Podium from '@/ui/events/podium/Podium';
|
||||
import { Timer } from './Timer';
|
||||
import { type ScoreEvent } from '@/lib/leaderboard';
|
||||
import useSWRSubscription, { type SWRSubscription } from 'swr/subscription';
|
||||
|
||||
const SCORE_COLORS = ['text-yellow-400', 'text-gray-400', 'text-orange-400'];
|
||||
|
||||
export default function Leaderboard() {
|
||||
export default function Leaderboard({ token }: { token: string }) {
|
||||
// TODO CHANGER CECI
|
||||
const CHAPITRE_EVENT = 1;
|
||||
|
||||
const subscription: SWRSubscription<string, ScoreEvent, Error> = (key, { next }) => {
|
||||
const socket = new WebSocket(key);
|
||||
// const subscription: SWRSubscription<string, ScoreEvent, Error> = (key, { next }) => {
|
||||
// const socket = new WebSocket(key);
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
next(null, JSON.parse(event.data));
|
||||
});
|
||||
// socket.addEventListener('message', (event) => {
|
||||
// next(null, JSON.parse(event.data));
|
||||
// });
|
||||
|
||||
socket.addEventListener('error', (event) => {
|
||||
console.error(event);
|
||||
});
|
||||
// socket.addEventListener('error', (event) => {
|
||||
// console.error(event);
|
||||
// });
|
||||
|
||||
return () => socket.close();
|
||||
};
|
||||
// return () => socket.close();
|
||||
// };
|
||||
|
||||
const { data } = useSWRSubscription(
|
||||
`wss://${process.env.NEXT_PUBLIC_API_URL?.split('//')[1]}/rleaderboard/${CHAPITRE_EVENT}`,
|
||||
subscription
|
||||
);
|
||||
// const { data } = useSWRSubscription(
|
||||
// `wss://${process.env.NEXT_PUBLIC_API_URL?.split('//')[1]}/rleaderboard/${CHAPITRE_EVENT}`,
|
||||
// subscription
|
||||
// );
|
||||
|
||||
const { data, isLoading } = useLeaderboardEvent({ token: token, id: CHAPITRE_EVENT });
|
||||
|
||||
const scores = [data?.groups]
|
||||
.flat()
|
||||
|
@ -60,8 +63,8 @@ export default function Leaderboard() {
|
|||
const tries = group.players.reduce((a, b) => a + b.tries, 0) || 0;
|
||||
return (
|
||||
<motion.li
|
||||
layout
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
// @ts-ignore TODO Je sais pas c'est quoi cette merde
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
|
@ -69,13 +72,18 @@ export default function Leaderboard() {
|
|||
className="flex justify-between space-x-2"
|
||||
>
|
||||
<div className="flex items-center space-x-4">
|
||||
<span className={cn('font-semibold', SCORE_COLORS[group.rank - 1])}>
|
||||
<span
|
||||
className={cn(
|
||||
'font-semibold text-highlight-secondary',
|
||||
SCORE_COLORS[group.rank - 1]
|
||||
)}
|
||||
>
|
||||
{group.rank}
|
||||
</span>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex flex-col gap-x-2 sm:flex-row sm:items-center">
|
||||
<span className="text-lg">{group.name}</span>
|
||||
<span className="text-sm text-muted">
|
||||
<span className="text-sm text-highlight-secondary">
|
||||
{group.players && group.players.length > 1
|
||||
? group.players
|
||||
.map((player) => player.pseudo || 'Anonyme')
|
||||
|
@ -89,15 +97,15 @@ export default function Leaderboard() {
|
|||
<div className="flex items-center space-x-4">
|
||||
{/* <div className="flex flex-col">
|
||||
<span className="text-sm font-semibold">Puzzle{puzzles > 1 ? 's' : ''}</span>
|
||||
<span className="text-lg text-muted">{puzzles}</span>
|
||||
<span className="text-lg text-highlight-secondary">{puzzles}</span>
|
||||
</div> */}
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold">Essai{tries > 1 ? 's' : ''}</span>
|
||||
<span className="text-lg text-muted">{tries}</span>
|
||||
<span className="text-lg text-highlight-secondary">{tries}</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-semibold">Score</span>
|
||||
<span className="text-lg text-muted">
|
||||
<span className="text-lg text-highlight-secondary">
|
||||
{group.players.reduce((a, b) => a + b.score, 0)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -257,14 +257,14 @@ function PuzzleProp({ puzzle, chapter }: { puzzle: Puzzle; chapter: Chapter }) {
|
|||
{puzzle.tags
|
||||
.filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name))
|
||||
.map((tag, i) => (
|
||||
<span key={i} className="inline-block rounded-md bg-primary-900 px-2 py-1">
|
||||
<span key={i} className="inline-block rounded-md bg-primary-800 px-2 py-1">
|
||||
{tag.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Icon
|
||||
className="-translate-x-2 transform-gpu duration-300 group-hover:translate-x-0"
|
||||
className="-translate-x-2 transform-gpu text-highlight-secondary duration-300 group-hover:translate-x-0 group-hover:text-brand"
|
||||
name="arrow-right-line"
|
||||
/>
|
||||
</div>
|
||||
|
@ -292,7 +292,7 @@ function PuzzleProp({ puzzle, chapter }: { puzzle: Puzzle; chapter: Chapter }) {
|
|||
</div>
|
||||
)}
|
||||
<Icon
|
||||
className="-translate-x-2 transform-gpu duration-300 group-hover:translate-x-0"
|
||||
className="-translate-x-2 transform-gpu text-highlight-secondary duration-300 group-hover:translate-x-0"
|
||||
name="arrow-right-line"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,7 @@ export default function ToHTML({ data, className }: { data: string; className?:
|
|||
a: ({ node, ...props }) => (
|
||||
<a
|
||||
{...props}
|
||||
className="inline text-brand-accent hover:text-brand hover:underline"
|
||||
className="inline text-brand transition-colors duration-150 hover:text-brand-accent hover:underline"
|
||||
// MAKE thIS SHIT DOWNLOADABLE
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
|
|
|
@ -37,6 +37,7 @@ export default function UserAuthForm() {
|
|||
avatar: ''
|
||||
}
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname()!;
|
||||
|
@ -101,6 +102,7 @@ export default function UserAuthForm() {
|
|||
<form
|
||||
className="flex w-52 flex-col justify-center space-y-4 sm:w-72"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
method="POST"
|
||||
>
|
||||
{!isSignIn && (
|
||||
<>
|
||||
|
|
|
@ -90,13 +90,12 @@ function NavItem({
|
|||
onClick?: () => void;
|
||||
}) {
|
||||
const segment = useSelectedLayoutSegment();
|
||||
const pathname = segment?.split('/').pop() || '';
|
||||
const isHttp = item.slug.includes('http');
|
||||
const isActive = pathname === item.slug || (item.slug === '' && !segment);
|
||||
const pathname = item.slug.split('/').pop();
|
||||
const isActive = segment === pathname || (segment === null && pathname === 'dashboard');
|
||||
return (
|
||||
<AppLink
|
||||
aria-disabled={item.disabled}
|
||||
href={isHttp ? item.slug : `dashboard/${item.slug}`}
|
||||
href={isHttp ? item.slug : `/${item.slug}`}
|
||||
target={isHttp ? '_blank' : undefined}
|
||||
rel={isHttp ? 'noopener noreferrer' : undefined}
|
||||
className={cn(
|
||||
|
|
Loading…
Add table
Reference in a new issue