feat: fix favorites display and add star indicator on favorited items

- Add ?metadata=true support to GET /api/files/{id} to return JSON metadata
  instead of binary content (was the root cause of favorites not loading)
- Fix favorites loadFileDetails to use metadata endpoint with auth headers
- Add star icon on favorited files/folders in grid view (top-left corner)
- Add star icon on favorited files/folders in list view (next to name)
- Refresh file view when toggling favorites so star appears/disappears
- Add CSS styles for .favorite-star and .favorite-star-inline
This commit is contained in:
Dionisio
2026-02-13 09:32:16 +01:00
parent fb65d1976b
commit 5c53d94c0c
4 changed files with 83 additions and 23 deletions
+37
View File
@@ -92,4 +92,41 @@
.favorite-indicator.active {
animation: favorite-pulse 0.3s ease;
}
/* ── Star badge on file/folder cards (normal view) ── */
/* Grid view: star in top-left corner */
.file-card .favorite-star {
position: absolute;
top: 8px;
left: 8px;
font-size: 14px;
color: #ffc107;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
z-index: 5;
pointer-events: none;
[dir='rtl'] & {
left: unset;
right: 8px;
}
}
.file-card .favorite-star.active i {
animation: favorite-pulse 0.3s ease;
}
/* List view: small star next to the name */
.favorite-star-inline {
color: #ffc107;
font-size: 11px;
margin-left: 6px;
vertical-align: middle;
filter: drop-shadow(0 0 1px rgba(255, 193, 7, 0.4));
[dir='rtl'] & {
margin-left: 0;
margin-right: 6px;
}
}
+20 -23
View File
@@ -234,6 +234,11 @@ const favorites = {
`"${name}" added to favorites`
);
// Refresh file view to show star icon
if (window.app.currentSection === 'files' && typeof window.loadFiles === 'function') {
window.loadFiles();
}
return true;
} catch (error) {
console.error('Error adding to favorites:', error);
@@ -275,6 +280,12 @@ const favorites = {
`"${item.name}" removed from favorites`
);
}
// Refresh file view to remove star icon
if (window.app.currentSection === 'files' && typeof window.loadFiles === 'function') {
window.loadFiles();
}
return true;
}
@@ -371,7 +382,9 @@ const favorites = {
*/
async loadFolderDetails(favorite, filesGrid, filesListView) {
try {
const response = await fetch(`/api/folders/${favorite.id}`);
const token = localStorage.getItem('oxicloud_token');
const headers = token ? { 'Authorization': `Bearer ${token}` } : {};
const response = await fetch(`/api/folders/${favorite.id}`, { headers });
if (response.ok) {
const folder = await response.json();
@@ -398,30 +411,14 @@ const favorites = {
*/
async loadFileDetails(favorite, filesGrid, filesListView) {
try {
const response = await fetch(`/api/files/${favorite.id}`);
const token = localStorage.getItem('oxicloud_token');
const headers = token ? { 'Authorization': `Bearer ${token}` } : {};
const response = await fetch(`/api/files/${favorite.id}?metadata=true`, { headers });
if (response.ok) {
// Check if the response is JSON or binary data like a PDF
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
const file = await response.json();
// Create UI element with favorite indicator
this.createFavoriteFileElement(file, filesGrid, filesListView);
} else {
// For non-JSON responses (like PDFs or other binary files)
// Create a simplified file element with minimal information
const file = {
id: favorite.id,
name: favorite.name || `File ${favorite.id}`,
mime_type: contentType || 'application/octet-stream',
size: 0, // We don't know the size from this response
modified_at: Math.floor(Date.now() / 1000) // Current time in seconds
};
this.createFavoriteFileElement(file, filesGrid, filesListView);
}
const file = await response.json();
// Create UI element with favorite indicator
this.createFavoriteFileElement(file, filesGrid, filesListView);
} else if (response.status === 404) {
// File not found, might be deleted
console.log(`Favorite file ${favorite.id} not found, removing from favorites`);
+12
View File
@@ -666,9 +666,14 @@ const ui = {
folderGridElement.dataset.folderId = folder.id;
folderGridElement.dataset.folderName = folder.name;
folderGridElement.dataset.parentId = folder.parent_id || "";
// Check if folder is a favorite
const isFolderFav = window.favorites && window.favorites.isFavorite(folder.id, 'folder');
folderGridElement.innerHTML = `
<div class="file-card-checkbox"><i class="fas fa-check"></i></div>
<button class="file-card-more"><i class="fas fa-ellipsis-v"></i></button>
${isFolderFav ? '<div class="favorite-star active"><i class="fas fa-star"></i></div>' : ''}
<div class="file-icon folder-icon">
<i class="fas fa-folder"></i>
</div>
@@ -813,6 +818,7 @@ const ui = {
<i class="fas fa-folder"></i>
</div>
<span>${folder.name}</span>
${isFolderFav ? '<i class="fas fa-star favorite-star-inline"></i>' : ''}
</div>
<div class="type-cell">${window.i18n ? window.i18n.t('files.file_types.folder') : 'Folder'}</div>
<div class="size-cell">--</div>
@@ -927,9 +933,14 @@ const ui = {
// Grid view element
const fileGridElement = document.createElement('div');
fileGridElement.className = 'file-card';
// Check if file is a favorite
const isFileFav = window.favorites && window.favorites.isFavorite(file.id, 'file');
fileGridElement.innerHTML = `
<div class="file-card-checkbox"><i class="fas fa-check"></i></div>
<button class="file-card-more"><i class="fas fa-ellipsis-v"></i></button>
${isFileFav ? '<div class="favorite-star active"><i class="fas fa-star"></i></div>' : ''}
<div class="file-icon">
<i class="${iconClass}"></i>
</div>
@@ -1037,6 +1048,7 @@ const ui = {
<i class="${iconClass}"></i>
</div>
<span>${file.name}</span>
${isFileFav ? '<i class="fas fa-star favorite-star-inline"></i>' : ''}
</div>
<div class="type-cell">${typeLabel}</div>
<div class="size-cell">${fileSize}</div>