feat(KAN-19): add responsive permission-aware navigation
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
Bell,
|
||||
Columns3,
|
||||
Folder,
|
||||
FolderGit2,
|
||||
House,
|
||||
KeyRound,
|
||||
Layers3,
|
||||
LayoutGrid,
|
||||
ListTodo,
|
||||
Settings2,
|
||||
Shield,
|
||||
Tags,
|
||||
Users,
|
||||
} from 'lucide-vue-next';
|
||||
import { dashboard } from '@/routes';
|
||||
import { index as adminUsers } from '@/routes/admin/users';
|
||||
import { index as templates } from '@/routes/project-templates';
|
||||
import { access, index as projects, show } from '@/routes/projects';
|
||||
import { index as backlog } from '@/routes/projects/backlog';
|
||||
import { index as board } from '@/routes/projects/board';
|
||||
import {
|
||||
board as boardSettings,
|
||||
general,
|
||||
metadata,
|
||||
notifications,
|
||||
repositories,
|
||||
} from '@/routes/projects/settings';
|
||||
import { index as teams } from '@/routes/teams';
|
||||
import type { Localization } from '@/lib/localization';
|
||||
import type { AuthPermissions, NavItem, NavigationProject } from '@/types';
|
||||
|
||||
export function workspaceNavigation(
|
||||
permissions: AuthPermissions,
|
||||
t: Localization['t'],
|
||||
): NavItem[] {
|
||||
const items: NavItem[] = [
|
||||
{
|
||||
title: t('navigation.dashboard'),
|
||||
href: dashboard(),
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
{
|
||||
title: t('navigation.projects'),
|
||||
href: projects(),
|
||||
icon: Folder,
|
||||
match: 'section',
|
||||
},
|
||||
];
|
||||
if (permissions.projectCreate) {
|
||||
items.push({
|
||||
title: t('navigation.templates'),
|
||||
href: templates(),
|
||||
icon: Layers3,
|
||||
match: 'section',
|
||||
});
|
||||
}
|
||||
if (permissions.canManageTeams) {
|
||||
items.push({
|
||||
title: t('navigation.teams'),
|
||||
href: teams(),
|
||||
icon: Users,
|
||||
match: 'section',
|
||||
});
|
||||
}
|
||||
if (permissions.globalAdmin) {
|
||||
items.push({
|
||||
title: t('navigation.users'),
|
||||
href: adminUsers(),
|
||||
icon: Shield,
|
||||
match: 'section',
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
export function projectNavigation(
|
||||
project: NavigationProject | null,
|
||||
t: Localization['t'],
|
||||
): NavItem[] {
|
||||
if (!project) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
title: t('navigation.overview'),
|
||||
href: show(project.id),
|
||||
icon: House,
|
||||
},
|
||||
{
|
||||
title: t('navigation.board'),
|
||||
href: board(project.id),
|
||||
icon: Columns3,
|
||||
match: 'section',
|
||||
},
|
||||
{
|
||||
title: t('navigation.backlog'),
|
||||
href: backlog(project.id),
|
||||
icon: ListTodo,
|
||||
match: 'section',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function projectSettingsNavigation(
|
||||
project: NavigationProject | null,
|
||||
t: Localization['t'],
|
||||
): NavItem[] {
|
||||
if (!project?.canManage) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
title: t('navigation.general'),
|
||||
href: general(project.id),
|
||||
icon: Settings2,
|
||||
},
|
||||
{
|
||||
title: t('navigation.boardSettings'),
|
||||
href: boardSettings(project.id),
|
||||
icon: Columns3,
|
||||
},
|
||||
{
|
||||
title: t('navigation.ticketSettings'),
|
||||
href: metadata(project.id),
|
||||
icon: Tags,
|
||||
},
|
||||
{
|
||||
title: t('navigation.repositories'),
|
||||
href: repositories(project.id),
|
||||
icon: FolderGit2,
|
||||
},
|
||||
{
|
||||
title: t('navigation.notifications'),
|
||||
href: notifications(project.id),
|
||||
icon: Bell,
|
||||
},
|
||||
{
|
||||
title: t('navigation.access'),
|
||||
href: access(project.id),
|
||||
icon: KeyRound,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function matchesNavigationUrl(
|
||||
target: string,
|
||||
current: string,
|
||||
section = false,
|
||||
): boolean {
|
||||
try {
|
||||
const base = 'http://localhost';
|
||||
const targetPath =
|
||||
new URL(target, base).pathname.replace(/\/+$/, '') || '/';
|
||||
const currentPath =
|
||||
new URL(current, base).pathname.replace(/\/+$/, '') || '/';
|
||||
return (
|
||||
currentPath === targetPath ||
|
||||
(section &&
|
||||
targetPath !== '/' &&
|
||||
currentPath.startsWith(`${targetPath}/`))
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user