bugfix: close sidenav when switching pages
authorPhiTux <redacted>
Sun, 27 Apr 2025 17:54:06 +0000 (19:54 +0200)
committerPhiTux <redacted>
Sun, 27 Apr 2025 17:54:06 +0000 (19:54 +0200)
frontend/src/lib/Datepicker.svelte
frontend/src/lib/Sidenav.svelte
frontend/src/lib/settingsStore.js
frontend/src/routes/+layout.svelte
frontend/src/routes/read/+page.svelte
frontend/src/routes/write/+page.svelte

index c6a10f6a675b977119147e5296feddb343423253..90d4a7d4c686bb886607c96f16a6e20df95e8f8d 100644 (file)
                }
        };
 
+       $effect(() => {
+               if (window.location.href) {
+                       setTimeout(() => {
+                               oc = document.querySelector('.offcanvas');
+                               oc.addEventListener('hidden.bs.offcanvas', () => {
+                                       $offcanvasIsOpen = false;
+                               });
+                               oc.addEventListener('shown.bs.offcanvas', () => {
+                                       $offcanvasIsOpen = true;
+                               });
+                       }, 500);
+               }
+       });
+
        onMount(() => {
                days = updateCalendar();
 
index 25e42d5808e35ee2801069eae74073fa33adfb1a..122438574a09a36545a09155eb2bb198755d8669 100644 (file)
@@ -9,8 +9,10 @@
        import * as bootstrap from 'bootstrap';
        import Tag from './Tag.svelte';
        import { offcanvasIsOpen } from '$lib/helpers.js';
+       import { API_URL } from '$lib/APIurl.js';
+       import axios from 'axios';
 
-       let { searchForString, searchForTag } = $props();
+       let oc;
 
        onMount(() => {
                const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
                }
        }
 
+       $effect(() => {
+               if (window.location.href) {
+                       setTimeout(() => {
+                               oc = document.querySelector('.offcanvas');
+                               oc.addEventListener('hidden.bs.offcanvas', () => {
+                                       $offcanvasIsOpen = false;
+                               });
+                               oc.addEventListener('shown.bs.offcanvas', () => {
+                                       $offcanvasIsOpen = true;
+                               });
+                       }, 1000);
+               }
+       });
+
+       function searchForString() {
+               if ($isSearching) {
+                       return;
+               }
+               $isSearching = true;
+
+               axios
+                       .get(API_URL + '/logs/searchString', {
+                               params: {
+                                       searchString: $searchString
+                               }
+                       })
+                       .then((response) => {
+                               $searchResults = [...response.data];
+                               $isSearching = false;
+                       })
+                       .catch((error) => {
+                               $searchResults = [];
+                               console.error(error);
+                               $isSearching = false;
+
+                               // toast
+                               const toast = new bootstrap.Toast(document.getElementById('toastErrorSearching'));
+                               toast.show();
+                       });
+       }
+
+       function searchForTag() {
+               $searchString = '';
+               if ($isSearching) {
+                       return;
+               }
+               $isSearching = true;
+
+               axios
+                       .get(API_URL + '/logs/searchTag', { params: { tag_id: $searchTag.id } })
+                       .then((response) => {
+                               $searchResults = [...response.data];
+                               $isSearching = false;
+                       })
+                       .catch((error) => {
+                               $isSearching = false;
+                               $searchResults = [];
+
+                               console.error(error);
+                               // toast
+                               const toast = new bootstrap.Toast(document.getElementById('toastErrorSearching'));
+                               toast.show();
+                       });
+       }
+
        let showTagDropdown = $state(false);
        let filteredTags = $state([]);
        let selectedTagIndex = $state(0);
                $searchResults = [];
        }
 
-       let oc;
+       // selects a search result
        function selectDate(date) {
                $selectedDate = date;
 
        </div>
 </div>
 
+<div class="toast-container position-fixed bottom-0 end-0 p-3">
+       <div
+               id="toastErrorSearching"
+               class="toast align-items-center text-bg-danger"
+               role="alert"
+               aria-live="assertive"
+               aria-atomic="true"
+       >
+               <div class="d-flex">
+                       <div class="toast-body">Fehler beim Suchen!</div>
+               </div>
+       </div>
+</div>
+
 <style>
        .btnSearchPopover {
                border-bottom-left-radius: 0px;
                color: #ccc;
                text-align: center;
                padding: 1rem;
+               user-select: none;
        }
 
        :global(.kbd) {
index e052facddb613efb5fd53497c1459227b8217e7d..77d0867c567fef908c8f9e90ef519ce51498796b 100644 (file)
@@ -1,6 +1,6 @@
 import {writable} from 'svelte/store';
 
-export const readingMode = writable(false);
+export const readingMode = writable('');
 
 // old, to be deleted
 export const useTrianglify = writable(true);
index 807a541f7088417e3a99ddbc8d91e12fe75778bb..b3368ed9ed44fb1e3bd0de9b3122bad364e4c582 100644 (file)
@@ -20,9 +20,8 @@
        import trianglify from 'trianglify';
        import { tags } from '$lib/tagStore.js';
        import TagModal from '$lib/TagModal.svelte';
-       import { alwaysShowSidenav } from '$lib/helpers.js';
+       import { alwaysShowSidenav, offcanvasIsOpen } from '$lib/helpers.js';
        import { templates } from '$lib/templateStore';
-
        import {
                faRightFromBracket,
                faGlasses,
        let inDuration = 150;
        let outDuration = 150;
 
+       axios.interceptors.request.use((config) => {
+               config.withCredentials = true;
+               return config;
+       });
+
+       axios.interceptors.response.use(
+               (response) => {
+                       return response;
+               },
+               (error) => {
+                       if (
+                               error.response &&
+                               error.response.status &&
+                               (error.response.status == 401 || error.response.status == 440)
+                       ) {
+                               // logout
+                               axios
+                                       .get(API_URL + '/users/logout')
+                                       .then((response) => {
+                                               localStorage.removeItem('user');
+                                               goto(`/login?error=${error.response.status}`);
+                                       })
+                                       .catch((error) => {
+                                               console.error(error);
+                                       });
+                       }
+                       return Promise.reject(error);
+               }
+       );
+
        $effect(() => {
-               if ($readingMode) {
+               if ($readingMode === true && page.url.pathname !== '/read') {
                        goto('/read');
-               } else {
+               } else if ($readingMode === false) {
                        goto('/write');
                }
        });
                getUserSettings();
                getTemplates();
 
+               if (page.url.pathname === '/read') {
+                       $readingMode = true;
+               } else if (page.url.pathname === '/write') {
+                       $readingMode = false;
+               }
+
                document.getElementById('settingsModal').addEventListener('shown.bs.modal', function () {
                        const height = document.getElementById('modal-body').clientHeight;
                        document.getElementById('settings-content').style.height = 'calc(' + height + 'px - 2rem)';
                                                                id="settings-content"
                                                        >
                                                                <div id="appearance">
-                                                                       <h3 id="" class="text-primary">Aussehen</h3>
+                                                                       <h3 class="text-primary">Aussehen</h3>
                                                                        <div id="lightdark">
                                                                                <h5>Light/Dark-Mode</h5>
                                                                                Bla<br />
                                                                </div>
 
                                                                <div id="functions">
-                                                                       <h3 id="" class="text-primary">Funktionen</h3>
+                                                                       <h3 class="text-primary">Funktionen</h3>
 
                                                                        <div id="autoLoadImages">
                                                                                {#if $tempSettings.setAutoloadImagesPerDevice !== $settings.setAutoloadImagesPerDevice || $tempSettings.autoloadImagesByDefault !== $settings.autoloadImagesByDefault}
index a37e7c8cce54e7ea7384b17cc728f1fd2350444c..1cff3048df224ff645df5b394b10d29b2e1b7c2f 100644 (file)
@@ -9,11 +9,17 @@
        import Tag from '$lib/Tag.svelte';
        import { tags } from '$lib/tagStore.js';
        import FileList from '$lib/FileList.svelte';
-       import { autoLoadImages } from '$lib/settingsStore';
+       import { autoLoadImagesThisDevice, settings } from '$lib/settingsStore';
        import { faCloudArrowDown } from '@fortawesome/free-solid-svg-icons';
        import { Fa } from 'svelte-fa';
        import { fade, slide } from 'svelte/transition';
        import ImageViewer from '$lib/ImageViewer.svelte';
+       import { alwaysShowSidenav } from '$lib/helpers.js';
+
+       axios.interceptors.request.use((config) => {
+               config.withCredentials = true;
+               return config;
+       });
 
        marked.use({
                breaks: true,
@@ -93,7 +99,7 @@
                                                ) {
                                                        log.images = [...log.images, file];
 
-                                                       if ($autoLoadImages) {
+                                                       if (autoLoadImages) {
                                                                loadImage(file.uuid_filename);
                                                        }
                                                }
                }
        });
 
+       let autoLoadImages = $derived(
+               ($settings.setAutoloadImagesPerDevice && $autoLoadImagesThisDevice) ||
+                       (!$settings.setAutoloadImagesPerDevice && $settings.autoloadImagesByDefault)
+       );
+
        function loadImage(uuid) {
                for (let i = 0; i < logs.length; i++) {
                        let log = logs[i];
 <DatepickerLogic />
 
 <!-- shown on small Screen, when triggered -->
-<div class="offcanvas-md d-md-none offcanvas-start p-3" id="sidenav" tabindex="-1">
+<div class="offcanvas offcanvas-start p-3" id="sidenav" tabindex="-1">
        <div class="offcanvas-header">
                <button
                        type="button"
                        aria-label="Close"
                ></button>
        </div>
-       <Sidenav {search} />
+       <Sidenav />
 </div>
 
 <div class="d-flex flex-row justify-content-between h-100">
        <!-- shown on large Screen -->
-       <div class="d-md-block d-none sidenav p-3">
-               <Sidenav {search} />
-       </div>
+       {#if $alwaysShowSidenav}
+               <div class="sidenav p-3">
+                       <Sidenav />
+               </div>
+       {/if}
 
        <!-- Center -->
        <div class="d-flex flex-column my-4 ms-4 flex-fill overflow-y-auto" id="scrollArea">
                {#each logs as log (log.day)}
                        <!-- Log-Area -->
-                       <div class="log mb-3 p-3 d-flex flex-row" data-log-day={log.day}>
-                               <div class="date me-3 d-flex flex-column align-items-center">
-                                       <p class="dateNumber">{log.day}</p>
-                                       <p class="dateDay">
-                                               <b>
-                                                       {new Date($cal.currentYear, $cal.currentMonth, log.day).toLocaleDateString('locale', {
-                                                               weekday: 'long'
-                                                       })}
-                                               </b>
-                                       </p>
-                               </div>
-                               <div class="flex-grow-1 middle">
-                                       {#if log.text && log.text !== ''}
-                                               <div class="text">
-                                                       {@html marked.parse(log.text)}
-                                               </div>
-                                       {/if}
-                                       {#if log.tags?.length > 0}
-                                               <div class="tags d-flex flex-row flex-wrap">
-                                                       {#each log.tags as t}
-                                                               <Tag tag={$tags.find((tag) => tag.id === t)} />
-                                                       {/each}
-                                               </div>
-                                       {/if}
-                                       {#if log.images?.length > 0}
-                                               {#if !$autoLoadImages && log.images.find((image) => !image.src && !image.loading)}
-                                                       <div class="d-flex flex-row">
-                                                               <button type="button" class="loadImageBtn" onclick={() => loadImages()}>
-                                                                       <Fa icon={faCloudArrowDown} class="me-2" size="2x" fw /><br />
-                                                                       Bilder laden
-                                                               </button>
+                       {#if ('text' in log && log.text !== '') || log.tags?.length > 0 || log.files?.length > 0}
+                               <div class="log mb-3 p-3 d-flex flex-row" data-log-day={log.day}>
+                                       <div class="date me-3 d-flex flex-column align-items-center">
+                                               <p class="dateNumber">{log.day}</p>
+                                               <p class="dateDay">
+                                                       <b>
+                                                               {new Date($cal.currentYear, $cal.currentMonth, log.day).toLocaleDateString(
+                                                                       'locale',
+                                                                       {
+                                                                               weekday: 'long'
+                                                                       }
+                                                               )}
+                                                       </b>
+                                               </p>
+                                       </div>
+                                       <div class="flex-grow-1 middle">
+                                               {#if log.text && log.text !== ''}
+                                                       <div class="text">
+                                                               {@html marked.parse(log.text)}
                                                        </div>
-                                               {:else}
-                                                       <ImageViewer images={log.images} />
                                                {/if}
+                                               {#if log.tags?.length > 0}
+                                                       <div class="tags d-flex flex-row flex-wrap">
+                                                               {#each log.tags as t}
+                                                                       <Tag tag={$tags.find((tag) => tag.id === t)} />
+                                                               {/each}
+                                                       </div>
+                                               {/if}
+                                               {#if log.images?.length > 0}
+                                                       {#if !autoLoadImages && log.images.find((image) => !image.src && !image.loading)}
+                                                               <div class="d-flex flex-row">
+                                                                       <button type="button" class="loadImageBtn" onclick={() => loadImages()}>
+                                                                               <Fa icon={faCloudArrowDown} class="me-2" size="2x" fw /><br />
+                                                                               Bilder laden
+                                                                       </button>
+                                                               </div>
+                                                       {:else}
+                                                               <ImageViewer images={log.images} />
+                                                       {/if}
+                                               {/if}
+                                       </div>
+
+                                       {#if log.files && log.files.length > 0}
+                                               <div class="d-flex flex-column ms-3 files">
+                                                       <FileList files={log.files} {downloadFile} />
+                                               </div>
                                        {/if}
                                </div>
-
-                               {#if log.files && log.files.length > 0}
-                                       <div class="d-flex flex-column ms-3 files">
-                                               <FileList files={log.files} {downloadFile} />
-                                       </div>
-                               {/if}
-                       </div>
+                       {/if}
                {/each}
        </div>
 </div>
 
 <style>
+       .sidenav {
+               width: 380px;
+               min-width: 380px;
+       }
+
        .files {
                max-width: 350px;
        }
index 75a799040649ba7286955e68e7d3d3534593b43e..dcb57d6f00b94a3c79207561a32efa8e42339222 100644 (file)
@@ -6,7 +6,7 @@
        import axios from 'axios';
        import { goto } from '$app/navigation';
        import { onMount } from 'svelte';
-       import { searchString, searchTag, searchResults, isSearching } from '$lib/searchStore.js';
+       import { searchString, searchResults } from '$lib/searchStore.js';
        import * as TinyMDE from 'tiny-markdown-editor';
        import '../../../node_modules/tiny-markdown-editor/dist/tiny-mde.css';
        import { API_URL } from '$lib/APIurl.js';
                return config;
        });
 
-       axios.interceptors.response.use(
-               (response) => {
-                       return response;
-               },
-               (error) => {
-                       if (
-                               error.response &&
-                               error.response.status &&
-                               (error.response.status == 401 || error.response.status == 440)
-                       ) {
-                               // logout
-                               axios
-                                       .get(API_URL + '/users/logout')
-                                       .then((response) => {
-                                               localStorage.removeItem('user');
-                                               goto(`/login?error=${error.response.status}`);
-                                       })
-                                       .catch((error) => {
-                                               console.error(error);
-                                       });
-                       }
-                       return Promise.reject(error);
-               }
-       );
-
        let cancelDownload = new AbortController();
 
        let tinyMDE;
                }
        });
 
-       function searchForString() {
-               if ($isSearching) {
-                       return;
-               }
-               $isSearching = true;
-
-               axios
-                       .get(API_URL + '/logs/searchString', {
-                               params: {
-                                       searchString: $searchString
-                               }
-                       })
-                       .then((response) => {
-                               $searchResults = [...response.data];
-                               $isSearching = false;
-                       })
-                       .catch((error) => {
-                               $searchResults = [];
-                               console.error(error);
-                               $isSearching = false;
-
-                               // toast
-                               const toast = new bootstrap.Toast(document.getElementById('toastErrorSearching'));
-                               toast.show();
-                       });
-       }
-
-       function searchForTag() {
-               $searchString = '';
-               if ($isSearching) {
-                       return;
-               }
-               $isSearching = true;
-
-               axios
-                       .get(API_URL + '/logs/searchTag', { params: { tag_id: $searchTag.id } })
-                       .then((response) => {
-                               $searchResults = [...response.data];
-                               $isSearching = false;
-                       })
-                       .catch((error) => {
-                               $isSearching = false;
-                               $searchResults = [];
-
-                               console.error(error);
-                               // toast
-                               const toast = new bootstrap.Toast(document.getElementById('toastErrorSearching'));
-                               toast.show();
-                       });
-       }
-
        function triggerFileInput() {
                document.getElementById('fileInput').click();
        }
 <DatepickerLogic />
 <svelte:window onkeydown={on_key_down} onkeyup={on_key_up} />
 
-<!-- offcanvas-md d-md-none -->
 <!-- shown on small Screen, when triggered -->
 <div class="offcanvas offcanvas-start p-3" id="sidenav" tabindex="-1">
        <div class="offcanvas-header">
                        aria-label="Close"
                ></button>
        </div>
-       <Sidenav {searchForString} {searchForTag} />
+       <Sidenav />
 </div>
 
 <div class="d-flex flex-row justify-content-between h-100 main-row">
        <!-- shown on large Screen -->
        {#if $alwaysShowSidenav}
-               <!-- d-md-block d-none-->
                <div class="sidenav p-3">
-                       <Sidenav {searchForString} {searchForTag} />
+                       <Sidenav />
                </div>
        {/if}
 
                        </div>
                </div>
 
-               <div
-                       id="toastErrorSearching"
-                       class="toast align-items-center text-bg-danger"
-                       role="alert"
-                       aria-live="assertive"
-                       aria-atomic="true"
-               >
-                       <div class="d-flex">
-                               <div class="toast-body">Fehler beim Suchen!</div>
-                       </div>
-               </div>
-
                <div
                        id="toastErrorSavingFile"
                        class="toast align-items-center text-bg-danger"
 
        #editor {
                height: 400px;
-               overflow-y: scroll;
                word-break: break-word;
        }
 
        }
 
        .sidenav {
-               /* max-width: 430px; */
                width: 380px;
                min-width: 380px;
        }
git clone https://git.99rst.org/PROJECT