feat: star favoris dynamique + sidebar refresh sans reload
- page_editor: étoile ⭐/☆ dynamique selon favorited (x-text)
- toggleFavorite() appelle refreshFavorites() du sidebar
- base.html: refreshFavorites() fetch /api/library/favorites + rebuild DOM
- Context menu 'Add to Favorites' → refreshFavorites() au lieu de location.reload()
- Les items dynamiques ont onclick/oncontextmenu pour fonctionner hors Alpine
This commit is contained in:
+35
-2
@@ -601,6 +601,40 @@
|
|||||||
|
|
||||||
// ── Favorites tracking ──
|
// ── Favorites tracking ──
|
||||||
favoriteIds: new Set([{% for p in favorite_pages %}'{{ p.id }}'{% if not loop.last %},{% endif %}{% endfor %}]),
|
favoriteIds: new Set([{% for p in favorite_pages %}'{{ p.id }}'{% if not loop.last %},{% endif %}{% endfor %}]),
|
||||||
|
|
||||||
|
refreshFavorites() {
|
||||||
|
const self = this;
|
||||||
|
fetch('/api/library/favorites', {credentials:'same-origin'})
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
const items = data.items || [];
|
||||||
|
self.favoriteIds = new Set(items.map(i => i.id));
|
||||||
|
const favList = document.querySelector('.sidebar-items[data-section="favorites"]');
|
||||||
|
if (!favList) return;
|
||||||
|
if (items.length === 0) {
|
||||||
|
favList.innerHTML = '<li class="sidebar-item empty-hint"><span class="page-icon">⭐</span><span class="page-name text-dim">No favorites yet</span></li>';
|
||||||
|
} else {
|
||||||
|
favList.innerHTML = items.map(function(item) {
|
||||||
|
const icon = item.icon || '📄';
|
||||||
|
const name = (item.title || 'Untitled');
|
||||||
|
const safeName = name.replace(/'/g, "\\'").replace(/"/g, '"');
|
||||||
|
const url = item.url || ('/pages/' + item.id);
|
||||||
|
return '<li class="sidebar-item" style="padding-left:8px;cursor:pointer" ' +
|
||||||
|
'data-page-id="' + item.id + '" data-page-depth="0" data-has-children="false" ' +
|
||||||
|
'onclick="window.appState.navigateTo(\'' + url + '\')" ' +
|
||||||
|
'oncontextmenu="event.preventDefault();window.appState.showContextMenu(event,\'' + item.id + '\',\'' + safeName + '\')">' +
|
||||||
|
'<span class="tree-toggle-placeholder"></span>' +
|
||||||
|
'<span class="page-icon">' + icon + '</span>' +
|
||||||
|
'<span class="page-name">' + safeName + '</span>' +
|
||||||
|
'<span class="item-actions">' +
|
||||||
|
'<button class="item-action-btn" title="View in Library" onclick="event.stopPropagation();window.appState.navigateTo(\'/library\')">📚</button>' +
|
||||||
|
'<button class="item-action-btn" title="New sub-page" onclick="event.stopPropagation();window.appState.newSubPage(\'' + item.id + '\')">+</button>' +
|
||||||
|
'</span>' +
|
||||||
|
'</li>';
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// ── Sections collapsible ──
|
// ── Sections collapsible ──
|
||||||
sectionsOpen: (function() {
|
sectionsOpen: (function() {
|
||||||
@@ -727,8 +761,7 @@
|
|||||||
if (isFav) self.favoriteIds.delete(pageId);
|
if (isFav) self.favoriteIds.delete(pageId);
|
||||||
else self.favoriteIds.add(pageId);
|
else self.favoriteIds.add(pageId);
|
||||||
self.contextMenu.visible = false;
|
self.contextMenu.visible = false;
|
||||||
// Reload to update sidebar
|
self.refreshFavorites();
|
||||||
location.reload();
|
|
||||||
})
|
})
|
||||||
.catch(e => this.toast('Favorite action failed', 'error'));
|
.catch(e => this.toast('Favorite action failed', 'error'));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
||||||
{% set page_icon = "📄" if page.content_format != 'file' else "📎" %}
|
{% set page_icon = "📄" if page.content_format != 'file' else "📎" %}
|
||||||
{% set page_title = page.title %}
|
{% set page_title = page.title %}
|
||||||
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()">🔒 Share ▾</button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">🔗</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()">⭐</button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()">🔒 Share ▾</button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">🔗</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()" x-text="(window.E && window.E.favorited) ? \'⭐\' : \'☆\'"></button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
||||||
{% include '_header.html' %}
|
{% include '_header.html' %}
|
||||||
{% endblock %} {% block content %}
|
{% endblock %} {% block content %}
|
||||||
<div class="page-editor-wrapper" x-data="editorState()">
|
<div class="page-editor-wrapper" x-data="editorState()">
|
||||||
@@ -686,7 +686,9 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
|||||||
const csrf=document.cookie.match(/csrf_token=([^;]+)/);
|
const csrf=document.cookie.match(/csrf_token=([^;]+)/);
|
||||||
const m=this.favorited?'DELETE':'POST';
|
const m=this.favorited?'DELETE':'POST';
|
||||||
fetch(`/board/api/favorites/${this.pid}`,{method:m,headers:{'X-CSRF-Token':csrf?csrf[1]:''}})
|
fetch(`/board/api/favorites/${this.pid}`,{method:m,headers:{'X-CSRF-Token':csrf?csrf[1]:''}})
|
||||||
.then(r=>r.json()).then(()=>{this.favorited=!this.favorited;this.showToast(this.favorited?'Added to favorites':'Removed from favorites');}).catch(()=>{this.showToast('Failed to toggle favorite');});
|
.then(r=>r.json()).then(()=>{this.favorited=!this.favorited;this.showToast(this.favorited?'Added to favorites':'Removed from favorites');
|
||||||
|
if(window.appState&&window.appState.refreshFavorites)window.appState.refreshFavorites();
|
||||||
|
}).catch(()=>{this.showToast('Failed to toggle favorite');});
|
||||||
},
|
},
|
||||||
toggleActivityOpen(){
|
toggleActivityOpen(){
|
||||||
if(!this.activityOpen){this.activityOpen=true;this._justOpened=true;setTimeout(()=>this._justOpened=false,200);}
|
if(!this.activityOpen){this.activityOpen=true;this._justOpened=true;setTimeout(()=>this._justOpened=false,200);}
|
||||||
|
|||||||
Reference in New Issue
Block a user