bunch of qol-updates and css-fixes
authorPhiTux <redacted>
Sat, 5 Apr 2025 17:31:35 +0000 (19:31 +0200)
committerPhiTux <redacted>
Sat, 5 Apr 2025 17:31:35 +0000 (19:31 +0200)
backend/server/main.py
frontend/src/lib/ImageViewer.svelte
frontend/src/lib/helpers.js
frontend/src/routes/+layout.svelte
frontend/src/routes/write/+page.svelte

index ab10bfd477a92bf38404e37e6363ccf371ac1bd6..86afc1553f4cc388d4c17080d13fea9b4843ba2b 100644 (file)
@@ -16,7 +16,9 @@ origins = [
     "http://localhost:5173",
     "localhost:5173",
     "http://192.168.1.35:5173",
-    "192.168.1.35:5173"
+    "192.168.1.35:5173",
+    "http://100.100.87.111:5173",
+    "http://lab:5173"
 ]
 
 app.add_middleware(
index 2ea5106f8b0446d38846e44f0668b4c36dc2b946..063e47240da22b7ac9706d8270e155d80ac45eb4 100644 (file)
                }
        }
 
-       // Variablen für die Swipe-Erkennung
+       // Variables for touch events
        let touchStartX = 0;
        let touchEndX = 0;
 
        // Swipe-Handler
        function handleTouchStart(event) {
-               touchStartX = event.touches[0].clientX; // X-Position des Touch-Starts speichern
+               touchStartX = event.touches[0].clientX; // save the initial touch position
+               touchEndX = touchStartX;
        }
 
        function handleTouchMove(event) {
-               touchEndX = event.touches[0].clientX; // X-Position während der Bewegung speichern
+               console.log('move');
+               touchEndX = event.touches[0].clientX; // update the touch position
        }
 
-       function handleTouchEnd() {
-               // Prüfen, ob der Swipe nach links oder rechts ging
+       function handleTouchEnd(event) {
+               console.log(event.target.classList);
+               if (
+                       event.target.classList.contains('fullscreen-scroll') ||
+                       event.target.classList.contains('image')
+               ) {
+                       return; // do nothing if the touch ends on the scroll area
+               }
+
+               // calculate the swipe distance
                if (touchStartX - touchEndX > 50) {
-                       // Swipe nach links
+                       // Swipe left
                        nextImage();
                } else if (touchEndX - touchStartX > 50) {
-                       // Swipe nach rechts
+                       // Swipe right
                        prevImage();
                }
        }
        </div>
 {/if}
 
-<div class="image-gallery">
-       <!-- Horizontal Scrollbar -->
-       <div class="horizontal-scroll px-2">
-               {#each images as image, index (image.uuid_filename)}
-                       <button
-                               type="button"
-                               class="image-container"
-                               onclick={() => openFullscreen(index)}
-                               transition:slide={{ axis: 'x' }}
-                       >
-                               <img class="image" alt={image.filename} src={image.src} transition:fade />
-                       </button>
-               {/each}
-       </div>
+<!-- <div class="image-gallery"> -->
+<div class="horizontal-scroll px-2">
+       {#each images as image, index (image.uuid_filename)}
+               <button
+                       type="button"
+                       class="image-container"
+                       onclick={() => openFullscreen(index)}
+                       transition:slide={{ axis: 'x' }}
+               >
+                       <img class="image" alt={image.filename} src={image.src} transition:fade />
+               </button>
+       {/each}
 </div>
 
 <style>
                background: rgba(255, 255, 255, 0.4);
        }
 
-       .image-gallery {
-               display: flex;
-               flex-direction: column;
-               gap: 1rem;
-       }
-
        .horizontal-scroll {
                display: flex;
                gap: 1rem;
                align-items: center;
                z-index: 9999;
                color: white;
+               pointer-events: all;
        }
 
        .fullscreen-image-container {
index 731e3b0bdcc278ed6211c5d4c69c271fef8586e3..a091aae21507ddebe9c8f393a14177d11ebd321f 100644 (file)
@@ -1,3 +1,5 @@
+import {writable} from 'svelte/store';
+
 function formatBytes(bytes) {
        if (!+bytes) return '0 Bytes';
 
@@ -10,4 +12,7 @@ function formatBytes(bytes) {
        return `${parseFloat((bytes / Math.pow(k, i)).toFixed(0))} ${sizes[i]}`;
 }
 
+export let alwaysShowSidenav = writable(true);
+
 export { formatBytes };
+
index 158d716c4b4defdcf84c3fb54adb29bda31b881b..44afa21213742cd50d2e84b1e6a0385b74d9e543 100644 (file)
@@ -14,6 +14,7 @@
        import { useTrianglify, trianglifyOpacity, autoLoadImages } from '$lib/settingsStore.js';
        import { tags } from '$lib/tagStore.js';
        import TagModal from '$lib/TagModal.svelte';
+       import { alwaysShowSidenav } from '$lib/helpers.js';
 
        import {
                faRightFromBracket,
                });
        }
 
+       function calculateResize() {
+               if (window.innerWidth > 840) {
+                       $alwaysShowSidenav = true;
+               } else {
+                       $alwaysShowSidenav = false;
+               }
+       }
+
+       /* trigger on window-resize */
+       window.addEventListener('resize', () => {
+               calculateResize();
+       });
+
        onMount(() => {
                createBackground();
+               calculateResize();
 
                document.getElementById('settingsModal').addEventListener('shown.bs.modal', function () {
                        const height = document.getElementById('modal-body').clientHeight;
        <nav class="navbar navbar-expand-lg bg-body-tertiary">
                <div class="row w-100">
                        <div class="col-lg-4 col-sm-5 col d-flex flex-row justify-content-start align-items-center">
-                               <button
-                                       class="btn d-md-none"
-                                       type="button"
-                                       data-bs-toggle="offcanvas"
-                                       data-bs-target="#sidenav"
-                                       aria-controls="sidenav">menü</button
-                               >
+                               {#if !$alwaysShowSidenav}
+                                       <button
+                                               class="btn d-xl-none"
+                                               type="button"
+                                               data-bs-toggle="offcanvas"
+                                               data-bs-target="#sidenav"
+                                               aria-controls="sidenav">menü</button
+                                       >
+                               {/if}
 
                                <div class="form-check form-switch d-flex flex-row">
                                        <label class="me-3" for="selectMode"><Fa icon={faPencil} size="1.5x" /></label>
index 59f8e17d5b7cd3a52f283e263eb6483425c82973..e2bece4adcf1c462dbb4882d358beb3fc617a5ca 100644 (file)
@@ -25,7 +25,7 @@
        import Tag from '$lib/Tag.svelte';
        import TagModal from '$lib/TagModal.svelte';
        import FileList from '$lib/FileList.svelte';
-       import { formatBytes } from '$lib/helpers.js';
+       import { formatBytes, alwaysShowSidenav } from '$lib/helpers.js';
        import ImageViewer from '$lib/ImageViewer.svelte';
 
        axios.interceptors.request.use((config) => {
 <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-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"
        <Sidenav {searchForString} {searchForTag} />
 </div>
 
-<div class="d-flex flex-row justify-content-between h-100">
+<div class="d-flex flex-row justify-content-between h-100 main-row">
        <!-- shown on large Screen -->
-       <div class="d-md-block d-none sidenav p-3">
-               <Sidenav {searchForString} {searchForTag} />
-       </div>
-
-       <!-- Center -->
-       <div class="d-flex flex-column mt-4 mx-4 flex-fill" id="middle">
-               <!-- Input-Area -->
-               <!-- <div class="d-flex flex-column"> -->
-               <div class="d-flex flex-row textAreaHeader">
-                       <div class="flex-fill textAreaDate">
-                               {$selectedDate.toLocaleDateString('locale', { weekday: 'long' })}<br />
-                               {$selectedDate.toLocaleDateString('locale', {
-                                       day: '2-digit',
-                                       month: '2-digit',
-                                       year: 'numeric'
-                               })}
-                       </div>
-                       <div class="flex-fill textAreaWrittenAt">
-                               <div class={logDateWritten ? '' : 'opacity-50'}>Geschrieben am:</div>
-                               {logDateWritten}
-                       </div>
-                       <div class="textAreaHistory">history</div>
-                       <div class="textAreaDelete">delete</div>
-               </div>
-               <div id="log" class="focus-ring">
-                       <div id="toolbar"></div>
-                       <div id="editor"></div>
+       {#if $alwaysShowSidenav}
+               <!-- d-md-block d-none-->
+               <div class="  sidenav p-3">
+                       <Sidenav {searchForString} {searchForTag} />
                </div>
-               {#if images.length > 0}
-                       {#if !$autoLoadImages && 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 />
-                                               {#if images.length === 1}
-                                                       1 Bild laden
-                                               {:else}
-                                                       {images.length} Bilder laden
-                                               {/if}
-                                               ({formatBytes(
-                                                       images.filter((i) => !i.src).reduce((sum, image) => sum + (image.size || 0), 0)
-                                               )})
-                                       </button>
+       {/if}
+
+       <div class="d-flex flex-row middle-right">
+               <!-- Center -->
+               <div class="d-flex flex-column pt-4 px-4 flex-fill" id="middle">
+                       <!-- Input-Area -->
+                       <!-- <div class="d-flex flex-column"> -->
+                       <div class="d-flex flex-row textAreaHeader">
+                               <div class="flex-fill textAreaDate">
+                                       {$selectedDate.toLocaleDateString('locale', { weekday: 'long' })}<br />
+                                       {$selectedDate.toLocaleDateString('locale', {
+                                               day: '2-digit',
+                                               month: '2-digit',
+                                               year: 'numeric'
+                                       })}
+                               </div>
+                               <div class="flex-fill textAreaWrittenAt">
+                                       <div class={logDateWritten ? '' : 'opacity-50'}>Geschrieben am:</div>
+                                       {logDateWritten}
                                </div>
-                       {:else}
-                               <ImageViewer {images} />
-                               <!-- <div class="d-flex flex-row images mt-3">
+                               <div class="textAreaHistory">history</div>
+                               <div class="textAreaDelete">delete</div>
+                       </div>
+                       <div id="log" class="focus-ring">
+                               <div id="toolbar"></div>
+                               <div id="editor"></div>
+                       </div>
+                       {#if images.length > 0}
+                               {#if !$autoLoadImages && 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 />
+                                                       {#if images.length === 1}
+                                                               1 Bild laden
+                                                       {:else}
+                                                               {images.length} Bilder laden
+                                                       {/if}
+                                                       ({formatBytes(
+                                                               images.filter((i) => !i.src).reduce((sum, image) => sum + (image.size || 0), 0)
+                                                       )})
+                                               </button>
+                                       </div>
+                               {:else}
+                                       <ImageViewer {images} />
+                                       <!-- <div class="d-flex flex-row images mt-3">
                                        {#each images as image (image.uuid_filename)}
                                                <button
                                                        type="button"
                                                </button>
                                        {/each}
                                </div> -->
+                               {/if}
                        {/if}
-               {/if}
-               {$selectedDate}<br />
-               {lastSelectedDate}
-               <!-- </div> -->
-       </div>
+                       <!-- </div> -->
+               </div>
 
-       <div id="right" class="d-flex flex-column">
-               <div class="tags">
-                       <div class="d-flex flex-row justify-content-between">
-                               <div class="d-flex flex-row">
-                                       <h3>Tags</h3>
-                                       {#if showTagLoading}
-                                               <div class="spinner-border ms-3" role="status">
-                                                       <span class="visually-hidden">Loading...</span>
-                                               </div>
-                                       {/if}
+               <div id="right" class="d-flex flex-column">
+                       <div class="tags">
+                               <div class="d-flex flex-row justify-content-between">
+                                       <div class="d-flex flex-row">
+                                               <h3>Tags</h3>
+                                               {#if showTagLoading}
+                                                       <div class="spinner-border ms-3" role="status">
+                                                               <span class="visually-hidden">Loading...</span>
+                                                       </div>
+                                               {/if}
+                                       </div>
+                                       <!-- svelte-ignore a11y_missing_attribute -->
+                                       <a
+                                               tabindex="-1"
+                                               type="button"
+                                               class="btn"
+                                               data-bs-toggle="popover"
+                                               data-bs-title="Tags"
+                                               data-bs-content="Hier kannst du Tags zum ausgewählten Datum hinzufügen und entfernen, um deine Einträge zu kategorisieren. Ebenso kannst du hier neue Tags erstellen.<br/><br/>Um ein Tag zu ändern oder auch vollständig zu löschen, musst du in die Einstellungen wechseln."
+                                       >
+                                               <Fa icon={faQuestionCircle} fw /></a
+                                       >
                                </div>
-                               <!-- svelte-ignore a11y_missing_attribute -->
-                               <a
-                                       tabindex="-1"
-                                       type="button"
-                                       class="btn"
-                                       data-bs-toggle="popover"
-                                       data-bs-title="Tags"
-                                       data-bs-content="Hier kannst du Tags zum ausgewählten Datum hinzufügen und entfernen, um deine Einträge zu kategorisieren. Ebenso kannst du hier neue Tags erstellen.<br/><br/>Um ein Tag zu ändern oder auch vollständig zu löschen, musst du in die Einstellungen wechseln."
-                               >
-                                       <Fa icon={faQuestionCircle} fw /></a
-                               >
-                       </div>
-                       <div class="tagRow d-flex flex-row">
-                               <input
-                                       bind:value={searchTab}
-                                       onfocus={() => {
-                                               showTagDropdown = true;
-                                               selectedTagIndex = 0;
-                                       }}
-                                       onfocusout={() => {
-                                               setTimeout(() => (showTagDropdown = false), 150);
-                                       }}
-                                       onkeydown={handleKeyDown}
-                                       type="text"
-                                       class="form-control"
-                                       id="tag-input"
-                                       placeholder="Tag..."
-                               />
-                               <button class="newTagBtn btn btn-outline-secondary ms-2" onclick={openTagModal}>
-                                       <Fa icon={faSquarePlus} fw /> Neu
-                               </button>
-                       </div>
-                       {#if showTagDropdown}
-                               <div id="tagDropdown">
-                                       {#if filteredTags.length === 0}
-                                               <em style="padding: 0.2rem;">Kein Tag gefunden...</em>
-                                       {:else}
-                                               {#each filteredTags as tag, index (tag.id)}
-                                                       <!-- svelte-ignore a11y_click_events_have_key_events -->
-                                                       <!-- svelte-ignore a11y_no_static_element_interactions -->
-                                                       <!-- svelte-ignore a11y_mouse_events_have_key_events -->
-                                                       <div
-                                                               role="button"
-                                                               tabindex="0"
-                                                               onclick={() => selectTag(tag.id)}
-                                                               onmouseover={() => (selectedTagIndex = index)}
-                                                               class="tag-item {index === selectedTagIndex ? 'selected' : ''}"
-                                                       >
-                                                               <Tag {tag} />
+                               <div class="tagRow d-flex flex-row">
+                                       <input
+                                               bind:value={searchTab}
+                                               onfocus={() => {
+                                                       showTagDropdown = true;
+                                                       selectedTagIndex = 0;
+                                               }}
+                                               onfocusout={() => {
+                                                       setTimeout(() => (showTagDropdown = false), 150);
+                                               }}
+                                               onkeydown={handleKeyDown}
+                                               type="text"
+                                               class="form-control"
+                                               id="tag-input"
+                                               placeholder="Tag..."
+                                       />
+                                       <button class="newTagBtn btn btn-outline-secondary ms-2" onclick={openTagModal}>
+                                               <Fa icon={faSquarePlus} fw /> Neu
+                                       </button>
+                               </div>
+                               {#if showTagDropdown}
+                                       <div id="tagDropdown">
+                                               {#if filteredTags.length === 0}
+                                                       <em style="padding: 0.2rem;">Kein Tag gefunden...</em>
+                                               {:else}
+                                                       {#each filteredTags as tag, index (tag.id)}
+                                                               <!-- svelte-ignore a11y_click_events_have_key_events -->
+                                                               <!-- svelte-ignore a11y_no_static_element_interactions -->
+                                                               <!-- svelte-ignore a11y_mouse_events_have_key_events -->
+                                                               <div
+                                                                       role="button"
+                                                                       tabindex="0"
+                                                                       onclick={() => selectTag(tag.id)}
+                                                                       onmouseover={() => (selectedTagIndex = index)}
+                                                                       class="tag-item {index === selectedTagIndex ? 'selected' : ''}"
+                                                               >
+                                                                       <Tag {tag} />
+                                                               </div>
+                                                       {/each}
+                                               {/if}
+                                       </div>
+                               {/if}
+                               <div class="selectedTags d-flex flex-row flex-wrap">
+                                       {#if $tags.length !== 0}
+                                               {#each selectedTags as tag_id (tag_id)}
+                                                       <div transition:slide={{ axis: 'x' }}>
+                                                               <Tag tag={$tags.find((tag) => tag.id === tag_id)} {removeTag} isRemovable="true" />
                                                        </div>
                                                {/each}
                                        {/if}
                                </div>
-                       {/if}
-                       <div class="selectedTags d-flex flex-row flex-wrap">
-                               {#if $tags.length !== 0}
-                                       {#each selectedTags as tag_id (tag_id)}
-                                               <div transition:slide={{ axis: 'x' }}>
-                                                       <Tag tag={$tags.find((tag) => tag.id === tag_id)} {removeTag} isRemovable="true" />
-                                               </div>
-                                       {/each}
-                               {/if}
                        </div>
-               </div>
 
-               <div class="files d-flex flex-column">
-                       <button
-                               class="btn btn-secondary {filesOfDay?.length > 0 ? 'mb-2' : ''}"
-                               id="uploadBtn"
-                               onclick={triggerFileInput}
-                               ><Fa icon={faCloudArrowUp} class="me-2" id="uploadIcon" />Upload</button
-                       >
-                       <input type="file" id="fileInput" multiple style="display: none;" onchange={onFileChange} />
-
-                       <FileList files={filesOfDay} {downloadFile} {askDeleteFile} deleteAllowed />
-                       {#each uploadingFiles as file}
-                               <div>
-                                       {file.name}
-                                       <div
-                                               class="progress"
-                                               role="progressbar"
-                                               aria-label="Upload progress"
-                                               aria-valuemin="0"
-                                               aria-valuemax="100"
-                                       >
+                       <div class="files d-flex flex-column">
+                               <button
+                                       class="btn btn-secondary {filesOfDay?.length > 0 ? 'mb-2' : ''}"
+                                       id="uploadBtn"
+                                       onclick={triggerFileInput}
+                                       ><Fa icon={faCloudArrowUp} class="me-2" id="uploadIcon" />Upload</button
+                               >
+                               <input type="file" id="fileInput" multiple style="display: none;" onchange={onFileChange} />
+
+                               <FileList files={filesOfDay} {downloadFile} {askDeleteFile} deleteAllowed />
+                               {#each uploadingFiles as file}
+                                       <div>
+                                               {file.name}
                                                <div
-                                                       class="progress-bar {file.progress === 100
-                                                               ? 'progress-bar-striped progress-bar-animated'
-                                                               : ''}"
-                                                       style:width={file.progress + '%'}
+                                                       class="progress"
+                                                       role="progressbar"
+                                                       aria-label="Upload progress"
+                                                       aria-valuemin="0"
+                                                       aria-valuemax="100"
                                                >
-                                                       {#if file.progress !== 100}
-                                                               {file.progress}%
-                                                       {:else}
-                                                               Wird verschlüsselt...
-                                                       {/if}
+                                                       <div
+                                                               class="progress-bar {file.progress === 100
+                                                                       ? 'progress-bar-striped progress-bar-animated'
+                                                                       : ''}"
+                                                               style:width={file.progress + '%'}
+                                                       >
+                                                               {#if file.progress !== 100}
+                                                                       {file.progress}%
+                                                               {:else}
+                                                                       Wird verschlüsselt...
+                                                               {/if}
+                                                       </div>
                                                </div>
                                        </div>
-                               </div>
-                       {/each}
+                               {/each}
+                       </div>
                </div>
        </div>
 
 </div>
 
 <style>
+       @media (max-width: 1150px) {
+               .middle-right {
+                       flex-direction: column !important;
+                       align-items: center;
+               }
+
+               #middle {
+                       flex: none !important;
+               }
+
+               #right {
+                       padding-right: 0 !important;
+               }
+       }
+
+       .main-row {
+               max-width: 100vw;
+               flex-wrap: wrap;
+       }
+
+       .middle-right {
+               flex: 1 0;
+               /* flex-wrap: wrap; */
+               justify-content: center;
+               width: 100%;
+       }
+
+       #middle {
+               width: 100%;
+       }
+
        .tagRow {
                width: 100%;
        }
        .tags {
                z-index: 10;
                padding: 0.5rem;
-               margin-right: 2rem;
+               /* margin-right: 2rem; */
                margin-bottom: 2rem;
                backdrop-filter: blur(8px) saturate(150%);
                background-color: rgba(219, 219, 219, 0.45);
        }
 
        .files {
-               margin-right: 2rem;
+               /* margin-right: 2rem; */
+               margin-bottom: 1rem;
                border-radius: 10px;
                padding: 1rem;
                backdrop-filter: blur(8px) saturate(150%);
                border-top: 1px solid #ccc;
                border-left: 1px solid #ccc;
                border-right: 1px solid #ccc;
+               height: auto;
+               flex-wrap: wrap;
        }
 
        #editor {
                margin-top: 1.5rem !important;
                min-width: 300px;
                max-width: 400px;
+               padding-right: 2rem;
        }
 </style>
git clone https://git.99rst.org/PROJECT