@@ -11,7 +11,7 @@ import {
1111 SlidersVertical ,
1212 UserCog ,
1313} from ' lucide-vue-next' ;
14- import { computed , onMounted , onUnmounted , ref } from ' vue' ;
14+ import { computed , onMounted , onUnmounted , ref , watch } from ' vue' ;
1515import { useI18n } from ' vue-i18n' ;
1616import { useFriends } from ' ../../composables/useFriends' ;
1717import { useUser } from ' ../../composables/useUser' ;
@@ -23,6 +23,10 @@ const { adminStatus } = useUser();
2323const halloweenActive = ref (isHalloweenEvent ());
2424const halloweenGreeting = ref (getEventGreeting ());
2525
26+ const sidebarHelpVideo = new URL (' ../../assets/videos/sidebar-help.mp4' , import .meta .url ).href ;
27+ const sidebarHelpKey = ' sidebar-help-shown' ;
28+ const showSidebarHelp = ref (false );
29+
2630const props = defineProps <{
2731 activeTab: string ;
2832 isOnline: boolean ;
@@ -138,6 +142,9 @@ const startDrag = (event: MouseEvent) => {
138142 if (target .closest (' button' )) return ;
139143
140144 isMouseDown .value = true ;
145+ if (showSidebarHelp .value ) {
146+ hideSidebarHelp ();
147+ }
141148 document .addEventListener (' mouseup' , stopDrag );
142149 document .addEventListener (' mousemove' , onDrag );
143150};
@@ -160,6 +167,9 @@ const toggleCenter = (event: MouseEvent) => {
160167 const target = event .target as HTMLElement ;
161168 if (target .closest (' button' )) return ;
162169 isCentered .value = ! isCentered .value ;
170+ if (showSidebarHelp .value ) {
171+ hideSidebarHelp ();
172+ }
163173};
164174
165175const currentPosition = computed (() => props .position || ' left' );
@@ -203,6 +213,38 @@ const animationClass = computed(() => {
203213 return ' sidebar-entered' ;
204214});
205215
216+ const helpTooltipClasses = computed (() => {
217+ const pos = currentPosition .value ;
218+ if (pos === ' left' ) return ' left-24 top-6' ;
219+ if (pos === ' right' ) return ' right-24 top-6' ;
220+ if (pos === ' top' ) return ' left-1/2 top-24 transform -translate-x-1/2' ;
221+ if (pos === ' bottom' ) return ' left-1/2 bottom-24 transform -translate-x-1/2' ;
222+ return ' left-24 top-6' ;
223+ });
224+
225+ const sidebarRef = ref <HTMLElement | null >(null );
226+ const helpTooltipRef = ref <HTMLElement | null >(null );
227+
228+ const hideSidebarHelp = () => {
229+ try {
230+ localStorage .setItem (sidebarHelpKey , ' true' );
231+ } catch {
232+ }
233+ showSidebarHelp .value = false ;
234+ };
235+
236+ const handleDocumentClick = (event : MouseEvent ) => {
237+ const target = event .target as Node ;
238+ if (helpTooltipRef .value ?.contains (target )) return ;
239+ if (sidebarRef .value ?.contains (target )) return ;
240+ hideSidebarHelp ();
241+ };
242+
243+ watch (showSidebarHelp , (val ) => {
244+ if (val ) document .addEventListener (' click' , handleDocumentClick );
245+ else document .removeEventListener (' click' , handleDocumentClick );
246+ });
247+
206248onMounted (async () => {
207249 window .addEventListener (' keydown' , handleKeyDown );
208250
@@ -215,6 +257,14 @@ onMounted(async () => {
215257
216258
217259 isDev .value = await getIsDevelopment ();
260+
261+ try {
262+ const shown = localStorage .getItem (sidebarHelpKey );
263+ if (! shown ) {
264+ showSidebarHelp .value = true ;
265+ }
266+ } catch {
267+ }
218268});
219269
220270onUnmounted (() => {
@@ -227,6 +277,7 @@ onUnmounted(() => {
227277 if (altPressTimeout .value ) {
228278 clearTimeout (altPressTimeout .value );
229279 }
280+ document .removeEventListener (' click' , handleDocumentClick );
230281});
231282 </script >
232283
@@ -246,7 +297,23 @@ onUnmounted(() => {
246297 </div >
247298 </div >
248299
249- <div :class =" [sidebarClasses, animationClass]" @mousedown =" startDrag" @dblclick =" toggleCenter" >
300+ <div ref =" sidebarRef" :class =" [sidebarClasses, animationClass]" @mousedown =" startDrag" @dblclick =" toggleCenter" >
301+ <div v-if =" showSidebarHelp" ref =" helpTooltipRef"
302+ :class =" ['sidebar-help-tooltip absolute z-60 p-3 w-80 origin-top-left bg-base-100 rounded-lg ml-3 mt-[100%]', helpTooltipClasses]" >
303+ <div class =" flex flex-col gap-2" >
304+ <video class =" w-full rounded-md mb-2" :src =" sidebarHelpVideo" muted autoplay loop playsinline
305+ controls ></video >
306+ <div class =" text-sm" >
307+ <strong >{{ t('navigation.sidebar_help.title') }}</strong >  ; {{ t('navigation.sidebar_help.tip')
308+ }}
309+ </div >
310+ <div class =" flex justify-end mt-1 gap-2" >
311+ <button class =" btn btn-ghost btn-xs" @click.stop =" hideSidebarHelp" >{{
312+ t('navigation.sidebar_help.got_it')
313+ }}</button >
314+ </div >
315+ </div >
316+ </div >
250317 <div class =" transition-all duration-500 ease-in-out basis-0" :class =" isCentered ? 'grow' : 'grow-0'" >
251318 </div >
252319
@@ -478,4 +545,8 @@ onUnmounted(() => {
478545.sidebar-entered .mt-auto > * :nth-child (3 ) {
479546 transition-delay : 0.30s ;
480547}
548+
549+ .sidebar-help-tooltip video {
550+ max-height : 180px ;
551+ }
481552 </style >
0 commit comments