77 <OrganizationStatus />
88
99 <div class =" flex items-start flex-1 gap-y-10" >
10- <div class =" p-4 mt-1 overflow-y-auto bg-white border-r border-gray-200 lg:w-72 shrink-0" >
10+ <!-- Desktop sidebar -->
11+ <div class =" hidden md:block p-4 mt-1 overflow-y-auto bg-white border-r border-gray-200 lg:w-72 shrink-0" >
1112 <nav >
1213 <ul class =" space-y-1" >
1314 <li v-for =" item in navigation" :key =" item.name" >
5758 </nav >
5859 </div >
5960
60- <div class =" grid items-start flex-1 p-9" :class =" gridClass" >
61+ <!-- Main content -->
62+ <div class =" grid items-start flex-1 p-9 pb-24 md:pb-9" :class =" gridClass" >
6163 <slot />
6264 </div >
6365 </div >
6466
67+ <!-- Mobile bottom nav -->
68+ <div class =" md:hidden fixed inset-x-0 bottom-0 z-50" >
69+ <!-- Dropdown / sheet pentru submenu -->
70+ <transition
71+ enter-active-class =" transition duration-150 ease-out"
72+ enter-from-class =" opacity-0 translate-y-2"
73+ enter-to-class =" opacity-100 translate-y-0"
74+ leave-active-class =" transition duration-150 ease-in"
75+ leave-from-class =" opacity-100 translate-y-0"
76+ leave-to-class =" opacity-0 translate-y-2"
77+ >
78+ <div v-if =" openSubMenuItem" class =" px-3 pb-2" >
79+ <div class =" bg-white border border-gray-200 rounded-2xl shadow-lg overflow-hidden" >
80+ <div class =" flex items-center justify-between px-4 py-3 border-b border-gray-100" >
81+ <div class =" text-sm font-semibold text-gray-800" >
82+ {{ openSubMenuItem.name }}
83+ </div >
84+ <button type =" button" class =" text-sm font-medium text-gray-500" @click =" closeSubMenu" >
85+ Închide
86+ </button >
87+ </div >
88+
89+ <div class =" p-2" >
90+ <Link
91+ v-for =" sub in openSubMenuItem.subMenu"
92+ :key =" sub.name"
93+ :href =" sub.route"
94+ class =" flex items-center gap-3 px-3 py-2 rounded-xl text-sm font-medium"
95+ :class =" isActive(sub) ? 'bg-primary-50 text-primary-600' : 'text-gray-700'"
96+ @click =" closeSubMenu"
97+ >
98+ <component
99+ :is =" sub.icon"
100+ class =" h-5 w-5"
101+ :class =" isActive(sub) ? 'text-primary-600' : 'text-gray-500'"
102+ aria-hidden =" true"
103+ />
104+ {{ $t(sub.name) }}
105+ </Link >
106+ </div >
107+ </div >
108+ </div >
109+ </transition >
110+
111+ <!-- Bara de jos -->
112+ <div class =" bg-white border-t border-gray-200 pb-[env(safe-area-inset-bottom)]" >
113+ <nav class =" grid grid-cols-5" >
114+ <button
115+ v-for =" item in mobileNavigation"
116+ :key =" item.name"
117+ type =" button"
118+ class =" flex flex-col items-center justify-center gap-1 py-2"
119+ :class =" isActive(item) ? 'text-primary-600' : 'text-gray-600'"
120+ @click =" onMobileNavClick(item)"
121+ >
122+ <component
123+ :is =" item.icon"
124+ class =" h-6 w-6"
125+ :class =" isActive(item) ? 'text-primary-600' : 'text-gray-500'"
126+ aria-hidden =" true"
127+ />
128+ <span class =" text-[11px] leading-none font-medium truncate max-w-[72px]" >
129+ {{ item.name }}
130+ </span >
131+ </button >
132+ </nav >
133+ </div >
134+ </div >
135+
65136 <Footer class =" mt-16" />
66137 </div >
67138</template >
68-
69139<script setup>
70140import Navbar from ' @/Components/Navbar.vue' ;
71141import Footer from ' @/Components/Footer.vue' ;
@@ -88,13 +158,15 @@ import {
88158} from ' @heroicons/vue/outline' ;
89159import OrganizationStatus from ' @/Components/OrganizationStatus.vue' ;
90160import { trans } from ' laravel-vue-i18n' ;
161+ import { computed , ref } from ' vue' ;
91162
92163const props = defineProps ({
93164 gridClass: {
94165 type: String ,
95166 default: ' gap-8' ,
96167 },
97168});
169+ const openSubMenuName = ref (null );
98170
99171const navigation = [
100172 {
@@ -165,6 +237,30 @@ const navigation = [
165237 },
166238];
167239
240+ const openSubMenuItem = computed (() => {
241+ if (! openSubMenuName .value ) return null ;
242+ return navigation .find ((x ) => x .name === openSubMenuName .value && x .subMenu ? .length );
243+ });
244+
245+ const closeSubMenu = () => {
246+ openSubMenuName .value = null ;
247+ };
248+
249+ const mobileNavigation = computed (() => {
250+ const wanted = [' Panou de control' , ' Toate proiectele' , ' Voluntari' , ' Donații ONG' , ' Tickets' ];
251+ return navigation .filter ((x ) => wanted .includes (x .name ));
252+ });
253+
254+ const onMobileNavClick = (item ) => {
255+ if (item .subMenu ? .length ) {
256+ openSubMenuName .value = openSubMenuName .value === item .name ? null : item .name ;
257+ return ;
258+ }
259+
260+ closeSubMenu ();
261+ window .location .href = item .route ;
262+ };
263+
168264const isActive = (item ) => {
169265 if (typeof window === ' undefined' ) {
170266 return false ;
0 commit comments