mirror of
https://github.com/open-webui/open-webui
synced 2025-03-06 12:32:58 +00:00
enh: files chat control
This commit is contained in:
parent
a33b0abbe0
commit
4eecdbadd3
@ -98,6 +98,8 @@
|
|||||||
|
|
||||||
let title = '';
|
let title = '';
|
||||||
let prompt = '';
|
let prompt = '';
|
||||||
|
|
||||||
|
let chatFiles = [];
|
||||||
let files = [];
|
let files = [];
|
||||||
let messages = [];
|
let messages = [];
|
||||||
let history = {
|
let history = {
|
||||||
@ -333,6 +335,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
params = chatContent?.params ?? {};
|
params = chatContent?.params ?? {};
|
||||||
|
chatFiles = chatContent?.files ?? {};
|
||||||
|
|
||||||
autoScroll = true;
|
autoScroll = true;
|
||||||
await tick();
|
await tick();
|
||||||
@ -408,7 +411,8 @@
|
|||||||
models: selectedModels,
|
models: selectedModels,
|
||||||
messages: messages,
|
messages: messages,
|
||||||
history: history,
|
history: history,
|
||||||
params: params
|
params: params,
|
||||||
|
files: chatFiles
|
||||||
});
|
});
|
||||||
await chats.set(await getChatList(localStorage.token));
|
await chats.set(await getChatList(localStorage.token));
|
||||||
}
|
}
|
||||||
@ -453,7 +457,8 @@
|
|||||||
models: selectedModels,
|
models: selectedModels,
|
||||||
messages: messages,
|
messages: messages,
|
||||||
history: history,
|
history: history,
|
||||||
params: params
|
params: params,
|
||||||
|
files: chatFiles
|
||||||
});
|
});
|
||||||
await chats.set(await getChatList(localStorage.token));
|
await chats.set(await getChatList(localStorage.token));
|
||||||
}
|
}
|
||||||
@ -514,6 +519,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _files = JSON.parse(JSON.stringify(files));
|
const _files = JSON.parse(JSON.stringify(files));
|
||||||
|
chatFiles.push(..._files.filter((item) => ['doc', 'file', 'collection'].includes(item.type)));
|
||||||
|
chatFiles = chatFiles.filter(
|
||||||
|
// Remove duplicates
|
||||||
|
(item, index, array) =>
|
||||||
|
array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index
|
||||||
|
);
|
||||||
|
|
||||||
files = [];
|
files = [];
|
||||||
|
|
||||||
prompt = '';
|
prompt = '';
|
||||||
@ -754,25 +766,10 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let files = [];
|
let files = JSON.parse(JSON.stringify(chatFiles));
|
||||||
if (model?.info?.meta?.knowledge ?? false) {
|
if (model?.info?.meta?.knowledge ?? false) {
|
||||||
files = model.info.meta.knowledge;
|
files.push(...model.info.meta.knowledge);
|
||||||
}
|
}
|
||||||
const lastUserMessage = messages.filter((message) => message.role === 'user').at(-1);
|
|
||||||
|
|
||||||
files = [
|
|
||||||
...files,
|
|
||||||
...(lastUserMessage?.files?.filter((item) =>
|
|
||||||
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
|
|
||||||
) ?? []),
|
|
||||||
...(responseMessage?.files?.filter((item) =>
|
|
||||||
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
|
|
||||||
) ?? [])
|
|
||||||
].filter(
|
|
||||||
// Remove duplicates
|
|
||||||
(item, index, array) =>
|
|
||||||
array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index
|
|
||||||
);
|
|
||||||
|
|
||||||
eventTarget.dispatchEvent(
|
eventTarget.dispatchEvent(
|
||||||
new CustomEvent('chat:start', {
|
new CustomEvent('chat:start', {
|
||||||
@ -936,7 +933,8 @@
|
|||||||
messages: messages,
|
messages: messages,
|
||||||
history: history,
|
history: history,
|
||||||
models: selectedModels,
|
models: selectedModels,
|
||||||
params: params
|
params: params,
|
||||||
|
files: chatFiles
|
||||||
});
|
});
|
||||||
await chats.set(await getChatList(localStorage.token));
|
await chats.set(await getChatList(localStorage.token));
|
||||||
}
|
}
|
||||||
@ -1003,24 +1001,10 @@
|
|||||||
let _response = null;
|
let _response = null;
|
||||||
const responseMessage = history.messages[responseMessageId];
|
const responseMessage = history.messages[responseMessageId];
|
||||||
|
|
||||||
let files = [];
|
let files = JSON.parse(JSON.stringify(chatFiles));
|
||||||
if (model?.info?.meta?.knowledge ?? false) {
|
if (model?.info?.meta?.knowledge ?? false) {
|
||||||
files = model.info.meta.knowledge;
|
files.push(...model.info.meta.knowledge);
|
||||||
}
|
}
|
||||||
const lastUserMessage = messages.filter((message) => message.role === 'user').at(-1);
|
|
||||||
files = [
|
|
||||||
...files,
|
|
||||||
...(lastUserMessage?.files?.filter((item) =>
|
|
||||||
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
|
|
||||||
) ?? []),
|
|
||||||
...(responseMessage?.files?.filter((item) =>
|
|
||||||
['doc', 'file', 'collection', 'web_search_results'].includes(item.type)
|
|
||||||
) ?? [])
|
|
||||||
].filter(
|
|
||||||
// Remove duplicates
|
|
||||||
(item, index, array) =>
|
|
||||||
array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index
|
|
||||||
);
|
|
||||||
|
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
|
|
||||||
@ -1214,7 +1198,8 @@
|
|||||||
models: selectedModels,
|
models: selectedModels,
|
||||||
messages: messages,
|
messages: messages,
|
||||||
history: history,
|
history: history,
|
||||||
params: params
|
params: params,
|
||||||
|
files: chatFiles
|
||||||
});
|
});
|
||||||
await chats.set(await getChatList(localStorage.token));
|
await chats.set(await getChatList(localStorage.token));
|
||||||
}
|
}
|
||||||
@ -1632,6 +1617,7 @@
|
|||||||
return a;
|
return a;
|
||||||
}, [])}
|
}, [])}
|
||||||
bind:show={showControls}
|
bind:show={showControls}
|
||||||
|
bind:chatFiles
|
||||||
bind:params
|
bind:params
|
||||||
bind:valves
|
bind:valves
|
||||||
/>
|
/>
|
||||||
|
@ -9,8 +9,9 @@
|
|||||||
export let models = [];
|
export let models = [];
|
||||||
|
|
||||||
export let chatId = null;
|
export let chatId = null;
|
||||||
export let valves = {};
|
|
||||||
|
|
||||||
|
export let chatFiles = [];
|
||||||
|
export let valves = {};
|
||||||
export let params = {};
|
export let params = {};
|
||||||
|
|
||||||
let largeScreen = false;
|
let largeScreen = false;
|
||||||
@ -48,6 +49,7 @@
|
|||||||
show = false;
|
show = false;
|
||||||
}}
|
}}
|
||||||
{models}
|
{models}
|
||||||
|
bind:chatFiles
|
||||||
bind:valves
|
bind:valves
|
||||||
bind:params
|
bind:params
|
||||||
/>
|
/>
|
||||||
@ -63,6 +65,7 @@
|
|||||||
show = false;
|
show = false;
|
||||||
}}
|
}}
|
||||||
{models}
|
{models}
|
||||||
|
bind:chatFiles
|
||||||
bind:valves
|
bind:valves
|
||||||
bind:params
|
bind:params
|
||||||
/>
|
/>
|
||||||
|
@ -6,8 +6,11 @@
|
|||||||
import XMark from '$lib/components/icons/XMark.svelte';
|
import XMark from '$lib/components/icons/XMark.svelte';
|
||||||
import AdvancedParams from '../Settings/Advanced/AdvancedParams.svelte';
|
import AdvancedParams from '../Settings/Advanced/AdvancedParams.svelte';
|
||||||
import Valves from '$lib/components/common/Valves.svelte';
|
import Valves from '$lib/components/common/Valves.svelte';
|
||||||
|
import FileItem from '$lib/components/common/FileItem.svelte';
|
||||||
|
|
||||||
export let models = [];
|
export let models = [];
|
||||||
|
|
||||||
|
export let chatFiles = [];
|
||||||
export let valves = {};
|
export let valves = {};
|
||||||
export let params = {};
|
export let params = {};
|
||||||
</script>
|
</script>
|
||||||
@ -26,9 +29,33 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" dark:text-gray-200 text-sm font-primary">
|
<div class=" dark:text-gray-200 text-sm font-primary">
|
||||||
|
{#if chatFiles.length > 0}
|
||||||
|
<div>
|
||||||
|
<div class="mb-1.5 font-medium">{$i18n.t('Files')}</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{#each chatFiles as file}
|
||||||
|
<FileItem
|
||||||
|
className="w-full"
|
||||||
|
url={`${file?.url}`}
|
||||||
|
name={file.name}
|
||||||
|
type={file.type}
|
||||||
|
dismissible={true}
|
||||||
|
on:dismiss={() => {
|
||||||
|
// Remove the file from the chatFiles array
|
||||||
|
chatFiles = chatFiles.filter((f) => f.id !== file.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-2 border-gray-100 dark:border-gray-800" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if models.length === 1 && models[0]?.pipe?.valves_spec}
|
{#if models.length === 1 && models[0]?.pipe?.valves_spec}
|
||||||
<div>
|
<div>
|
||||||
<div class=" font-medium">Valves</div>
|
<div class=" font-medium">{$i18n.t('Valves')}</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Valves valvesSpec={models[0]?.pipe?.valves_spec} bind:valves />
|
<Valves valvesSpec={models[0]?.pipe?.valves_spec} bind:valves />
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
import Headphone from '../icons/Headphone.svelte';
|
import Headphone from '../icons/Headphone.svelte';
|
||||||
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
||||||
import { transcribeAudio } from '$lib/apis/audio';
|
import { transcribeAudio } from '$lib/apis/audio';
|
||||||
|
import FileItem from '../common/FileItem.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -502,8 +503,8 @@
|
|||||||
{#if files.length > 0}
|
{#if files.length > 0}
|
||||||
<div class="mx-2 mt-2 mb-1 flex flex-wrap gap-2">
|
<div class="mx-2 mt-2 mb-1 flex flex-wrap gap-2">
|
||||||
{#each files as file, fileIdx}
|
{#each files as file, fileIdx}
|
||||||
<div class=" relative group">
|
{#if file.type === 'image'}
|
||||||
{#if file.type === 'image'}
|
<div class=" relative group">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img
|
<img
|
||||||
src={file.url}
|
src={file.url}
|
||||||
@ -534,137 +535,39 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if ['doc', 'file'].includes(file.type)}
|
<div class=" absolute -top-1 -right-1">
|
||||||
<div
|
<button
|
||||||
class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-none"
|
class=" bg-gray-400 text-white border border-white rounded-full group-hover:visible invisible transition"
|
||||||
>
|
type="button"
|
||||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
on:click={() => {
|
||||||
{#if file.status === 'processed'}
|
files.splice(fileIdx, 1);
|
||||||
<svg
|
files = files;
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
}}
|
||||||
viewBox="0 0 24 24"
|
>
|
||||||
fill="currentColor"
|
|
||||||
class="w-6 h-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{:else}
|
|
||||||
<svg
|
|
||||||
class=" w-6 h-6 translate-y-[0.5px]"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
><style>
|
|
||||||
.spinner_qM83 {
|
|
||||||
animation: spinner_8HQG 1.05s infinite;
|
|
||||||
}
|
|
||||||
.spinner_oXPr {
|
|
||||||
animation-delay: 0.1s;
|
|
||||||
}
|
|
||||||
.spinner_ZTLf {
|
|
||||||
animation-delay: 0.2s;
|
|
||||||
}
|
|
||||||
@keyframes spinner_8HQG {
|
|
||||||
0%,
|
|
||||||
57.14% {
|
|
||||||
animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
|
|
||||||
transform: translate(0);
|
|
||||||
}
|
|
||||||
28.57% {
|
|
||||||
animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
|
|
||||||
transform: translateY(-6px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translate(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style><circle
|
|
||||||
class="spinner_qM83"
|
|
||||||
cx="4"
|
|
||||||
cy="12"
|
|
||||||
r="2.5"
|
|
||||||
/><circle
|
|
||||||
class="spinner_qM83 spinner_oXPr"
|
|
||||||
cx="12"
|
|
||||||
cy="12"
|
|
||||||
r="2.5"
|
|
||||||
/><circle
|
|
||||||
class="spinner_qM83 spinner_ZTLf"
|
|
||||||
cx="20"
|
|
||||||
cy="12"
|
|
||||||
r="2.5"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-center -space-y-0.5">
|
|
||||||
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
|
||||||
{file.name}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if file.type === 'collection'}
|
|
||||||
<div
|
|
||||||
class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-none"
|
|
||||||
>
|
|
||||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 20 20"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="w-6 h-6"
|
class="w-4 h-4"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
|
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
|
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<div class="flex flex-col justify-center -space-y-0.5">
|
|
||||||
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
|
||||||
{file?.title ?? `#${file.name}`}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class=" absolute -top-1 -right-1">
|
|
||||||
<button
|
|
||||||
class=" bg-gray-400 text-white border border-white rounded-full group-hover:visible invisible transition"
|
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
files.splice(fileIdx, 1);
|
|
||||||
files = files;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{:else}
|
||||||
|
<FileItem
|
||||||
|
name={file.name}
|
||||||
|
type={file.type}
|
||||||
|
dismissible={true}
|
||||||
|
on:dismiss={() => {
|
||||||
|
files.splice(fileIdx, 1);
|
||||||
|
files = files;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
import { user as _user } from '$lib/stores';
|
import { user as _user } from '$lib/stores';
|
||||||
import { getFileContentById } from '$lib/apis/files';
|
import { getFileContentById } from '$lib/apis/files';
|
||||||
|
import FileItem from '$lib/components/common/FileItem.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -99,106 +100,11 @@
|
|||||||
{#if file.type === 'image'}
|
{#if file.type === 'image'}
|
||||||
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
|
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
|
||||||
{:else if file.type === 'file'}
|
{:else if file.type === 'file'}
|
||||||
<button
|
<FileItem url={`${file?.url}/content`} name={file.name} type={$i18n.t('File')} />
|
||||||
class="h-16 w-72 flex items-center space-x-3 px-2.5 dark:bg-gray-850 rounded-xl border border-gray-200 dark:border-none text-left"
|
|
||||||
type="button"
|
|
||||||
on:click={async () => {
|
|
||||||
if (file?.url) {
|
|
||||||
window.open(`${file?.url}/content`, '_blank').focus();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-6 h-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-center -space-y-0.5">
|
|
||||||
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
|
||||||
{file.name}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-gray-500 text-sm">{$i18n.t('File')}</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{:else if file.type === 'doc'}
|
{:else if file.type === 'doc'}
|
||||||
<button
|
<FileItem url={`${file?.url}`} name={file.name} type={$i18n.t('Document')} />
|
||||||
class="h-16 w-72 flex items-center space-x-3 px-2.5 dark:bg-gray-850 rounded-xl border border-gray-200 dark:border-none text-left"
|
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
if (file?.url) {
|
|
||||||
window.open(file?.url, '_blank').focus();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-6 h-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-center -space-y-0.5">
|
|
||||||
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
|
||||||
{file.name}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{:else if file.type === 'collection'}
|
{:else if file.type === 'collection'}
|
||||||
<button
|
<FileItem name={file?.title ?? `#${file.name}`} type={$i18n.t('Collection')} />
|
||||||
class="h-16 w-72 flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none text-left"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-6 h-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-center -space-y-0.5">
|
|
||||||
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
|
||||||
{file?.title ?? `#${file.name}`}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
130
src/lib/components/common/FileItem.svelte
Normal file
130
src/lib/components/common/FileItem.svelte
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, getContext } from 'svelte';
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let className = 'w-72';
|
||||||
|
export let url: string | null = null;
|
||||||
|
|
||||||
|
export let dismissible = false;
|
||||||
|
|
||||||
|
export let status = 'processed';
|
||||||
|
|
||||||
|
export let name: string;
|
||||||
|
export let type: string;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="relative group">
|
||||||
|
<button
|
||||||
|
class="h-14 {className} flex items-center space-x-3 bg-white dark:bg-gray-800 rounded-xl border border-gray-100 dark:border-gray-800 text-left"
|
||||||
|
type="button"
|
||||||
|
on:click={async () => {
|
||||||
|
if (url) {
|
||||||
|
if (type === 'file') {
|
||||||
|
window.open(`${url}/content`, '_blank').focus();
|
||||||
|
} else {
|
||||||
|
window.open(`${url}`, '_blank').focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="p-4 py-[1.1rem] bg-red-400 text-white rounded-l-lg">
|
||||||
|
{#if status === 'processed'}
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
class=" size-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<svg
|
||||||
|
class=" size-5 translate-y-[0.5px]"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
><style>
|
||||||
|
.spinner_qM83 {
|
||||||
|
animation: spinner_8HQG 1.05s infinite;
|
||||||
|
}
|
||||||
|
.spinner_oXPr {
|
||||||
|
animation-delay: 0.1s;
|
||||||
|
}
|
||||||
|
.spinner_ZTLf {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
@keyframes spinner_8HQG {
|
||||||
|
0%,
|
||||||
|
57.14% {
|
||||||
|
animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
|
||||||
|
transform: translate(0);
|
||||||
|
}
|
||||||
|
28.57% {
|
||||||
|
animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
|
||||||
|
transform: translateY(-6px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style><circle class="spinner_qM83" cx="4" cy="12" r="2.5" /><circle
|
||||||
|
class="spinner_qM83 spinner_oXPr"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="2.5"
|
||||||
|
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="2.5" /></svg
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-center -space-y-0.5 pl-1.5 pr-4 w-full">
|
||||||
|
<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" text-gray-500 text-xs">
|
||||||
|
{#if type === 'file'}
|
||||||
|
{$i18n.t('File')}
|
||||||
|
{:else if type === 'doc'}
|
||||||
|
{$i18n.t('Document')}
|
||||||
|
{:else if type === 'collection'}
|
||||||
|
{$i18n.t('Collection')}
|
||||||
|
{:else}
|
||||||
|
<span class=" capitalize">{type}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if dismissible}
|
||||||
|
<div class=" absolute -top-1 -right-1">
|
||||||
|
<button
|
||||||
|
class=" bg-gray-400 text-white border border-white rounded-full group-hover:visible invisible transition"
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
dispatch('dismiss');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Block a user