Updated main app

This commit is contained in:
Viswamedha Nalabotu 2025-12-17 14:28:16 +00:00
parent 91df929dad
commit a10632e4bf

View file

@ -1,83 +1,261 @@
<script setup lang="ts"> <script setup lang="ts">
// Navbar is intentionally simple authentication is not handled here. import { computed, onMounted } from 'vue';
import { Layout, Menu, Button, Space, Typography } from 'ant-design-vue';
import type { MenuProps } from 'ant-design-vue';
import {
HomeOutlined,
InfoCircleOutlined,
RocketOutlined,
ReadOutlined,
TeamOutlined,
RobotOutlined,
BulbOutlined,
AppstoreOutlined,
DashboardOutlined,
LoginOutlined,
UserAddOutlined,
} from '@ant-design/icons-vue';
import { useRoute, useRouter } from 'vue-router';
import { useAuthStore } from '../stores/authStore';
const router = useRouter();
const route = useRoute();
const authStore = useAuthStore();
const navItems = [
{
key: '/',
label: 'Home',
icon: HomeOutlined,
path: '/',
},
{
key: '/about',
label: 'About',
icon: InfoCircleOutlined,
path: '/about',
},
{
key: '/onboarding',
label: 'Onboarding',
icon: RocketOutlined,
path: '/onboarding',
},
{
key: '/training',
label: 'Training',
icon: ReadOutlined,
path: '/training',
},
{
key: '/roles',
label: 'Roles',
icon: TeamOutlined,
path: '/roles',
roles: ['manager', 'admin'],
},
{
key: '/agents',
label: 'Agents',
icon: RobotOutlined,
path: '/agents',
roles: ['manager', 'admin'],
},
{
key: '/assessments',
label: 'Assessments',
icon: BulbOutlined,
path: '/assessments',
},
{
key: '/resources',
label: 'Resources',
icon: AppstoreOutlined,
path: '/resources',
},
{
key: '/progress',
label: 'Progress',
icon: DashboardOutlined,
path: '/progress',
},
];
const visibleNavItems = computed(() =>
navItems.filter((item) =>
item.roles ? authStore.hasRole(item.roles) : true
)
);
const selectedKeys = computed(() => {
const match = visibleNavItems.value.find((item) =>
route.path.startsWith(item.key)
);
return match ? [match.key] : [];
});
const onSelect: MenuProps['onSelect'] = ({ key }) => {
const item = visibleNavItems.value.find((n) => n.key === key);
if (item) router.push(item.path);
};
const handleLogout = async () => {
await authStore.logout();
router.push('/');
};
onMounted(() => {
authStore.fetchSession();
});
</script> </script>
<template> <template>
<div> <Layout class="shell">
<nav class="topnav"> <Layout.Header class="shell-header">
<div class="brand"> <div class="brand" @click="router.push('/')">Dynavera</div>
<router-link to="/">Agentic Trainers</router-link> <Menu
</div> mode="horizontal"
theme="dark"
:selectedKeys="selectedKeys"
class="shell-menu"
@select="onSelect"
>
<Menu.Item v-for="item in visibleNavItems" :key="item.key">
<Space size="small">
<component :is="item.icon" />
<span>{{ item.label }}</span>
</Space>
</Menu.Item>
</Menu>
<Space>
<template v-if="authStore.isAuthenticated">
<Typography.Text class="user-chip" strong>
{{ authStore.displayName || 'Account' }}
</Typography.Text>
<Button
ghost
:loading="authStore.loading"
@click="handleLogout"
>
Logout
</Button>
</template>
<template v-else>
<Button ghost @click="router.push('/login')">
<LoginOutlined /> Login
</Button>
<Button type="primary" @click="router.push('/register')">
<UserAddOutlined /> Register
</Button>
</template>
</Space>
</Layout.Header>
<ul class="navlinks"> <Layout class="shell-body">
<li><router-link to="/">Home</router-link></li> <Layout.Content class="shell-content">
<li><router-link to="/about">About</router-link></li> <router-view />
<li><router-link to="/onboarding">Onboarding</router-link></li> </Layout.Content>
<li><router-link to="/training">Training</router-link></li> <Layout.Footer class="shell-footer">
<li><router-link to="/roles">Roles</router-link></li> <Typography.Text type="secondary">
<li><router-link to="/agents">Agents</router-link></li> <strong>Project Disclaimer:</strong> This is a
<li> proof-of-concept demo project for educational purposes. All
<router-link to="/assessments">Assessments</router-link> testimonials, statistics, and company names are fictional
</li> placeholders.
<li><router-link to="/resources">Resources</router-link></li> </Typography.Text>
<li><router-link to="/progress">Progress</router-link></li> </Layout.Footer>
</ul> </Layout>
</Layout>
<ul class="navlinks">
<li><router-link to="/login">Login</router-link></li>
<li><router-link to="/register">Register</router-link></li>
</ul>
</nav>
<main>
<router-view />
</main>
</div>
</template> </template>
<style scoped> <style scoped>
.topnav { .shell {
display: flex; min-height: 100vh;
justify-content: space-between; background: #0b1220;
align-items: center;
padding: 0.75rem 1rem;
background: #fff;
border-bottom: 1px solid #e5e7eb;
} }
.brand a { .shell-header {
display: flex;
align-items: center;
gap: 1rem;
padding: 0 1.25rem;
background: #0f172a;
}
.brand {
color: #e5e7eb;
font-weight: 700; font-weight: 700;
color: #111827;
text-decoration: none;
}
.navlinks {
list-style: none;
display: flex;
gap: 0.75rem;
margin: 0;
padding: 0;
align-items: center;
}
.navlinks a {
color: #4b5563;
text-decoration: none;
padding: 0.25rem 0.5rem;
}
.navlinks a.router-link-active {
color: #4f46e5;
font-weight: 600;
}
.user {
margin-left: 0.5rem;
color: #374151;
}
.link-logout {
background: none;
border: none;
color: #ef4444;
cursor: pointer; cursor: pointer;
margin-left: 0.5rem; font-size: 1.05rem;
} }
main { .shell-menu {
padding: 1rem; flex: 1;
background: transparent;
border-bottom: none;
}
.shell-body {
background: #0b1220;
min-height: calc(100vh - 64px);
display: flex;
flex-direction: column;
}
.shell-content {
padding: 24px;
flex: 1;
min-height: calc(100vh - 64px - 64px);
}
.shell-footer {
text-align: center;
background: #0f172a;
}
:deep(.ant-menu-dark) {
background: transparent;
}
:deep(.ant-menu-dark .ant-menu-item-selected) {
background: transparent !important;
}
:deep(.ant-typography),
:deep(.ant-typography p),
:deep(.ant-typography span),
:deep(.ant-list-item),
:deep(.ant-list-item-meta-title),
:deep(.ant-list-item-meta-description),
:deep(.ant-statistic-title),
:deep(.ant-statistic-content),
:deep(.ant-card-meta-title),
:deep(.ant-card-meta-description) {
color: #e5e7eb;
}
:deep(.ant-typography-secondary) {
color: #cbd5e1 !important;
}
:deep(.ant-form-item-label > label) {
color: #e5e7eb;
}
:deep(.ant-input),
:deep(.ant-select-selector),
:deep(.ant-select-selection-item),
:deep(.ant-picker-input input) {
background: #111827;
color: #e5e7eb;
border-color: #334155;
}
:deep(.ant-input::placeholder),
:deep(.ant-select-selection-placeholder),
:deep(.ant-picker-input input::placeholder) {
color: #9ca3af;
}
:deep(.ant-card) {
background: #0f172a;
border-color: #1f2937;
}
:deep(.ant-btn:not(.ant-btn-primary)) {
color: #e5e7eb;
border-color: #334155;
background: #111827;
}
:deep(.ant-btn-primary) {
background: linear-gradient(90deg, #6366f1, #8b5cf6);
border: none;
}
.user-chip {
color: #e5e7eb;
} }
</style> </style>