mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-23 05:54:48 -06:00
refac
This commit is contained in:
@@ -33,12 +33,12 @@
|
||||
import GarbageBin from '../icons/GarbageBin.svelte';
|
||||
import Search from '../icons/Search.svelte';
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import AddFunctionMenu from './Functions/AddFunctionMenu.svelte';
|
||||
import ImportModal from '../ImportModal.svelte';
|
||||
import ViewSelector from '../workspace/common/ViewSelector.svelte';
|
||||
import TagSelector from '../workspace/common/TagSelector.svelte';
|
||||
import CommunityDiscover from '../workspace/common/CommunityDiscover.svelte';
|
||||
import { capitalizeFirstLetter } from '$lib/utils';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
|
||||
@@ -352,11 +352,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class="px-3.5 flex flex-1 items-center w-full space-x-2 py-0.5 pb-2">
|
||||
<div class="flex flex-1">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 flex-1 items-center w-full gap-2">
|
||||
<div class="flex min-w-0 flex-1">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -381,47 +379,49 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-0.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
|
||||
<TagSelector
|
||||
bind:value={selectedType}
|
||||
items={[
|
||||
{ value: 'pipe', label: $i18n.t('Pipe') },
|
||||
{ value: 'filter', label: $i18n.t('Filter') },
|
||||
{ value: 'action', label: $i18n.t('Action') },
|
||||
{ value: 'event', label: $i18n.t('Event') }
|
||||
]}
|
||||
/>
|
||||
<TagSelector
|
||||
bind:value={selectedType}
|
||||
align="end"
|
||||
items={[
|
||||
{ value: 'pipe', label: $i18n.t('Pipe') },
|
||||
{ value: 'filter', label: $i18n.t('Filter') },
|
||||
{ value: 'action', label: $i18n.t('Action') },
|
||||
{ value: 'event', label: $i18n.t('Event') }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if (filteredItems ?? []).length !== 0}
|
||||
<div class="px-3 my-2 gap-1 lg:gap-2 grid lg:grid-cols-2">
|
||||
<div class="my-1 gap-x-2 gap-y-0.5 grid lg:grid-cols-2">
|
||||
{#each filteredItems as func (func.id)}
|
||||
<div
|
||||
class=" flex space-x-4 cursor-pointer w-full px-2 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
|
||||
class="flex space-x-4 cursor-pointer w-full px-2.5 py-1.5 rounded-2xl hover:bg-gray-50/70 dark:hover:bg-gray-850/50"
|
||||
>
|
||||
<a
|
||||
class=" flex flex-1 space-x-3.5 cursor-pointer w-full"
|
||||
@@ -606,30 +606,11 @@
|
||||
</div> -->
|
||||
|
||||
{#if $config?.features.enable_community_sharing}
|
||||
<div class=" my-16">
|
||||
<div class=" text-xl font-medium mb-1 line-clamp-1">
|
||||
{$i18n.t('Made by Open WebUI Community')}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class=" flex cursor-pointer items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-850 w-full mb-2 px-3.5 py-1.5 rounded-xl transition"
|
||||
href="https://openwebui.com/functions"
|
||||
target="_blank"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<div class=" font-semibold line-clamp-1">{$i18n.t('Discover a function')}</div>
|
||||
<div class=" text-sm line-clamp-1">
|
||||
{$i18n.t('Discover, download, and explore custom functions')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<CommunityDiscover
|
||||
href="https://openwebui.com/functions"
|
||||
title={$i18n.t('Discover a function')}
|
||||
description={$i18n.t('Discover, download, and explore custom functions')}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
editHandler();
|
||||
@@ -59,7 +59,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
cloneHandler();
|
||||
@@ -71,7 +71,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
runHandler();
|
||||
@@ -99,7 +99,7 @@
|
||||
<hr class="border-gray-50 dark:border-gray-850/30 mx-1 my-0.5" />
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-2xl text-xs transition
|
||||
text-gray-600 dark:text-gray-400 hover:bg-black/5 dark:hover:bg-white/5"
|
||||
text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -91,8 +91,8 @@
|
||||
{#each filteredModels as model (model.id)}
|
||||
<button
|
||||
class="h-[1.6875rem] px-2 rounded-xl w-full text-left text-[13px] {model_id === model.id
|
||||
? 'bg-gray-50 dark:bg-gray-800'
|
||||
: ''}"
|
||||
? 'text-gray-900 dark:text-gray-100'
|
||||
: 'text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'}"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
model_id = model.id;
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-2xl text-xs transition
|
||||
text-gray-600 dark:text-gray-400 hover:bg-black/5 dark:hover:bg-white/5"
|
||||
text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -284,7 +284,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="flex-1 py-1 text-xs rounded-xl transition {selectedDays.includes(d.key)
|
||||
? 'bg-gray-50 dark:bg-gray-800 text-black dark:text-gray-100'
|
||||
? 'text-black dark:text-gray-100'
|
||||
: 'text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-200'}"
|
||||
on:click={() => {
|
||||
if (selectedDays.includes(d.key)) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
type="button"
|
||||
class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-2xl text-xs transition
|
||||
{terminalServerId ? 'text-black dark:text-gray-100' : 'text-gray-600 dark:text-gray-400'}
|
||||
hover:bg-black/5 dark:hover:bg-white/5"
|
||||
hover:text-gray-900 dark:hover:text-gray-100"
|
||||
>
|
||||
<Cloud className="size-3.5 shrink-0" strokeWidth="2" />
|
||||
<span class="whitespace-nowrap max-w-32 truncate">{terminalLabel}</span>
|
||||
@@ -59,8 +59,8 @@
|
||||
<button
|
||||
class="flex w-full h-[1.6875rem] justify-between gap-2 items-center px-2 text-[13px] cursor-pointer rounded-xl {terminalServerId ===
|
||||
server.id
|
||||
? 'bg-gray-50 dark:bg-gray-800/50'
|
||||
: 'hover:bg-gray-50 dark:hover:bg-gray-800/50'}"
|
||||
? 'text-gray-900 dark:text-gray-100'
|
||||
: 'text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'}"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
if (terminalServerId === server.id) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={`rounded-xl! p-0.5! border border-gray-100 dark:border-gray-800 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg ${className} [&>button]:flex [&>button]:w-full [&>button]:h-[1.6875rem] [&>button]:items-center [&>button]:gap-2 [&>button]:rounded-xl! [&>button]:px-2! [&>button]:text-[13px] [&>button:hover]:bg-gray-50/60 dark:[&>button:hover]:bg-gray-800/60 [&>a]:flex [&>a]:w-full [&>a]:h-[1.6875rem] [&>a]:items-center [&>a]:gap-2 [&>a]:rounded-xl! [&>a]:px-2! [&>a]:text-[13px] [&>a:hover]:bg-gray-50/60 dark:[&>a:hover]:bg-gray-800/60 [&>button_svg]:size-3.5 [&>a_svg]:size-3.5 [&>hr]:my-0.5 [&>hr]:mx-1`}
|
||||
class={`rounded-xl! p-0.5! border border-gray-100 dark:border-gray-800 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg ${className} [&_button:hover]:bg-transparent! [&_a:hover]:bg-transparent! [&_button:hover]:text-gray-900 dark:[&_button:hover]:text-gray-100 [&_a:hover]:text-gray-900 dark:[&_a:hover]:text-gray-100 [&>button]:flex [&>button]:w-full [&>button]:h-[1.6875rem]! [&>button]:items-center [&>button]:gap-2! [&>button]:rounded-xl! [&>button]:bg-transparent [&>button]:px-2! [&>button]:text-[13px]! [&>button]:font-normal! [&>a]:flex [&>a]:w-full [&>a]:h-[1.6875rem]! [&>a]:items-center [&>a]:gap-2! [&>a]:rounded-xl! [&>a]:bg-transparent [&>a]:px-2! [&>a]:text-[13px]! [&>a]:font-normal! [&_button_svg]:size-3.5! [&_a_svg]:size-3.5! [&>hr]:my-0.5 [&>hr]:mx-1`}
|
||||
{style}
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
{align}
|
||||
triggerClass={className
|
||||
? className
|
||||
: 'flex shrink-0 items-center gap-2 bg-transparent px-0.5 text-sm placeholder-gray-400 outline-hidden focus:outline-hidden'}
|
||||
itemClass="flex w-full h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
: 'flex h-8 shrink-0 items-center gap-1.5 rounded-xl bg-transparent px-1.5 text-[13px] font-normal text-gray-700 transition placeholder-gray-400 outline-hidden hover:text-gray-900 focus:outline-hidden dark:text-gray-200 dark:hover:text-gray-100'}
|
||||
itemClass="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
onChange={(v) => {
|
||||
onChange(v);
|
||||
}}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
/** CSS classes for each item button */
|
||||
export let itemClass =
|
||||
'flex w-full gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl';
|
||||
'flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100';
|
||||
|
||||
/** Alignment of the dropdown: 'start' | 'end' */
|
||||
export let align = 'start';
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px] font-primary">
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={async () => {
|
||||
onEdit();
|
||||
show = false;
|
||||
@@ -43,7 +43,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onChat();
|
||||
show = false;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
$: loadLocale($i18n.languages);
|
||||
|
||||
import { goto } from '$app/navigation';
|
||||
import { WEBUI_NAME, config, user, pinnedNotes } from '$lib/stores';
|
||||
import { WEBUI_NAME, config, user, pinnedNotes, mobile, showSidebar } from '$lib/stores';
|
||||
import {
|
||||
createNewNote,
|
||||
deleteNoteById,
|
||||
@@ -47,7 +47,6 @@
|
||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
import Search from '../icons/Search.svelte';
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import NoteMenu from './Notes/NoteMenu.svelte';
|
||||
@@ -55,6 +54,7 @@
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import DropdownOptions from '../common/DropdownOptions.svelte';
|
||||
import Loader from '../common/Loader.svelte';
|
||||
import SidebarIcon from '../icons/Sidebar.svelte';
|
||||
|
||||
let loaded = false;
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
|
||||
<FilesOverlay show={dragged} />
|
||||
|
||||
<div id="notes-container" class="w-full min-h-full h-full px-3 md:px-[18px]">
|
||||
<div id="notes-container" class="w-full min-h-full h-full">
|
||||
{#if loaded}
|
||||
<DeleteConfirmDialog
|
||||
bind:show={showDeleteConfirm}
|
||||
@@ -339,15 +339,31 @@
|
||||
</div>
|
||||
</DeleteConfirmDialog>
|
||||
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center md:self-center text-xl font-medium px-0.5 gap-2 shrink-0">
|
||||
{#if $mobile}
|
||||
<Tooltip content={$showSidebar ? $i18n.t('Close Sidebar') : $i18n.t('Open Sidebar')}>
|
||||
<button
|
||||
id="sidebar-toggle-button"
|
||||
class="cursor-pointer flex rounded-lg hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
on:click={() => {
|
||||
showSidebar.set(!$showSidebar);
|
||||
}}
|
||||
>
|
||||
<div class="self-center p-1.5">
|
||||
<SidebarIcon />
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
{$i18n.t('Notes')}
|
||||
</div>
|
||||
|
||||
<div class="text-lg font-medium text-gray-500 dark:text-gray-500">
|
||||
{total}
|
||||
{total ?? ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -364,17 +380,15 @@
|
||||
>
|
||||
<Plus className="size-3" strokeWidth="2.5" />
|
||||
|
||||
<div class=" ml-1 text-xs">{$i18n.t('New Note')}</div>
|
||||
<div class="hidden md:block md:ml-1 text-xs">{$i18n.t('New Note')}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class="px-3.5 flex flex-1 items-center w-full space-x-2 py-0.5 pb-2">
|
||||
<div class="flex flex-1 items-center">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 flex-1 items-center w-full gap-2">
|
||||
<div class="flex min-w-0 flex-1 items-center">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -399,11 +413,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-3 flex justify-between">
|
||||
<div
|
||||
class="flex w-full bg-transparent overflow-x-auto scrollbar-none"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
@@ -412,11 +424,10 @@
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-3 w-fit text-center text-sm rounded-full bg-transparent px-0.5 whitespace-nowrap"
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
className="flex shrink-0 items-center gap-2 px-3 py-1.5 text-sm bg-gray-50 dark:bg-gray-850 rounded-xl placeholder-gray-400 outline-hidden focus:outline-hidden"
|
||||
align="end"
|
||||
bind:value={viewOption}
|
||||
items={[
|
||||
{ value: null, label: $i18n.t('All') },
|
||||
@@ -434,7 +445,7 @@
|
||||
|
||||
{#if [null, 'shared'].includes(viewOption)}
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
align="end"
|
||||
bind:value={permission}
|
||||
items={[
|
||||
{ value: null, label: $i18n.t('Write') },
|
||||
@@ -442,25 +453,23 @@
|
||||
]}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shrink-0">
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
bind:value={displayOption}
|
||||
items={[
|
||||
{ value: null, label: $i18n.t('List') },
|
||||
{ value: 'grid', label: $i18n.t('Grid') }
|
||||
]}
|
||||
onChange={() => {
|
||||
if (displayOption) {
|
||||
localStorage.noteDisplayOption = displayOption;
|
||||
} else {
|
||||
delete localStorage.noteDisplayOption;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<DropdownOptions
|
||||
align="end"
|
||||
bind:value={displayOption}
|
||||
items={[
|
||||
{ value: null, label: $i18n.t('List') },
|
||||
{ value: 'grid', label: $i18n.t('Grid') }
|
||||
]}
|
||||
onChange={() => {
|
||||
if (displayOption) {
|
||||
localStorage.noteDisplayOption = displayOption;
|
||||
} else {
|
||||
delete localStorage.noteDisplayOption;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -468,22 +477,20 @@
|
||||
{#if (items ?? []).length > 0}
|
||||
{@const groupedNotes = groupNotes(items)}
|
||||
|
||||
<div class="@container h-full py-2.5 px-2.5">
|
||||
<div class="@container h-full my-1">
|
||||
<div class="">
|
||||
{#each groupedNotes as [timeRange, notesList], idx}
|
||||
<div
|
||||
class="w-full text-xs text-gray-500 dark:text-gray-500 font-medium px-2.5 pb-2.5"
|
||||
>
|
||||
<div class="w-full text-xs text-gray-500 dark:text-gray-500 px-2.5 pb-2.5">
|
||||
{$i18n.t(timeRange)}
|
||||
</div>
|
||||
|
||||
{#if displayOption === null}
|
||||
<div
|
||||
class="{groupedNotes.length - 1 !== idx ? 'mb-3' : ''} gap-1.5 flex flex-col"
|
||||
class="{groupedNotes.length - 1 !== idx ? 'mb-3' : ''} gap-y-0.5 flex flex-col"
|
||||
>
|
||||
{#each notesList as note, idx (note.id)}
|
||||
<div
|
||||
class=" flex cursor-pointer w-full px-3.5 py-1.5 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
||||
class="flex cursor-pointer w-full px-3 py-2 bg-transparent hover:bg-gray-50/70 dark:hover:bg-gray-850/50 rounded-2xl transition"
|
||||
>
|
||||
<a href={`/notes/${note.id}`} class="w-full flex flex-col justify-between">
|
||||
<div class="flex-1">
|
||||
@@ -493,9 +500,7 @@
|
||||
className="flex-1"
|
||||
placement="top-start"
|
||||
>
|
||||
<div
|
||||
class=" text-sm font-medium capitalize flex-1 w-full line-clamp-1"
|
||||
>
|
||||
<div class="text-sm capitalize flex-1 w-full line-clamp-1">
|
||||
{note.title}
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -555,7 +560,7 @@
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||
class="self-center w-fit text-sm p-1 text-gray-500 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100 rounded-xl"
|
||||
type="button"
|
||||
>
|
||||
<EllipsisHorizontal className="size-5" />
|
||||
@@ -577,7 +582,7 @@
|
||||
>
|
||||
{#each notesList as note, idx (note.id)}
|
||||
<div
|
||||
class=" flex space-x-4 cursor-pointer w-full px-4.5 py-4 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
||||
class="flex space-x-4 cursor-pointer w-full px-3 py-2.5 bg-transparent hover:bg-gray-50/70 dark:hover:bg-gray-850/50 rounded-2xl transition"
|
||||
>
|
||||
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
|
||||
<a
|
||||
@@ -588,7 +593,7 @@
|
||||
<div
|
||||
class=" flex items-center gap-2 self-center mb-1 justify-between"
|
||||
>
|
||||
<div class=" font-semibold line-clamp-1 capitalize">
|
||||
<div class="line-clamp-1 capitalize">
|
||||
{note.title}
|
||||
</div>
|
||||
|
||||
@@ -625,7 +630,7 @@
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||
class="self-center w-fit text-sm p-1 text-gray-500 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100 rounded-xl"
|
||||
type="button"
|
||||
>
|
||||
<EllipsisHorizontal className="size-5" />
|
||||
|
||||
@@ -43,14 +43,14 @@
|
||||
<DropdownSub contentClass="select-none z-50">
|
||||
<button
|
||||
slot="trigger"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
>
|
||||
<Download className="size-3.5" strokeWidth="2" />
|
||||
<div class="flex items-center">{$i18n.t('Download')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onDownload('txt');
|
||||
}}
|
||||
@@ -59,7 +59,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onDownload('md');
|
||||
}}
|
||||
@@ -68,7 +68,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onDownload('pdf');
|
||||
}}
|
||||
@@ -81,7 +81,7 @@
|
||||
<DropdownSub contentClass="select-none z-50">
|
||||
<button
|
||||
slot="trigger"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
>
|
||||
<Share className="size-3.5" strokeWidth="2" />
|
||||
<div class="flex items-center">{$i18n.t('Share')}</div>
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
{#if onCopyLink}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onCopyLink();
|
||||
}}
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
{#if onCopyToClipboard}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onCopyToClipboard();
|
||||
}}
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
{#if onPin}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onPin();
|
||||
show = false;
|
||||
@@ -132,7 +132,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onDelete();
|
||||
}}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px] font-primary">
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={async () => {
|
||||
onRecord();
|
||||
show = false;
|
||||
@@ -44,7 +44,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onCaptureAudio();
|
||||
show = false;
|
||||
@@ -57,7 +57,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition"
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload();
|
||||
show = false;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import ViewSelector from './common/ViewSelector.svelte';
|
||||
import TagSelector from './common/TagSelector.svelte';
|
||||
import Loader from '../common/Loader.svelte';
|
||||
|
||||
type KnowledgeListItem = {
|
||||
@@ -187,7 +188,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center md:self-center text-xl font-medium px-0.5 gap-2 shrink-0">
|
||||
<div>
|
||||
@@ -212,11 +213,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class=" flex w-full space-x-2 py-0.5 px-3.5 pb-2">
|
||||
<div class="flex flex-1">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 w-full items-center gap-2">
|
||||
<div class="flex min-w-0 flex-1">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -242,52 +241,54 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none -mx-1"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-1.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
|
||||
<select
|
||||
class="relative w-full flex items-center gap-0.5 px-2.5 py-1.5 bg-gray-50 dark:bg-gray-850 rounded-xl outline-hidden"
|
||||
bind:value={sourceOption}
|
||||
on:change={async () => {
|
||||
localStorage.workspaceKnowledgeSourceOption = sourceOption;
|
||||
await tick();
|
||||
}}
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<option value="">{$i18n.t('All Sources')}</option>
|
||||
<option value="local">{$i18n.t('Local')}</option>
|
||||
<option value="external">{$i18n.t('Connected')}</option>
|
||||
</select>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
|
||||
<TagSelector
|
||||
bind:value={sourceOption}
|
||||
align="end"
|
||||
placeholder={$i18n.t('All Sources')}
|
||||
items={[
|
||||
{ value: 'local', label: $i18n.t('Local') },
|
||||
{ value: 'external', label: $i18n.t('Connected') }
|
||||
]}
|
||||
onChange={async () => {
|
||||
localStorage.workspaceKnowledgeSourceOption = sourceOption;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if items !== null && total !== null}
|
||||
{#if (items ?? []).length !== 0}
|
||||
<!-- The Aleph dreams itself into being, and the void learns its own name -->
|
||||
<div class=" my-2 px-3 grid grid-cols-1 lg:grid-cols-2 gap-2">
|
||||
<div class="my-1 grid grid-cols-1 lg:grid-cols-2 gap-x-2 gap-y-0.5">
|
||||
{#each items as item}
|
||||
<button
|
||||
class=" flex space-x-4 cursor-pointer text-left w-full px-3 py-2.5 dark:hover:bg-gray-850/50 hover:bg-gray-50 transition rounded-2xl"
|
||||
class="flex space-x-4 cursor-pointer text-left w-full px-2.5 py-1.5 transition rounded-2xl hover:bg-gray-50/70 dark:hover:bg-gray-850/50"
|
||||
on:click={() => {
|
||||
if (item?.meta?.document) {
|
||||
toast.error(
|
||||
@@ -413,10 +414,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=" text-gray-500 text-xs m-2">
|
||||
ⓘ {$i18n.t("Use '#' in the prompt input to load and include your knowledge.")}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<Spinner className="size-5" />
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
{#if onExport}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onExport();
|
||||
}}
|
||||
@@ -57,7 +57,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
dispatch('delete');
|
||||
}}
|
||||
|
||||
@@ -1410,7 +1410,7 @@
|
||||
|
||||
<Dropdown align="end">
|
||||
<button
|
||||
class="p-1.5 mr-1 rounded-xl text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 transition"
|
||||
class="p-1.5 mr-1 rounded-xl text-gray-500 bg-transparent hover:text-gray-900 dark:hover:text-gray-100 transition"
|
||||
type="button"
|
||||
>
|
||||
<AdjustmentsHorizontal className="size-3.5" strokeWidth="2" />
|
||||
@@ -1419,7 +1419,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[180px]">
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
includeContent = !includeContent;
|
||||
@@ -1482,8 +1482,8 @@
|
||||
class="flex gap-3 w-fit text-center text-sm rounded-full bg-transparent px-0.5 whitespace-nowrap"
|
||||
>
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
className="flex shrink-0 items-center gap-2 px-3 py-1.5 text-sm bg-gray-50 dark:bg-gray-850 rounded-xl placeholder-gray-400 outline-hidden focus:outline-hidden"
|
||||
align="end"
|
||||
className="flex h-8 shrink-0 items-center gap-1.5 rounded-xl bg-transparent px-1.5 text-[13px] font-normal text-gray-700 transition placeholder-gray-400 outline-hidden hover:text-gray-900 focus:outline-hidden dark:text-gray-200 dark:hover:text-gray-100"
|
||||
bind:value={viewOption}
|
||||
items={[
|
||||
{ value: null, label: $i18n.t('All') },
|
||||
@@ -1500,19 +1500,19 @@
|
||||
/>
|
||||
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
align="end"
|
||||
bind:value={sortKey}
|
||||
placeholder={$i18n.t('Sort')}
|
||||
items={[
|
||||
{ value: 'name', label: $i18n.t('Name') },
|
||||
{ value: 'created_at', label: $i18n.t('Created At') },
|
||||
{ value: 'updated_at', label: $i18n.t('Updated At') }
|
||||
{ value: 'created_at', label: $i18n.t('Created') },
|
||||
{ value: 'updated_at', label: $i18n.t('Updated') }
|
||||
]}
|
||||
/>
|
||||
|
||||
{#if sortKey}
|
||||
<DropdownOptions
|
||||
align="start"
|
||||
align="end"
|
||||
bind:value={direction}
|
||||
items={[
|
||||
{ value: 'asc', label: $i18n.t('Asc') },
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
>
|
||||
<Tooltip content={$i18n.t('Add Content')}>
|
||||
<button
|
||||
class=" p-1.5 rounded-xl hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
|
||||
class="p-1.5 rounded-xl bg-transparent transition text-[13px] font-normal flex items-center space-x-1 hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
show = true;
|
||||
@@ -58,7 +58,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[200px] transition">
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload({ type: 'new_directory' });
|
||||
show = false;
|
||||
@@ -71,7 +71,7 @@
|
||||
<hr class="my-1 border-gray-100 dark:border-gray-800" />
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload({ type: 'files' });
|
||||
}}
|
||||
@@ -81,7 +81,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload({ type: 'directory' });
|
||||
}}
|
||||
@@ -97,7 +97,7 @@
|
||||
className="w-full"
|
||||
>
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onSync();
|
||||
}}
|
||||
@@ -108,7 +108,7 @@
|
||||
</Tooltip>
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload({ type: 'web' });
|
||||
}}
|
||||
@@ -118,7 +118,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onUpload({ type: 'text' });
|
||||
}}
|
||||
@@ -130,7 +130,7 @@
|
||||
<hr class="my-1 border-gray-100 dark:border-gray-800" />
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onReset();
|
||||
show = false;
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
<DropdownMenu className="min-w-[140px] z-[9999999]">
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => startRename()}
|
||||
>
|
||||
<Pencil className="size-3.5" />
|
||||
@@ -183,7 +183,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => onDelete(directory.id)}
|
||||
>
|
||||
<GarbageBin className="size-3.5" />
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
<DropdownMenu className="min-w-[140px] z-[9999999]">
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
startRename(file);
|
||||
}}
|
||||
@@ -198,7 +198,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
let fileId = file?.id ?? file?.tempId;
|
||||
window.open(`${WEBUI_BASE_URL}/api/v1/files/${fileId}/content`, '_blank');
|
||||
@@ -209,7 +209,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] transition hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
onDelete(file?.id ?? file?.tempId);
|
||||
}}
|
||||
|
||||
@@ -37,17 +37,18 @@
|
||||
import GarbageBin from '../icons/GarbageBin.svelte';
|
||||
import Search from '../icons/Search.svelte';
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Switch from '../common/Switch.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import EyeSlash from '../icons/EyeSlash.svelte';
|
||||
import Eye from '../icons/Eye.svelte';
|
||||
import ChevronDown from '../icons/ChevronDown.svelte';
|
||||
|
||||
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||
import DropdownMenu from '$lib/components/common/DropdownMenu.svelte';
|
||||
import ViewSelector from './common/ViewSelector.svelte';
|
||||
import TagSelector from './common/TagSelector.svelte';
|
||||
import CommunityDiscover from './common/CommunityDiscover.svelte';
|
||||
import Pagination from '../common/Pagination.svelte';
|
||||
import Badge from '$lib/components/common/Badge.svelte';
|
||||
|
||||
@@ -373,7 +374,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<input
|
||||
id="models-import-input"
|
||||
bind:this={modelsImportInputElement}
|
||||
@@ -481,11 +482,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class="px-3.5 flex flex-1 items-center w-full space-x-2 py-0.5 pb-2">
|
||||
<div class="flex flex-1 items-center">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 flex-1 items-center w-full gap-2">
|
||||
<div class="flex min-w-0 flex-1 items-center">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -520,113 +519,114 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-0.5 whitespace-nowrap"
|
||||
class="flex max-w-[60%] shrink-0 items-center gap-1 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if (tags ?? []).length > 0}
|
||||
<TagSelector
|
||||
bind:value={selectedTag}
|
||||
items={tags.map((tag) => {
|
||||
return { value: tag, label: tag };
|
||||
})}
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-1"></div>
|
||||
|
||||
<Dropdown>
|
||||
<Tooltip content={$i18n.t('Actions')}>
|
||||
<button
|
||||
class="p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition"
|
||||
type="button"
|
||||
>
|
||||
<EllipsisHorizontal className="size-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu className="w-[170px] shadow-sm">
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
enableAllHandler();
|
||||
}}
|
||||
>
|
||||
<CheckCircle className="size-4" />
|
||||
<div class="flex items-center">{$i18n.t('Enable All')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
disableAllHandler();
|
||||
}}
|
||||
>
|
||||
<Minus className="size-4" />
|
||||
<div class="flex items-center">{$i18n.t('Disable All')}</div>
|
||||
</button>
|
||||
|
||||
<hr class="border-gray-100 dark:border-gray-800 my-1" />
|
||||
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showAllHandler();
|
||||
}}
|
||||
>
|
||||
<Eye className="size-4" />
|
||||
<div class="flex items-center">{$i18n.t('Show All')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
hideAllHandler();
|
||||
}}
|
||||
>
|
||||
<EyeSlash className="size-4" />
|
||||
<div class="flex items-center">{$i18n.t('Hide All')}</div>
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
{#if (tags ?? []).length > 0}
|
||||
<TagSelector
|
||||
bind:value={selectedTag}
|
||||
align="end"
|
||||
items={tags.map((tag) => {
|
||||
return { value: tag, label: tag };
|
||||
})}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown align="end">
|
||||
<Tooltip content={$i18n.t('Actions')}>
|
||||
<button
|
||||
class="flex h-8 items-center gap-1.5 rounded-xl bg-transparent px-1.5 text-[13px] font-normal text-gray-700 transition hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
>
|
||||
<span>{$i18n.t('Actions')}</span>
|
||||
<ChevronDown className="size-3" strokeWidth="2.5" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu className="w-[170px] shadow-sm">
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer select-none items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
enableAllHandler();
|
||||
}}
|
||||
>
|
||||
<CheckCircle className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Enable All')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer select-none items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
disableAllHandler();
|
||||
}}
|
||||
>
|
||||
<Minus className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Disable All')}</div>
|
||||
</button>
|
||||
|
||||
<hr class="mx-1 my-0.5 border-gray-100 dark:border-gray-800" />
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer select-none items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showAllHandler();
|
||||
}}
|
||||
>
|
||||
<Eye className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Show All')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer select-none items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
hideAllHandler();
|
||||
}}
|
||||
>
|
||||
<EyeSlash className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Hide All')}</div>
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if models !== null}
|
||||
{#if (models ?? []).length !== 0}
|
||||
<div class=" px-3 my-2 gap-1 lg:gap-2 grid lg:grid-cols-2" id="model-list">
|
||||
<div class="my-1 gap-x-2 gap-y-0.5 grid lg:grid-cols-2" id="model-list">
|
||||
{#each models as model (model.id)}
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
class="flex transition rounded-2xl w-full p-2.5 {model.write_access
|
||||
? 'cursor-pointer dark:hover:bg-gray-850/50 hover:bg-gray-50'
|
||||
: 'dark:hover:bg-gray-850/50 hover:bg-gray-50'}"
|
||||
class="flex transition w-full px-2.5 py-1.5 rounded-2xl {model.write_access
|
||||
? 'cursor-pointer hover:bg-gray-50/70 dark:hover:bg-gray-850/50'
|
||||
: ''}"
|
||||
id="model-item-{model.id}"
|
||||
on:click={() => {
|
||||
if (model.write_access) {
|
||||
@@ -849,30 +849,11 @@
|
||||
</div>
|
||||
|
||||
{#if $config?.features.enable_community_sharing}
|
||||
<div class=" my-16">
|
||||
<div class=" text-xl font-medium mb-1 line-clamp-1">
|
||||
{$i18n.t('Made by Open WebUI Community')}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class=" flex cursor-pointer items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-850 w-full mb-2 px-3.5 py-1.5 rounded-xl transition"
|
||||
href="https://openwebui.com/models"
|
||||
target="_blank"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<div class=" font-medium line-clamp-1">{$i18n.t('Discover a model')}</div>
|
||||
<div class=" text-sm line-clamp-1">
|
||||
{$i18n.t('Discover, download, and explore model presets')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<CommunityDiscover
|
||||
href="https://openwebui.com/models"
|
||||
title={$i18n.t('Discover a model')}
|
||||
description={$i18n.t('Discover, download, and explore model presets')}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="h-[1.6875rem] px-2 rounded-xl w-full text-left flex justify-between items-center text-[13px] hover:bg-gray-50/60 hover:dark:bg-gray-800/60 hover:dark:text-gray-100 selected-command-option-button"
|
||||
class="h-[1.6875rem] px-2 rounded-xl w-full text-left flex justify-between items-center text-[13px] bg-transparent hover:text-gray-900 dark:hover:text-gray-100 selected-command-option-button"
|
||||
>
|
||||
<button
|
||||
class="w-full flex-1"
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
{#if writeAccess}
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
editHandler();
|
||||
}}
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
{#if writeAccess}
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
hideHandler();
|
||||
}}
|
||||
@@ -127,7 +127,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
pinModelHandler(model?.id);
|
||||
}}
|
||||
@@ -149,7 +149,7 @@
|
||||
|
||||
{#if writeAccess}
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
cloneHandler();
|
||||
}}
|
||||
@@ -165,7 +165,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
copyLinkHandler();
|
||||
}}
|
||||
@@ -177,7 +177,7 @@
|
||||
|
||||
{#if writeAccess && ($currentUser?.role === 'admin' || $currentUser?.permissions?.workspace?.models_export)}
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
exportHandler();
|
||||
}}
|
||||
@@ -190,7 +190,7 @@
|
||||
|
||||
{#if writeAccess && $config?.features.enable_community_sharing}
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
shareHandler();
|
||||
}}
|
||||
@@ -204,7 +204,7 @@
|
||||
<hr class="border-gray-50/30 dark:border-gray-800/30 my-1" />
|
||||
|
||||
<button
|
||||
class="select-none flex gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl w-full"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
}}
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
import Search from '../icons/Search.svelte';
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import GarbageBin from '../icons/GarbageBin.svelte';
|
||||
import ViewSelector from './common/ViewSelector.svelte';
|
||||
import TagSelector from './common/TagSelector.svelte';
|
||||
import CommunityDiscover from './common/CommunityDiscover.svelte';
|
||||
import Badge from '$lib/components/common/Badge.svelte';
|
||||
import Switch from '../common/Switch.svelte';
|
||||
import Pagination from '../common/Pagination.svelte';
|
||||
@@ -231,7 +231,7 @@
|
||||
</div>
|
||||
</DeleteConfirmDialog>
|
||||
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<input
|
||||
id="prompts-import-input"
|
||||
bind:this={promptsImportInputElement}
|
||||
@@ -323,11 +323,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class=" flex w-full space-x-2 py-0.5 px-3.5 pb-2">
|
||||
<div class="flex flex-1">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 w-full items-center gap-2">
|
||||
<div class="flex min-w-0 flex-1">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -354,36 +352,38 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none -mx-1"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-1.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
page = 1;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if (tags ?? []).length > 0}
|
||||
<TagSelector
|
||||
bind:value={selectedTag}
|
||||
items={tags.map((tag) => ({ value: tag, label: tag }))}
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
page = 1;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if (tags ?? []).length > 0}
|
||||
<TagSelector
|
||||
bind:value={selectedTag}
|
||||
align="end"
|
||||
items={tags.map((tag) => ({ value: tag, label: tag }))}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -393,10 +393,10 @@
|
||||
</div>
|
||||
{:else if (prompts ?? []).length !== 0}
|
||||
<!-- Before they call, I will answer; while they are yet speaking, I will hear. -->
|
||||
<div class="gap-2 grid my-2 px-3 lg:grid-cols-2">
|
||||
<div class="gap-x-2 gap-y-0.5 grid my-1 lg:grid-cols-2">
|
||||
{#each prompts as prompt (prompt.id)}
|
||||
<a
|
||||
class=" flex space-x-4 cursor-pointer text-left w-full px-3 py-2.5 dark:hover:bg-gray-850/50 hover:bg-gray-50 transition rounded-2xl"
|
||||
class="flex space-x-4 cursor-pointer text-left w-full px-2.5 py-1.5 transition rounded-2xl hover:bg-gray-50/70 dark:hover:bg-gray-850/50"
|
||||
href={`/workspace/prompts/${prompt.id}`}
|
||||
>
|
||||
<div class=" flex flex-col flex-1 space-x-4 cursor-pointer w-full pl-1">
|
||||
@@ -535,30 +535,11 @@
|
||||
</div>
|
||||
|
||||
{#if $config?.features.enable_community_sharing}
|
||||
<div class=" my-16">
|
||||
<div class=" text-xl font-medium mb-1 line-clamp-1">
|
||||
{$i18n.t('Made by Open WebUI Community')}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class=" flex cursor-pointer items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-850 w-full mb-2 px-3.5 py-1.5 rounded-xl transition"
|
||||
href="https://openwebui.com/prompts"
|
||||
target="_blank"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<div class=" font-medium line-clamp-1">{$i18n.t('Discover a prompt')}</div>
|
||||
<div class=" text-sm line-clamp-1">
|
||||
{$i18n.t('Discover, download, and explore custom prompts')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<CommunityDiscover
|
||||
href="https://openwebui.com/prompts"
|
||||
title={$i18n.t('Discover a prompt')}
|
||||
description={$i18n.t('Discover, download, and explore custom prompts')}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
show = false;
|
||||
showDeleteConfirmDialog = true;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
editHandler();
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
{#if $config.features.enable_community_sharing}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
shareHandler();
|
||||
@@ -75,7 +75,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
cloneHandler();
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
{#if $user?.role === 'admin' || $user?.permissions?.workspace?.prompts_export}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
exportHandler();
|
||||
@@ -101,7 +101,7 @@
|
||||
<hr class="border-gray-50 dark:border-gray-850/30 mx-1 my-0.5" />
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
</svelte:head>
|
||||
|
||||
{#if loaded}
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center md:self-center text-xl font-medium px-0.5 gap-2 shrink-0">
|
||||
<div>
|
||||
@@ -312,11 +312,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class=" flex w-full space-x-2 py-0.5 px-3.5 pb-2">
|
||||
<div class="flex flex-1">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 w-full items-center gap-2">
|
||||
<div class="flex min-w-0 flex-1">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -342,29 +340,30 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none -mx-1"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-1.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
page = 1;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
page = 1;
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -373,12 +372,12 @@
|
||||
<Spinner className="size-5" />
|
||||
</div>
|
||||
{:else if (filteredItems ?? []).length !== 0}
|
||||
<div class=" my-2 gap-2 grid px-3 lg:grid-cols-2">
|
||||
<div class="my-1 gap-x-2 gap-y-0.5 grid lg:grid-cols-2">
|
||||
{#each filteredItems as skill}
|
||||
<Tooltip content={skill?.description ?? skill?.id}>
|
||||
<div
|
||||
class=" flex space-x-4 text-left w-full px-3 py-2.5 transition rounded-2xl {skill.write_access
|
||||
? 'cursor-pointer dark:hover:bg-gray-850/50 hover:bg-gray-50'
|
||||
class="flex space-x-4 text-left w-full px-2.5 py-1.5 transition rounded-2xl {skill.write_access
|
||||
? 'cursor-pointer hover:bg-gray-50/70 dark:hover:bg-gray-850/50'
|
||||
: 'cursor-not-allowed opacity-60'}"
|
||||
>
|
||||
{#if skill.write_access}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
editHandler();
|
||||
}}
|
||||
@@ -59,7 +59,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
cloneHandler();
|
||||
}}
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
{#if $user?.role === 'admin' || $user?.permissions?.workspace?.skills_export}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
exportHandler();
|
||||
}}
|
||||
@@ -83,7 +83,7 @@
|
||||
<hr class="border-gray-50 dark:border-gray-850/30 mx-1 my-0.5" />
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
}}
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
import GarbageBin from '../icons/GarbageBin.svelte';
|
||||
import Search from '../icons/Search.svelte';
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import AddToolMenu from './Tools/AddToolMenu.svelte';
|
||||
import ImportModal from '../ImportModal.svelte';
|
||||
import ViewSelector from './common/ViewSelector.svelte';
|
||||
import CommunityDiscover from './common/CommunityDiscover.svelte';
|
||||
import Badge from '$lib/components/common/Badge.svelte';
|
||||
|
||||
let shiftKey = false;
|
||||
@@ -220,7 +220,7 @@
|
||||
/>
|
||||
|
||||
{#if loaded}
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<input
|
||||
id="documents-import-input"
|
||||
bind:this={toolsImportInputElement}
|
||||
@@ -313,12 +313,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
<!-- The iron remembers its forge. -->
|
||||
<div class=" flex w-full space-x-2 py-0.5 px-3.5 pb-2">
|
||||
<div class="flex flex-1">
|
||||
<div class="flex h-8 w-full items-center gap-2">
|
||||
<div class="flex min-w-0 flex-1">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -344,39 +342,40 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none -mx-1"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-1.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
bind:this={tagsContainerElement}
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<ViewSelector
|
||||
bind:value={viewOption}
|
||||
align="end"
|
||||
onChange={async (value) => {
|
||||
localStorage.workspaceViewOption = value;
|
||||
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
await tick();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if (filteredItems ?? []).length !== 0}
|
||||
<div class=" my-2 gap-2 grid px-3 lg:grid-cols-2">
|
||||
<div class="my-1 gap-x-2 gap-y-0.5 grid lg:grid-cols-2">
|
||||
{#each filteredItems as tool}
|
||||
<Tooltip content={tool?.meta?.description ?? tool?.id}>
|
||||
<div
|
||||
class=" flex space-x-4 text-left w-full px-3 py-2.5 transition rounded-2xl {tool.write_access
|
||||
? 'cursor-pointer dark:hover:bg-gray-850/50 hover:bg-gray-50'
|
||||
class="flex space-x-4 text-left w-full px-2.5 py-1.5 transition rounded-2xl {tool.write_access
|
||||
? 'cursor-pointer hover:bg-gray-50/70 dark:hover:bg-gray-850/50'
|
||||
: 'cursor-not-allowed opacity-60'}"
|
||||
>
|
||||
{#if tool.write_access}
|
||||
@@ -565,30 +564,11 @@
|
||||
</div>
|
||||
|
||||
{#if $config?.features.enable_community_sharing}
|
||||
<div class=" my-16">
|
||||
<div class=" text-xl font-medium mb-1 line-clamp-1">
|
||||
{$i18n.t('Made by Open WebUI Community')}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class=" flex cursor-pointer items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-850 w-full mb-2 px-3.5 py-1.5 rounded-xl transition"
|
||||
href="https://openwebui.com/tools"
|
||||
target="_blank"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<div class=" font-medium line-clamp-1">{$i18n.t('Discover a tool')}</div>
|
||||
<div class=" text-sm line-clamp-1">
|
||||
{$i18n.t('Discover, download, and explore custom tools')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<CommunityDiscover
|
||||
href="https://openwebui.com/tools"
|
||||
title={$i18n.t('Discover a tool')}
|
||||
description={$i18n.t('Discover, download, and explore custom tools')}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<DeleteConfirmDialog
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[190px]">
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={async () => {
|
||||
createHandler();
|
||||
show = false;
|
||||
@@ -46,7 +46,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={async () => {
|
||||
importFromLinkHandler();
|
||||
show = false;
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[170px]">
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
editHandler();
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
{#if $config.features.enable_community_sharing}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
shareHandler();
|
||||
@@ -76,7 +76,7 @@
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
cloneHandler();
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
{#if $user?.role === 'admin' || $user?.permissions?.workspace?.tools_export}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
exportHandler();
|
||||
@@ -104,7 +104,7 @@
|
||||
<hr class="border-gray-50 dark:border-gray-850/30 mx-1 my-0.5" />
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
draggable="false"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import ChevronRight from '$lib/components/icons/ChevronRight.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let href = '';
|
||||
export let title = '';
|
||||
export let description = '';
|
||||
</script>
|
||||
|
||||
<div class="mt-6 px-2">
|
||||
<div class="mb-0.5 text-[11px] font-normal text-gray-400 dark:text-gray-600">
|
||||
{$i18n.t('Made by Open WebUI Community')}
|
||||
</div>
|
||||
|
||||
<a
|
||||
class="flex w-full cursor-pointer items-center justify-between gap-3 px-0 py-1 text-left transition"
|
||||
{href}
|
||||
target="_blank"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<div class="line-clamp-1 text-[13px] font-normal text-gray-700 dark:text-gray-200">
|
||||
{title}
|
||||
</div>
|
||||
<div class="line-clamp-1 text-xs text-gray-500 dark:text-gray-500">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ChevronRight className="size-3.5 shrink-0 text-gray-400 dark:text-gray-600" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
export let value = '';
|
||||
export let placeholder = $i18n.t('Tag');
|
||||
export let align = 'start';
|
||||
export let onChange: (value: string) => void = () => {};
|
||||
|
||||
export let items = [];
|
||||
@@ -19,13 +20,14 @@
|
||||
bind:value
|
||||
{items}
|
||||
{placeholder}
|
||||
triggerClass="relative w-full flex items-center gap-0.5 px-2.5 py-1.5 rounded-xl "
|
||||
itemClass="flex w-full gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl capitalize"
|
||||
{align}
|
||||
triggerClass="relative h-8 w-full flex items-center gap-0.5 px-1.5 py-1.5 bg-transparent rounded-xl text-[13px] font-normal text-gray-700 transition hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100"
|
||||
itemClass="flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] capitalize hover:text-gray-900 dark:hover:text-gray-100"
|
||||
onChange={() => onChange(value)}
|
||||
>
|
||||
<svelte:fragment slot="trigger" let:selectedLabel>
|
||||
<div
|
||||
class="inline-flex h-input px-0.5 w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden capitalize"
|
||||
class="inline-flex h-input w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden capitalize"
|
||||
>
|
||||
{#if value}
|
||||
{value}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
export let value = '';
|
||||
export let placeholder = $i18n.t('Select view');
|
||||
export let align = 'start';
|
||||
export let onChange: (value: string) => void = () => {};
|
||||
|
||||
const items = [
|
||||
@@ -22,13 +23,14 @@
|
||||
bind:value
|
||||
{items}
|
||||
{placeholder}
|
||||
triggerClass="relative w-full flex items-center gap-0.5 px-2.5 py-1.5 bg-gray-50 dark:bg-gray-850 rounded-xl "
|
||||
labelClass="inline-flex h-input px-0.5 w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
{align}
|
||||
triggerClass="relative h-8 w-full flex items-center gap-0.5 px-1.5 py-1.5 bg-transparent rounded-xl text-[13px] font-normal text-gray-700 transition hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100"
|
||||
labelClass="inline-flex h-input w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
onChange={() => onChange(value)}
|
||||
>
|
||||
<svelte:fragment slot="trigger" let:selectedLabel>
|
||||
<span
|
||||
class="inline-flex h-input px-0.5 w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
class="inline-flex h-input w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
>
|
||||
{selectedLabel}
|
||||
</span>
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
<div class="flex-1 max-h-full overflow-y-auto">
|
||||
{#if loaded}
|
||||
<div class="pb-1 px-3 md:px-[18px] pt-2">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-3">
|
||||
<div class="flex flex-col gap-1 px-1 mt-1.5 mb-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center md:self-center text-xl font-medium px-0.5 gap-2 shrink-0">
|
||||
{#if $mobile}
|
||||
@@ -303,11 +303,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="py-2 bg-white dark:bg-gray-900 rounded-3xl border border-gray-100/30 dark:border-gray-850/30"
|
||||
>
|
||||
<div class="px-3.5 flex flex-1 items-center w-full space-x-2 py-0.5 pb-2">
|
||||
<div class="flex flex-1 items-center">
|
||||
<div class="space-y-1">
|
||||
<div class="flex h-8 flex-1 items-center w-full gap-2">
|
||||
<div class="flex min-w-0 flex-1 items-center">
|
||||
<div class="self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
@@ -335,76 +333,83 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-3 flex w-full bg-transparent overflow-x-auto scrollbar-none -mx-1">
|
||||
<div
|
||||
class="flex gap-0.5 w-fit text-center text-sm rounded-full bg-transparent px-1.5 whitespace-nowrap"
|
||||
class="flex max-w-[55%] shrink-0 overflow-x-auto scrollbar-none"
|
||||
on:wheel={(e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.scrollLeft += e.deltaY;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
bind:value={statusFilter}
|
||||
items={[
|
||||
{ value: 'all', label: $i18n.t('All') },
|
||||
{ value: 'active', label: $i18n.t('Active') },
|
||||
{ value: 'paused', label: $i18n.t('Paused') }
|
||||
]}
|
||||
onChange={() => {
|
||||
page = 1;
|
||||
}}
|
||||
triggerClass="relative w-full flex items-center gap-0.5 px-2.5 py-1.5 bg-gray-50 dark:bg-gray-850 rounded-xl"
|
||||
<div
|
||||
class="flex w-fit gap-0.5 text-center text-sm rounded-full bg-transparent whitespace-nowrap"
|
||||
>
|
||||
<svelte:fragment slot="trigger" let:selectedLabel>
|
||||
<span
|
||||
class="inline-flex h-input px-0.5 w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
>
|
||||
{selectedLabel}
|
||||
</span>
|
||||
<ChevronDown className="size-3.5" strokeWidth="2.5" />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="item" let:item let:selected>
|
||||
{item.label}
|
||||
<div class="ml-auto {selected ? '' : 'invisible'}">
|
||||
<Check />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div class="flex-1"></div>
|
||||
|
||||
<Dropdown align="end">
|
||||
<Tooltip content={$i18n.t('Actions')}>
|
||||
<button
|
||||
class="p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition"
|
||||
type="button"
|
||||
aria-label={$i18n.t('Actions')}
|
||||
<Select
|
||||
bind:value={statusFilter}
|
||||
align="end"
|
||||
items={[
|
||||
{ value: 'all', label: $i18n.t('All') },
|
||||
{ value: 'active', label: $i18n.t('Active') },
|
||||
{ value: 'paused', label: $i18n.t('Paused') }
|
||||
]}
|
||||
onChange={() => {
|
||||
page = 1;
|
||||
}}
|
||||
triggerClass="relative h-8 w-full flex items-center gap-0.5 px-1.5 py-1.5 bg-transparent rounded-xl text-[13px] font-normal text-gray-700 transition hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100"
|
||||
>
|
||||
<EllipsisHorizontal className="size-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<svelte:fragment slot="trigger" let:selectedLabel>
|
||||
<span
|
||||
class="inline-flex h-input w-full outline-hidden bg-transparent truncate placeholder-gray-400 focus:outline-hidden"
|
||||
>
|
||||
{selectedLabel}
|
||||
</span>
|
||||
<ChevronDown className="size-3.5" strokeWidth="2.5" />
|
||||
</svelte:fragment>
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu className="w-[170px] shadow-sm">
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => bulkToggleHandler(true)}
|
||||
>
|
||||
<CheckCircle className="size-4" />
|
||||
{$i18n.t('Enable All')}
|
||||
</button>
|
||||
<button
|
||||
class="select-none flex w-full gap-2 items-center px-3 py-1.5 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
type="button"
|
||||
on:click={() => bulkToggleHandler(false)}
|
||||
>
|
||||
<Minus className="size-4" />
|
||||
{$i18n.t('Disable All')}
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
<svelte:fragment slot="item" let:item let:selected>
|
||||
{item.label}
|
||||
<div class="ml-auto {selected ? '' : 'invisible'}">
|
||||
<Check />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Select>
|
||||
|
||||
<Dropdown align="end">
|
||||
<Tooltip content={$i18n.t('Actions')}>
|
||||
<button
|
||||
class="flex h-8 items-center gap-1.5 rounded-xl bg-transparent px-1.5 text-[13px] font-normal text-gray-700 transition hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
>
|
||||
<span>{$i18n.t('Actions')}</span>
|
||||
<ChevronDown className="size-3" strokeWidth="2.5" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu className="w-[170px] shadow-sm">
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => bulkToggleHandler(true)}
|
||||
>
|
||||
<CheckCircle className="size-3.5" />
|
||||
{$i18n.t('Enable All')}
|
||||
</button>
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[13px] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
type="button"
|
||||
on:click={() => bulkToggleHandler(false)}
|
||||
>
|
||||
<Minus className="size-3.5" />
|
||||
{$i18n.t('Disable All')}
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if automations === null || loading}
|
||||
@@ -430,10 +435,10 @@
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="gap-2 grid my-2 px-3">
|
||||
<div class="gap-y-0.5 grid my-1">
|
||||
{#each automations as automation (automation.id)}
|
||||
<a
|
||||
class="flex space-x-4 text-left w-full px-3 py-2.5 dark:hover:bg-gray-850/50 hover:bg-gray-50 transition rounded-2xl"
|
||||
class="flex space-x-4 text-left w-full px-3 py-2 bg-transparent hover:bg-gray-50/70 dark:hover:bg-gray-850/50 transition rounded-2xl"
|
||||
href={`/automations/${automation.id}`}
|
||||
>
|
||||
<div class="flex-1">
|
||||
@@ -460,7 +465,7 @@
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="self-center w-fit text-sm p-1.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||
class="self-center w-fit text-sm p-1.5 text-gray-500 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100 rounded-xl"
|
||||
type="button"
|
||||
>
|
||||
<EllipsisHorizontal className="size-5" />
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
<script>
|
||||
import { getContext, onMount } from 'svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import dayjs from '$lib/dayjs';
|
||||
import { mobile, showArchivedChats, showSidebar, user } from '$lib/stores';
|
||||
import { showSidebar } from '$lib/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
import { createNoteHandler } from '$lib/components/notes/utils';
|
||||
|
||||
import UserMenu from '$lib/components/layout/Sidebar/UserMenu.svelte';
|
||||
import Notes from '$lib/components/notes/Notes.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import Sidebar from '$lib/components/icons/Sidebar.svelte';
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
|
||||
let loaded = false;
|
||||
|
||||
@@ -38,80 +33,20 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<div
|
||||
class=" flex flex-col w-full h-screen max-h-[100dvh] transition-width duration-200 ease-in-out {$showSidebar
|
||||
? 'md:max-w-[calc(100%-var(--sidebar-width))]'
|
||||
: ''} max-w-full"
|
||||
>
|
||||
<nav class=" px-2 pt-1.5 backdrop-blur-xl w-full drag-region">
|
||||
<div class=" flex items-center">
|
||||
{#if $mobile}
|
||||
<div class="{$showSidebar ? 'md:hidden' : ''} flex flex-none items-center">
|
||||
<Tooltip
|
||||
content={$showSidebar ? $i18n.t('Close Sidebar') : $i18n.t('Open Sidebar')}
|
||||
interactive={true}
|
||||
>
|
||||
<button
|
||||
id="sidebar-toggle-button"
|
||||
class=" cursor-pointer flex rounded-lg hover:bg-gray-100 dark:hover:bg-gray-850 transition cursor-"
|
||||
on:click={() => {
|
||||
showSidebar.set(!$showSidebar);
|
||||
}}
|
||||
>
|
||||
<div class=" self-center p-1.5">
|
||||
<Sidebar />
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="ml-2 py-0.5 self-center flex items-center justify-between w-full">
|
||||
<div class="">
|
||||
<div
|
||||
class="flex gap-1 scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium bg-transparent py-1 touch-auto pointer-events-auto"
|
||||
>
|
||||
<a class="min-w-fit transition" href="/notes">
|
||||
{$i18n.t('Notes')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" self-center flex items-center gap-1">
|
||||
{#if $user !== undefined && $user !== null}
|
||||
<UserMenu
|
||||
className="w-[240px]"
|
||||
role={$user?.role}
|
||||
help={true}
|
||||
on:show={(e) => {
|
||||
if (e.detail === 'archived-chat') {
|
||||
showArchivedChats.set(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="select-none flex rounded-xl p-1.5 w-full hover:bg-gray-50 dark:hover:bg-gray-850 transition"
|
||||
aria-label="User Menu"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/users/${$user?.id}/profile/image`}
|
||||
class="size-6 object-cover rounded-full"
|
||||
alt="User profile"
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</UserMenu>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col w-full h-screen max-h-[100dvh] transition-width duration-200 ease-in-out {$showSidebar
|
||||
? 'md:max-w-[calc(100%-var(--sidebar-width))]'
|
||||
: ''} max-w-full"
|
||||
>
|
||||
<div class="flex-1 max-h-full overflow-y-auto">
|
||||
{#if loaded}
|
||||
<div class="pb-1 px-3 md:px-[18px] pt-2">
|
||||
<Notes />
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class=" flex-1 max-h-full overflow-y-auto @container">
|
||||
<Notes />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<Spinner className="size-5" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user