From adb256415383fa3b5522e344f220e00cbd9a4db7 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Fri, 20 Feb 2026 15:46:23 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20optimiser=20l'interface=20des=20notes?= =?UTF-8?q?=20avec=20=C3=A9moji=20=F0=9F=93=9D=20automatique=20dans=20les?= =?UTF-8?q?=20titres,=20redirection=20intelligente=20vers=20vue=20Notes=20?= =?UTF-8?q?au=20clic=20sur=20titre,=20retour=20URL=20dynamique=20post-sauv?= =?UTF-8?q?egarde,=20auto-ouverture=20note=20via=20hash=20#open-note-{id},?= =?UTF-8?q?=20r=C3=A9duction=20tailles=20boutons=20actions=20(36px?= =?UTF-8?q?=E2=86=9228px=20hover,=2032px=E2=86=9230px),=20suppression=20ga?= =?UTF-8?q?ps=20entre=20boutons=20(0.25rem=E2=86=920),=20link-footer=20now?= =?UTF-8?q?rap=20avec=20overflow=20hidden,=20et=20changement=20placeholder?= =?UTF-8?q?=20"Page=20title"=E2=86=92"Note=20title"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shaarli-pro/css/style.css | 32 +++++++------ shaarli-pro/editlink.html | 2 +- shaarli-pro/js/custom_views.js | 15 ++++++ shaarli-pro/js/script.js | 84 ++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 15 deletions(-) diff --git a/shaarli-pro/css/style.css b/shaarli-pro/css/style.css index 03afb13..0201d89 100644 --- a/shaarli-pro/css/style.css +++ b/shaarli-pro/css/style.css @@ -1318,7 +1318,7 @@ body.view-notes .paging { position: absolute; top: 0.75rem; left: auto; - right: 10.5rem; + right: 9.5rem; transform: none; width: 32px; height: 32px; @@ -1399,9 +1399,9 @@ body.view-notes .paging { .link-hover-actions { position: absolute; top: 0.75rem; - right: 3.5rem; + right: 2.9rem; display: flex; - gap: 0.25rem; + gap: 0; opacity: 0; transition: opacity 0.15s ease; z-index: 20; @@ -1415,8 +1415,8 @@ body.view-notes .paging { display: flex; align-items: center; justify-content: center; - width: 32px; - height: 32px; + width: 30px; + height: 30px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 0.375rem; @@ -1514,7 +1514,7 @@ body.view-notes .paging { .link-readlater-badge { position: absolute; top: 0.75rem; - right: 3.2rem; + right: 2.9rem; display: inline-flex; align-items: center; justify-content: center; @@ -1582,13 +1582,14 @@ body.view-notes .paging { .link-footer { display: flex; - flex-wrap: wrap; + flex-wrap: nowrap; gap: 0.5rem; align-items: center; justify-content: space-between; margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--border); + overflow: hidden; } .view-grid .link-footer { @@ -1600,10 +1601,11 @@ body.view-notes .paging { /* Tags */ .link-tag-list { display: flex; - flex-wrap: wrap; + flex-wrap: nowrap; gap: 0.375rem; flex: 1 1 auto; min-width: 0; + overflow: hidden; } .link-tag { @@ -1669,6 +1671,7 @@ body.view-notes .paging { order: 2; width: 100%; justify-content: flex-end; + flex-wrap: wrap; } .view-grid .link-actions { @@ -1678,10 +1681,10 @@ body.view-notes .paging { /* Actions */ .link-actions { display: flex; - gap: 0.25rem; + gap: 0; flex-shrink: 0; align-items: center; - flex-wrap: wrap; + flex-wrap: nowrap; justify-content: flex-end; max-width: 100%; margin-left: auto; @@ -1693,8 +1696,8 @@ body.view-notes .paging { display: flex; align-items: center; justify-content: center; - width: 36px; - height: 36px; + width: 28px; + height: 28px; background: transparent; border: none; border-radius: 0.375rem; @@ -1702,11 +1705,12 @@ body.view-notes .paging { cursor: pointer; transition: all 0.15s ease; text-decoration: none; + flex-shrink: 0; } .link-actions a i, .link-actions button i { - font-size: 1.15rem; + font-size: 1rem; } .link-actions a:hover, @@ -1744,7 +1748,7 @@ body.view-notes .paging { .view-list .link-readlater-badge { top: 1.25rem; - right: 3.95rem; + right: 3.4rem; } /* List view - selection */ diff --git a/shaarli-pro/editlink.html b/shaarli-pro/editlink.html index 58d1b01..b75f791 100644 --- a/shaarli-pro/editlink.html +++ b/shaarli-pro/editlink.html @@ -53,7 +53,7 @@
- +
diff --git a/shaarli-pro/js/custom_views.js b/shaarli-pro/js/custom_views.js index 4326ba6..7f2319e 100644 --- a/shaarli-pro/js/custom_views.js +++ b/shaarli-pro/js/custom_views.js @@ -1846,6 +1846,21 @@ function initNoteView(linkList, container) { container.appendChild(wrapper); } + // Check for hash parameter to auto-open a specific note + const hash = window.location.hash; + if (hash && hash.startsWith('#open-note-')) { + const noteId = hash.replace('#open-note-', ''); + const targetNote = notes.find(n => String(n.id) === String(noteId)); + if (targetNote) { + // Clear the hash to avoid reopening on refresh + history.replaceState(null, null, window.location.pathname + window.location.search); + // Open the note modal after a short delay to ensure DOM is ready + setTimeout(() => { + openNoteModal(targetNote); + }, 100); + } + } + // Modal Container const modalOverlay = document.createElement("div"); modalOverlay.className = "note-modal-overlay"; diff --git a/shaarli-pro/js/script.js b/shaarli-pro/js/script.js index fec5ff1..bfa7074 100644 --- a/shaarli-pro/js/script.js +++ b/shaarli-pro/js/script.js @@ -1602,6 +1602,7 @@ document.addEventListener('DOMContentLoaded', () => { const tagsTextInput = form.querySelector('.bookmark-tags-text-input'); const readLaterCheckbox = form.querySelector('.bookmark-toggle-readlater'); const noteCheckbox = form.querySelector('.bookmark-toggle-note'); + const titleInput = form.querySelector('input[name="lf_title"]'); const isDarkTheme = document.documentElement.getAttribute('data-theme') === 'dark'; // Markdown editor @@ -1676,6 +1677,17 @@ document.addEventListener('DOMContentLoaded', () => { .map((tag) => normalizeTag(tag)) .filter(Boolean); + // Update return URL based on bookmark type (note vs regular) + const returnUrlInput = form.querySelector('input[name="returnurl"]'); + if (returnUrlInput) { + form.addEventListener('submit', () => { + const isNote = noteCheckbox?.checked || tags.some((tag) => /^note$/i.test(tag)); + if (isNote) { + returnUrlInput.value = `${shaarli.basePath}/?searchtags=note`; + } + }); + } + const updateHiddenTags = () => { hiddenTagsInput.value = tags.join(' '); }; @@ -1690,6 +1702,44 @@ document.addEventListener('DOMContentLoaded', () => { noteCheckbox.checked = tags.some((tag) => /^note$/i.test(tag)); }; + // Helper functions to manage note emoji in title + const NOTE_EMOJI = '📝'; + + const hasNoteEmoji = (title) => { + return title && title.startsWith(NOTE_EMOJI); + }; + + const addNoteEmoji = (title) => { + if (!title) return NOTE_EMOJI + ' '; + if (hasNoteEmoji(title)) return title; + return NOTE_EMOJI + ' ' + title; + }; + + const removeNoteEmoji = (title) => { + if (!title) return ''; + if (title.startsWith(NOTE_EMOJI + ' ')) { + return title.substring(NOTE_EMOJI.length + 1); + } + if (title.startsWith(NOTE_EMOJI)) { + return title.substring(NOTE_EMOJI.length); + } + return title; + }; + + const updateNoteTitle = (isNote) => { + if (!titleInput) return; + const currentTitle = titleInput.value || ''; + if (isNote) { + if (!hasNoteEmoji(currentTitle)) { + titleInput.value = addNoteEmoji(currentTitle); + } + } else { + if (hasNoteEmoji(currentTitle)) { + titleInput.value = removeNoteEmoji(currentTitle); + } + } + }; + const addTag = (rawTag) => { const tag = normalizeTag(rawTag); if (!tag) return; @@ -1804,6 +1854,9 @@ document.addEventListener('DOMContentLoaded', () => { if (noteCheckbox.checked) { tags.push('note'); + updateNoteTitle(true); + } else { + updateNoteTitle(false); } updateHiddenTags(); @@ -1838,6 +1891,16 @@ document.addEventListener('DOMContentLoaded', () => { syncNoteCheckbox(); renderTags(); refreshAutocomplete(); + + // Initial title update if note tag is present + if (noteCheckbox && noteCheckbox.checked && titleInput) { + const currentTitle = titleInput.value || ''; + if (!hasNoteEmoji(currentTitle) && !currentTitle.trim()) { + titleInput.value = NOTE_EMOJI + ' '; + } else if (!hasNoteEmoji(currentTitle)) { + titleInput.value = addNoteEmoji(currentTitle); + } + } }); } @@ -2740,6 +2803,27 @@ document.addEventListener('DOMContentLoaded', () => { var url = urlEl.textContent.trim(); var realUrl = (titleEl && titleEl.getAttribute('href')) || url; + // Check if this is a note bookmark (has 'note' tag) + var isNote = false; + var noteId = card.dataset.id || ''; + card.querySelectorAll('.link-tag[data-tag]').forEach(function(tagEl) { + if (tagEl.dataset.tag === 'note') { + isNote = true; + } + }); + + // Add click handler for note bookmarks to redirect to notes page + if (isNote && titleEl) { + titleEl.addEventListener('click', function(e) { + // Only redirect if it's a left-click without modifiers + if (e.button === 0 && !e.ctrlKey && !e.metaKey && !e.shiftKey) { + e.preventDefault(); + var basePath = (typeof shaarli !== 'undefined' && shaarli.basePath) ? shaarli.basePath : ''; + window.location.href = basePath + '/?searchtags=note#open-note-' + noteId; + } + }); + } + if (isMediaUrl(url) || isMediaUrl(realUrl)) { var actionsDiv = card.querySelector('.link-actions'); if (!actionsDiv) return;