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:
@@ -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
@@ -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`);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user