feat: Initialize core frontend application structure, including layouts, authentication pages, and common UI components.
This commit is contained in:
parent
ae84e7e879
commit
69eb60f901
16 changed files with 1178 additions and 1396 deletions
|
|
@ -2,107 +2,79 @@
|
|||
/**
|
||||
* @file AppSidebar.vue
|
||||
* @description Sidebar navigation for the authenticated dashboard.
|
||||
* Includes navigation links and responsive behaviors.
|
||||
* Uses Quasar QList for structure.
|
||||
*/
|
||||
|
||||
const route = useRoute();
|
||||
const { isAuthenticated } = useAuth(); // Optional if you need auth state
|
||||
const isSidebarOpen = defineModel<boolean>("open"); // Controlled by layout
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const navItems = computed(() => [
|
||||
{
|
||||
to: "/dashboard",
|
||||
label: t('sidebar.overview'),
|
||||
icon: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z",
|
||||
icon: "dashboard", // Using Material Icons names where possible or SVG paths
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/dashboard/my-courses",
|
||||
label: t('sidebar.myCourses'),
|
||||
icon: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253",
|
||||
icon: "school",
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/browse/discovery",
|
||||
label: t('sidebar.browseCourses'),
|
||||
icon: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z",
|
||||
icon: "explore",
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/dashboard/announcements",
|
||||
label: t('sidebar.announcements'),
|
||||
icon: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9",
|
||||
icon: "campaign",
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/dashboard/profile",
|
||||
label: t('sidebar.profile'),
|
||||
icon: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z",
|
||||
icon: "person",
|
||||
isSvg: false
|
||||
},
|
||||
]);
|
||||
|
||||
const isActive = (path: string) => {
|
||||
if (path === "/dashboard") return route.path === "/dashboard";
|
||||
return route.path.startsWith(path);
|
||||
};
|
||||
|
||||
const closeSidebar = () => {
|
||||
isSidebarOpen.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Desktop & Mobile Sidebar -->
|
||||
<aside
|
||||
class="app-sidebar transition-all duration-300"
|
||||
:class="{ open: isSidebarOpen }"
|
||||
>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Menu Items -->
|
||||
<div class="px-2 py-4 space-y-1">
|
||||
<NuxtLink
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
:to="item.to"
|
||||
class="nav-item"
|
||||
:class="{ active: isActive(item.to) }"
|
||||
@click="closeSidebar"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
:d="item.icon"
|
||||
/>
|
||||
</svg>
|
||||
<span>{{ item.label }}</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="flex flex-col h-full bg-white">
|
||||
<!-- Branding Area (Optional if not in Header) -->
|
||||
|
||||
<q-list padding class="text-slate-600 flex-grow">
|
||||
|
||||
<!-- Footer / Version -->
|
||||
<div class="mt-auto p-4 text-xs text-center opacity-50">
|
||||
<p>e-Learning v0.1.0</p>
|
||||
<p>© 2026</p>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<q-item
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
:to="item.to"
|
||||
clickable
|
||||
v-ripple
|
||||
active-class="text-primary bg-blue-50 font-bold"
|
||||
class="rounded-r-full mr-2"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="item.icon" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
|
||||
<!-- Mobile Overlay -->
|
||||
<div
|
||||
class="sidebar-overlay"
|
||||
:class="{ show: isSidebarOpen }"
|
||||
@click="closeSidebar"
|
||||
/>
|
||||
<!-- Footer / Version -->
|
||||
<div class="mt-auto p-4 text-xs text-center opacity-50 pb-8">
|
||||
<p>e-Learning v0.1.0</p>
|
||||
<p>© 2026</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Sidebar styles are mainly handled by global main.css (.app-sidebar) */
|
||||
/* This component structure ensures it hooks into the .app-shell grid correctly */
|
||||
/* Custom styles if needed */
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue