mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
feat: customize the order of Explorer sidebar items
This commit is contained in:
parent
121043d312
commit
ff30de1d69
@ -563,6 +563,11 @@ async function UIDesktop(options){
|
||||
}
|
||||
})
|
||||
|
||||
// load window sidebar items from KV
|
||||
puter.kv.get("sidebar_items").then(async (val) => {
|
||||
window.sidebar_items = val;
|
||||
})
|
||||
|
||||
// Get menubar style
|
||||
puter.kv.get('menubar_style').then(async (val) => {
|
||||
let value = val;
|
||||
|
@ -265,12 +265,35 @@ async function UIWindow(options) {
|
||||
>`;
|
||||
// favorites
|
||||
h += `<h2 class="window-sidebar-title disable-user-select">${i18n('favorites')}</h2>`;
|
||||
// default items if sidebar_items is not set
|
||||
if(!window.sidebar_items){
|
||||
h += `<div draggable="false" title="${i18n('home')}" class="window-sidebar-item disable-user-select ${options.path === window.home_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.home_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-home.svg'])}">${i18n('home')}</div>`;
|
||||
h += `<div draggable="false" title="${i18n('documents')}" class="window-sidebar-item disable-user-select ${options.path === window.docs_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.docs_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-documents.svg'])}">${i18n('documents')}</div>`;
|
||||
h += `<div draggable="false" title="${i18n('public')}" class="window-sidebar-item disable-user-select ${options.path === window.public_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.public_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-public.svg'])}">${i18n('public')}</div>`;
|
||||
h += `<div draggable="false" title="${i18n('pictures')}" class="window-sidebar-item disable-user-select ${options.path === window.pictures_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.pictures_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-pictures.svg'])}">${i18n('pictures')}</div>`;
|
||||
h += `<div draggable="false" title="${i18n('desktop')}" class="window-sidebar-item disable-user-select ${options.path === window.desktop_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.desktop_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-desktop.svg'])}">${i18n('desktop')}</div>`;
|
||||
h += `<div draggable="false" title="${i18n('videos')}" class="window-sidebar-item disable-user-select ${options.path === window.videos_path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(window.videos_path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(window.icons['sidebar-folder-videos.svg'])}">${i18n('videos')}</div>`;
|
||||
}else{
|
||||
let items = JSON.parse(window.sidebar_items);
|
||||
for(let item of items){
|
||||
let icon;
|
||||
if(item.path === window.home_path)
|
||||
icon = window.icons['sidebar-folder-home.svg'];
|
||||
else if(item.path === window.docs_path)
|
||||
icon = window.icons['sidebar-folder-documents.svg'];
|
||||
else if(item.path === window.public_path)
|
||||
icon = window.icons['sidebar-folder-public.svg'];
|
||||
else if(item.path === window.pictures_path)
|
||||
icon = window.icons['sidebar-folder-pictures.svg'];
|
||||
else if(item.path === window.desktop_path)
|
||||
icon = window.icons['sidebar-folder-desktop.svg'];
|
||||
else if(item.path === window.videos_path)
|
||||
icon = window.icons['sidebar-folder-videos.svg'];
|
||||
else
|
||||
icon = window.icons['sidebar-folder.svg'];
|
||||
h += `<div title="${html_encode(item.label)}" class="window-sidebar-item disable-user-select ${options.path === item.path ? 'window-sidebar-item-active' : ''}" data-path="${html_encode(item.path)}"><img draggable="false" class="window-sidebar-item-icon" src="${html_encode(icon)}">${html_encode(item.name)}</div>`;
|
||||
}
|
||||
}
|
||||
h += `</div>`;
|
||||
}
|
||||
|
||||
@ -434,6 +457,7 @@ async function UIWindow(options) {
|
||||
// Append
|
||||
$(el_body).append(h);
|
||||
|
||||
|
||||
// disable_parent_window
|
||||
if(options.disable_parent_window && options.parent_uuid !== null){
|
||||
const $el_parent_window = $(`.window[data-element_uuid="${options.parent_uuid}"]`);
|
||||
@ -2369,6 +2393,70 @@ async function UIWindow(options) {
|
||||
});
|
||||
})
|
||||
|
||||
//--------------------------------------------------
|
||||
// Sidebar sortable
|
||||
//--------------------------------------------------
|
||||
if(options.is_dir && !isMobile.phone){
|
||||
loadSavedSidebarOrder(el_window);
|
||||
const $sidebar = $(el_window).find('.window-sidebar');
|
||||
|
||||
$sidebar.sortable({
|
||||
items: '.window-sidebar-item:not(.window-sidebar-title)', // More specific selector
|
||||
connectWith: '.window-sidebar',
|
||||
cursor: 'move',
|
||||
axis: 'y',
|
||||
distance: 5,
|
||||
containment: 'parent',
|
||||
placeholder: 'window-sidebar-item-placeholder',
|
||||
tolerance: 'pointer',
|
||||
helper: 'clone',
|
||||
opacity: 0.8,
|
||||
|
||||
start: function(event, ui) {
|
||||
// Add dragging class
|
||||
ui.item.addClass('window-sidebar-item-dragging');
|
||||
|
||||
// Create placeholder styling
|
||||
ui.placeholder.css({
|
||||
'height': ui.item.height(),
|
||||
'visibility': 'visible',
|
||||
});
|
||||
},
|
||||
|
||||
sort: function(event, ui) {
|
||||
// Ensure the helper follows the cursor properly
|
||||
ui.helper.css('pointer-events', 'none');
|
||||
},
|
||||
|
||||
stop: function(event, ui) {
|
||||
// Remove dragging class
|
||||
ui.item.removeClass('window-sidebar-item-dragging');
|
||||
|
||||
// Get the new order
|
||||
const newOrder = $sidebar.find('.window-sidebar-item').map(function() {
|
||||
return {
|
||||
path: $(this).attr('data-path'),
|
||||
name: $(this).text().trim()
|
||||
};
|
||||
}).get();
|
||||
|
||||
// Save the new order
|
||||
saveSidebarOrder(newOrder);
|
||||
}
|
||||
}).disableSelection(); // Prevent text selection while dragging
|
||||
|
||||
// Make the sortable operation more responsive
|
||||
$sidebar.on('mousedown', '.window-sidebar-item', function(e) {
|
||||
if (!$(this).hasClass('window-sidebar-title')) {
|
||||
$(this).addClass('grabbing');
|
||||
}
|
||||
});
|
||||
|
||||
$sidebar.on('mouseup mouseleave', '.window-sidebar-item', function() {
|
||||
$(this).removeClass('grabbing');
|
||||
});
|
||||
}
|
||||
|
||||
//set styles
|
||||
$(el_window_body).css(options.body_css);
|
||||
|
||||
@ -3575,4 +3663,50 @@ document.addEventListener('scroll', function (event) {
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Function to save sidebar order to user preferences
|
||||
async function saveSidebarOrder(order) {
|
||||
try {
|
||||
await puter.kv.set({
|
||||
key: "sidebar_items",
|
||||
value: JSON.stringify(order)
|
||||
});
|
||||
|
||||
// Save to window object for quick access
|
||||
window.sidebar_items = JSON.stringify(order);
|
||||
} catch(err) {
|
||||
console.error('Error saving sidebar order:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load and apply saved sidebar order
|
||||
async function loadSavedSidebarOrder(el_window) {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
// Load saved sidebar order
|
||||
let savedOrder = window.sidebar_items
|
||||
|
||||
// If not found in window object, try to get from KV
|
||||
if(!savedOrder){
|
||||
savedOrder = await puter.kv.get("sidebar_items");
|
||||
}
|
||||
|
||||
// If found, apply the order
|
||||
if (savedOrder && savedOrder !== 'null' && savedOrder !== 'undefined') {
|
||||
const order = JSON.parse(savedOrder);
|
||||
const $sidebar = $(el_window).find('.window-sidebar');
|
||||
|
||||
// Reorder items according to saved order
|
||||
order.forEach(item => {
|
||||
const $item = $sidebar.find(`.window-sidebar-item[data-path="${item.path}"]`);
|
||||
if ($item.length) {
|
||||
$item.appendTo($sidebar);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch(err) {
|
||||
console.error('Error loading sidebar order:', err);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
export default UIWindow;
|
||||
|
@ -1242,7 +1242,7 @@ span.header-sort-icon img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.window-sidebar-item {
|
||||
.window-sidebar-item, .window-sidebar-item.grabbing {
|
||||
margin-bottom: 6px;
|
||||
margin-top: 2px;
|
||||
padding: 4px;
|
||||
@ -1262,6 +1262,34 @@ span.header-sort-icon img {
|
||||
background-color: #fefeff;
|
||||
}
|
||||
|
||||
.window-sidebar-item.grabbing, .window-sidebar-item.ui-sortable-helper{
|
||||
background-color: none !important;
|
||||
height: 23px !important;
|
||||
/* width: 100% !important; */
|
||||
}
|
||||
.window-sidebar-item-placeholder{
|
||||
height: 27px !important;
|
||||
}
|
||||
.window-sidebar-item {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.window-sidebar-item:not(.window-sidebar-title):hover {
|
||||
cursor: grab;
|
||||
}
|
||||
.window-sidebar-item.grabbing {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
.window-sidebar-item-dragging {
|
||||
background-color: #f5f5f5 !important;
|
||||
opacity: 0.8;
|
||||
cursor: grabbing;
|
||||
}
|
||||
.ui-sortable-helper {
|
||||
background: white !important;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
|
||||
.window-sidebar-item-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
8
src/gui/src/icons/sidebar-folder.svg
Normal file
8
src/gui/src/icons/sidebar-folder.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" version="1">
|
||||
<rect style="opacity:0.2" width="40" height="26" x="4" y="17" rx="2" ry="2"/>
|
||||
<path style="fill:#e19d00" d="M 4,34 C 4,35.108 4.892,36 6,36 H 42 C 43.108,36 44,35.108 44,34 V 12 C 44,10.892 43.108,10 42,10 H 24 C 21,10 20,6 17,6 H 6 C 4.892,6 4,6.892 4,8"/>
|
||||
<rect style="opacity:0.2" width="40" height="26" x="4" y="15" rx="2" ry="2"/>
|
||||
<rect style="fill:#e4e4e4" width="36" height="16" x="6" y="13" rx="2" ry="2"/>
|
||||
<rect style="fill:#f9bd30" width="40" height="26" x="4" y="16" rx="2" ry="2"/>
|
||||
<path style="opacity:0.1;fill:#ffffff" d="M 6,6 C 4.892,6 4,6.892 4,8 V 9 C 4,7.892 4.892,7 6,7 H 17 C 20,7 21,11 24,11 H 42 C 43.108,11 44,11.892 44,13 V 12 C 44,10.892 43.108,10 42,10 H 24 C 21,10 20,6 17,6 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 797 B |
Loading…
Reference in New Issue
Block a user