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 ──
|
||||
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 ──
|
||||
sectionsOpen: (function() {
|
||||
@@ -727,8 +761,7 @@
|
||||
if (isFav) self.favoriteIds.delete(pageId);
|
||||
else self.favoriteIds.add(pageId);
|
||||
self.contextMenu.visible = false;
|
||||
// Reload to update sidebar
|
||||
location.reload();
|
||||
self.refreshFavorites();
|
||||
})
|
||||
.catch(e => this.toast('Favorite action failed', 'error'));
|
||||
break;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
||||
{% set page_icon = "📄" if page.content_format != 'file' else "📎" %}
|
||||
{% 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' %}
|
||||
{% endblock %} {% block content %}
|
||||
<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 m=this.favorited?'DELETE':'POST';
|
||||
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(){
|
||||
if(!this.activityOpen){this.activityOpen=true;this._justOpened=true;setTimeout(()=>this._justOpened=false,200);}
|
||||
|
||||
Reference in New Issue
Block a user