feat: Implement initial application layouts, global navigation, and course browsing pages with i18n support.
All checks were successful
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Successful in 41s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Successful in 4s
Build and Deploy Frontend Learner / Notify Deployment Status (push) Successful in 1s
All checks were successful
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Successful in 41s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Successful in 4s
Build and Deploy Frontend Learner / Notify Deployment Status (push) Successful in 1s
This commit is contained in:
parent
b56f604890
commit
3fa236cff5
15 changed files with 993 additions and 392 deletions
|
|
@ -41,6 +41,17 @@ const searchText = ref('')
|
|||
<span class="text-[10px] font-bold uppercase tracking-[0.2em] leading-none mt-1 text-slate-500 dark:text-slate-400">Platform</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<nav class="hidden md:flex items-center gap-6 ml-8 text-sm font-bold">
|
||||
<NuxtLink to="/browse" class="text-slate-600 hover:text-blue-600 transition-colors">
|
||||
{{ $t('sidebar.onlineCourses') }}
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/browse/discovery" class="text-slate-600 hover:text-blue-600 transition-colors">
|
||||
{{ $t('sidebar.recommendedCourses') }}
|
||||
</NuxtLink>
|
||||
|
||||
</nav>
|
||||
|
||||
<q-space />
|
||||
|
||||
|
|
|
|||
|
|
@ -5,28 +5,10 @@
|
|||
* Uses Quasar QList for structure.
|
||||
*/
|
||||
|
||||
const { sidebarItems } = useNavItems()
|
||||
const { t } = useI18n()
|
||||
const navItems = sidebarItems
|
||||
|
||||
const navItems = computed(() => [
|
||||
{
|
||||
to: "/dashboard",
|
||||
label: t('sidebar.overview'),
|
||||
icon: "dashboard", // Using Material Icons names where possible or SVG paths
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/browse/discovery",
|
||||
label: t('sidebar.browseCourses'),
|
||||
icon: "explore",
|
||||
isSvg: false
|
||||
},
|
||||
{
|
||||
to: "/dashboard/my-courses",
|
||||
label: t('sidebar.myCourses'),
|
||||
icon: "school",
|
||||
isSvg: false
|
||||
}
|
||||
]);
|
||||
|
||||
const handleNavigate = (path: string) => {
|
||||
if (import.meta.client) {
|
||||
|
|
@ -55,7 +37,7 @@ const handleNavigate = (path: string) => {
|
|||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label class="font-bold text-sm">{{ item.label }}</q-item-label>
|
||||
<q-item-label class="font-bold text-sm">{{ $t(item.labelKey) }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
|
|
|
|||
|
|
@ -27,10 +27,8 @@ onMounted(() => {
|
|||
:class="[isScrolled ? 'h-16 glass-nav shadow-lg' : 'h-24 bg-transparent']"
|
||||
>
|
||||
<div class="container h-full flex items-center justify-between">
|
||||
<!--
|
||||
Left Section: Logo & Desktop Navigation
|
||||
-->
|
||||
<div class="flex items-center gap-12">
|
||||
<!-- Left Section: Logo & Desktop Navigation -->
|
||||
<div class="flex items-center gap-8">
|
||||
<!-- Logo -->
|
||||
<NuxtLink to="/" class="flex items-center gap-3 group">
|
||||
<div class="logo-box bg-blue-600 text-white font-black rounded-xl w-10 h-10 flex items-center justify-center shadow-lg shadow-blue-600/30 group-hover:scale-110 transition-transform">
|
||||
|
|
@ -53,35 +51,28 @@ onMounted(() => {
|
|||
</NuxtLink>
|
||||
|
||||
<!-- Desktop Links -->
|
||||
<nav class="hidden md:block">
|
||||
<ul class="flex items-center gap-8 text-sm font-bold">
|
||||
<li>
|
||||
<NuxtLink
|
||||
to="/browse"
|
||||
class="transition-colors relative group"
|
||||
:class="[isScrolled ? 'text-slate-400 hover:text-white' : 'text-slate-600 hover:text-blue-600']"
|
||||
>
|
||||
{{ $t('landing.allCourses') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li>
|
||||
<NuxtLink
|
||||
to="/browse/discovery"
|
||||
class="transition-colors relative group"
|
||||
:class="[isScrolled ? 'text-slate-400 hover:text-white' : 'text-slate-600 hover:text-blue-600']"
|
||||
>
|
||||
{{ $t('landing.discovery') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
<nav class="flex items-center gap-6 text-sm font-bold">
|
||||
<NuxtLink
|
||||
to="/browse"
|
||||
class="transition-colors relative group"
|
||||
:class="[isScrolled ? 'text-slate-400 hover:text-white' : 'text-slate-600 hover:text-blue-600']"
|
||||
>
|
||||
{{ $t('sidebar.onlineCourses') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
to="/browse/recommended"
|
||||
class="transition-colors relative group"
|
||||
:class="[isScrolled ? 'text-slate-400 hover:text-white' : 'text-slate-600 hover:text-blue-600']"
|
||||
>
|
||||
{{ $t('sidebar.recommendedCourses') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Right Section: Action Buttons (Login/Register or Dashboard)
|
||||
-->
|
||||
<!-- Right Section: Action Buttons -->
|
||||
<div class="flex items-center gap-4">
|
||||
<template v-if="!isAuthenticated">
|
||||
<NuxtLink
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
|
||||
const navItems = computed(() => [
|
||||
{ to: '/dashboard', icon: 'dashboard', label: t('sidebar.overview') },
|
||||
{ to: '/browse/discovery', icon: 'explore', label: t('sidebar.browseCourses') },
|
||||
{ to: '/dashboard/my-courses', icon: 'school', label: t('sidebar.myCourses') }
|
||||
])
|
||||
const { mobileItems } = useNavItems()
|
||||
const navItems = mobileItems
|
||||
|
||||
const handleNavigate = (path: string) => {
|
||||
if (import.meta.client) {
|
||||
|
|
@ -27,7 +22,7 @@ const handleNavigate = (path: string) => {
|
|||
:key="item.to"
|
||||
@click="handleNavigate(item.to)"
|
||||
:icon="item.icon"
|
||||
:label="item.label"
|
||||
:label="$t(item.labelKey)"
|
||||
no-caps
|
||||
class="py-2"
|
||||
:class="{ 'q-tab--active text-primary': $route.path === item.to }"
|
||||
|
|
|
|||
|
|
@ -29,12 +29,9 @@ const userInitials = computed(() => {
|
|||
return f + l
|
||||
})
|
||||
|
||||
const menuItems = computed(() => [
|
||||
{ label: t('userMenu.home'), to: '/dashboard' },
|
||||
{ label: t('userMenu.courseList'), to: '/browse/discovery' },
|
||||
{ label: t('userMenu.myCourses'), to: '/dashboard/my-courses' },
|
||||
{ label: t('userMenu.settings'), to: '/dashboard/profile' }
|
||||
])
|
||||
const { userMenuItems } = useNavItems()
|
||||
const menuItems = userMenuItems
|
||||
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout()
|
||||
|
|
@ -63,14 +60,14 @@ const handleLogout = async () => {
|
|||
<q-list class="py-2">
|
||||
<q-item
|
||||
v-for="item in menuItems"
|
||||
:key="item.label"
|
||||
:key="item.labelKey"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="navigateTo(item.to)"
|
||||
class="hover:bg-slate-100 dark:hover:bg-white/5 transition-colors"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label class="font-bold text-sm text-slate-800 dark:text-slate-100">{{ item.label }}</q-item-label>
|
||||
<q-item-label class="font-bold text-sm text-slate-800 dark:text-slate-100">{{ $t(item.labelKey) }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue