mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-28 05:27:35 +00:00
feat(ui): add drag-to-reorder for pinned notes in sidebar (#25677)
This commit is contained in:
parent
3fd0384ffc
commit
70b89d01c2
3 changed files with 102 additions and 45 deletions
|
|
@ -78,6 +78,7 @@
|
|||
import FolderModal from './Sidebar/Folders/FolderModal.svelte';
|
||||
import Sidebar from '../icons/Sidebar.svelte';
|
||||
import PinnedModelList from './Sidebar/PinnedModelList.svelte';
|
||||
import PinnedNoteList from './Sidebar/PinnedNoteList.svelte';
|
||||
import Note from '../icons/Note.svelte';
|
||||
import Code from '../icons/Code.svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
|
|
@ -1257,51 +1258,7 @@
|
|||
}}
|
||||
onAddLabel={$i18n.t('New Note')}
|
||||
>
|
||||
<div class="mt-0.5 pb-1.5">
|
||||
{#each $pinnedNotes as note (note.id)}
|
||||
<a
|
||||
class="w-full flex items-center gap-2.5 rounded-xl px-2.5 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-900 transition group text-sm"
|
||||
href={`/notes/${note.id}`}
|
||||
on:click={() => {
|
||||
itemClickHandler();
|
||||
}}
|
||||
draggable="false"
|
||||
>
|
||||
<div class="self-center">
|
||||
<Note className="size-4" strokeWidth="2" />
|
||||
</div>
|
||||
<div class="flex-1 text-ellipsis line-clamp-1">
|
||||
{note.title}
|
||||
</div>
|
||||
<button
|
||||
class="invisible group-hover:visible self-center p-0.5 hover:bg-gray-200 dark:hover:bg-gray-800 rounded-lg transition"
|
||||
on:click|preventDefault|stopPropagation={async () => {
|
||||
await toggleNotePinnedStatusById(localStorage.token, note.id);
|
||||
const _pinnedNotes = await getPinnedNoteList(localStorage.token).catch(
|
||||
() => []
|
||||
);
|
||||
pinnedNotes.set(_pinnedNotes);
|
||||
}}
|
||||
aria-label={$i18n.t('Unpin')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M6 18 18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
<PinnedNoteList bind:selectedChatId />
|
||||
</Folder>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
99
src/lib/components/layout/Sidebar/PinnedNoteList.svelte
Normal file
99
src/lib/components/layout/Sidebar/PinnedNoteList.svelte
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<script>
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
import { onMount, getContext, tick } from 'svelte';
|
||||
|
||||
import { chatId, mobile, pinnedNotes, settings, showSidebar } from '$lib/stores';
|
||||
import { updateUserSettings } from '$lib/apis/users';
|
||||
import { getPinnedNoteList, toggleNotePinnedStatusById } from '$lib/apis/notes';
|
||||
import Note from '$lib/components/icons/Note.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let selectedChatId = null;
|
||||
|
||||
$: sortedPinnedNotes = (() => {
|
||||
const order = $settings?.pinnedNotesOrder;
|
||||
if (!order || order.length === 0) return $pinnedNotes;
|
||||
const orderMap = new Map(order.map((id, idx) => [id, idx]));
|
||||
return [...$pinnedNotes].sort((a, b) => {
|
||||
const aIdx = orderMap.has(a.id) ? orderMap.get(a.id) : Infinity;
|
||||
const bIdx = orderMap.has(b.id) ? orderMap.get(b.id) : Infinity;
|
||||
return aIdx - bIdx;
|
||||
});
|
||||
})();
|
||||
|
||||
const initPinnedNotesSortable = () => {
|
||||
const pinnedNotesList = document.getElementById('pinned-notes-list');
|
||||
if (pinnedNotesList && !$mobile) {
|
||||
new Sortable(pinnedNotesList, {
|
||||
animation: 150,
|
||||
onUpdate: async (event) => {
|
||||
const noteId = event.item.dataset.id;
|
||||
const newIndex = event.newIndex;
|
||||
const current = sortedPinnedNotes.map((n) => n.id);
|
||||
const oldIndex = current.indexOf(noteId);
|
||||
current.splice(oldIndex, 1);
|
||||
current.splice(newIndex, 0, noteId);
|
||||
settings.set({ ...$settings, pinnedNotesOrder: current });
|
||||
await updateUserSettings(localStorage.token, { ui: $settings });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
await tick();
|
||||
initPinnedNotesSortable();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="mt-0.5 pb-1.5" id="pinned-notes-list">
|
||||
{#each sortedPinnedNotes as note (note.id)}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="flex items-center text-gray-800 dark:text-gray-200 cursor-grab relative group rounded-xl px-2.5 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
|
||||
data-id={note.id}
|
||||
>
|
||||
<a
|
||||
class="grow flex items-center gap-2.5 text-sm"
|
||||
href={`/notes/${note.id}`}
|
||||
on:click={() => {
|
||||
selectedChatId = null;
|
||||
chatId.set('');
|
||||
if ($mobile) {
|
||||
showSidebar.set(false);
|
||||
}
|
||||
}}
|
||||
draggable="false"
|
||||
>
|
||||
<div class="self-center">
|
||||
<Note className="size-4" strokeWidth="2" />
|
||||
</div>
|
||||
<div class="flex-1 text-ellipsis line-clamp-1">
|
||||
{note.title}
|
||||
</div>
|
||||
</a>
|
||||
<button
|
||||
class="invisible group-hover:visible self-center p-0.5 hover:bg-gray-200 dark:hover:bg-gray-800 rounded-lg transition"
|
||||
on:click|preventDefault|stopPropagation={async () => {
|
||||
await toggleNotePinnedStatusById(localStorage.token, note.id);
|
||||
const _pinnedNotes = await getPinnedNoteList(localStorage.token).catch(() => []);
|
||||
pinnedNotes.set(_pinnedNotes);
|
||||
}}
|
||||
aria-label={$i18n.t('Unpin')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
@ -234,6 +234,7 @@ type Settings = {
|
|||
renderMarkdownInAssistantMessages?: boolean;
|
||||
recentEmojis?: string[];
|
||||
pinnedMenuItems?: string[];
|
||||
pinnedNotesOrder?: string[];
|
||||
|
||||
system?: string;
|
||||
seed?: number;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue