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;