forked from open-webui/open-webui
		
	refac: styling
This commit is contained in:
		
							parent
							
								
									db08ad964c
								
							
						
					
					
						commit
						e99d69bfe2
					
				
					 8 changed files with 163 additions and 132 deletions
				
			
		| 
						 | 
				
			
			@ -55,6 +55,11 @@
 | 
			
		|||
	let isRecording = false;
 | 
			
		||||
	const MIN_DECIBELS = -45;
 | 
			
		||||
 | 
			
		||||
	const scrollToBottom = () => {
 | 
			
		||||
		const element = document.getElementById('messages-container');
 | 
			
		||||
		element.scrollTop = element.scrollHeight;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const startRecording = async () => {
 | 
			
		||||
		const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
 | 
			
		||||
		mediaRecorder = new MediaRecorder(stream);
 | 
			
		||||
| 
						 | 
				
			
			@ -371,17 +376,17 @@
 | 
			
		|||
	</div>
 | 
			
		||||
{/if}
 | 
			
		||||
 | 
			
		||||
<div class="w-full pt-2 md:pt-0">
 | 
			
		||||
	<div class="px-2.5 pt-2.5 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
 | 
			
		||||
<div class="w-full">
 | 
			
		||||
	<div class="px-2.5 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
 | 
			
		||||
		<div class="flex flex-col max-w-3xl w-full">
 | 
			
		||||
			<div>
 | 
			
		||||
			<div class="relative">
 | 
			
		||||
				{#if autoScroll === false && messages.length > 0}
 | 
			
		||||
					<div class=" flex justify-center mb-4">
 | 
			
		||||
					<div class=" absolute -top-12 left-0 right-0 flex justify-center">
 | 
			
		||||
						<button
 | 
			
		||||
							class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
 | 
			
		||||
							on:click={() => {
 | 
			
		||||
								autoScroll = true;
 | 
			
		||||
								window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
 | 
			
		||||
								scrollToBottom();
 | 
			
		||||
							}}
 | 
			
		||||
						>
 | 
			
		||||
							<svg
 | 
			
		||||
| 
						 | 
				
			
			@ -401,7 +406,7 @@
 | 
			
		|||
				{/if}
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="w-full">
 | 
			
		||||
			<div class="w-full relative">
 | 
			
		||||
				{#if prompt.charAt(0) === '/'}
 | 
			
		||||
					<Prompts bind:this={promptsElement} bind:prompt />
 | 
			
		||||
				{:else if prompt.charAt(0) === '#'}
 | 
			
		||||
| 
						 | 
				
			
			@ -432,14 +437,16 @@
 | 
			
		|||
						bind:chatInputPlaceholder
 | 
			
		||||
						{messages}
 | 
			
		||||
					/>
 | 
			
		||||
				{:else if messages.length == 0 && suggestionPrompts.length !== 0}
 | 
			
		||||
				{/if}
 | 
			
		||||
 | 
			
		||||
				{#if messages.length == 0 && suggestionPrompts.length !== 0}
 | 
			
		||||
					<Suggestions {suggestionPrompts} {submitPrompt} />
 | 
			
		||||
				{/if}
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="bg-white dark:bg-gray-900">
 | 
			
		||||
		<div class="max-w-3xl px-2.5 -mb-0.5 mx-auto inset-x-0">
 | 
			
		||||
		<div class="max-w-3xl px-2.5 mx-auto inset-x-0">
 | 
			
		||||
			<div class=" pb-2">
 | 
			
		||||
				<input
 | 
			
		||||
					bind:this={filesInputElement}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
{#if filteredItems.length > 0 || prompt.split(' ')?.at(0)?.substring(1).startsWith('http')}
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full">
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full absolute bottom-0 left-0 right-0">
 | 
			
		||||
		<div class="flex w-full rounded-lg border border-gray-100 dark:border-gray-700">
 | 
			
		||||
			<div class=" bg-gray-100 dark:bg-gray-700 w-10 rounded-l-lg text-center">
 | 
			
		||||
				<div class=" text-lg font-semibold mt-2">#</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,7 +120,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
{#if filteredModels.length > 0}
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full">
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full absolute bottom-0 left-0 right-0">
 | 
			
		||||
		<div class="flex w-full rounded-lg border border-gray-100 dark:border-gray-700">
 | 
			
		||||
			<div class=" bg-gray-100 dark:bg-gray-700 w-10 rounded-l-lg text-center">
 | 
			
		||||
				<div class=" text-lg font-semibold mt-2">@</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
{#if filteredPromptCommands.length > 0}
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full">
 | 
			
		||||
	<div class="md:px-2 mb-3 text-left w-full absolute bottom-0 left-0 right-0">
 | 
			
		||||
		<div class="flex w-full rounded-lg border border-gray-100 dark:border-gray-700">
 | 
			
		||||
			<div class=" bg-gray-100 dark:bg-gray-700 w-10 rounded-l-lg text-center">
 | 
			
		||||
				<div class=" text-lg font-semibold mt-2">/</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,10 +29,16 @@
 | 
			
		|||
	$: if (autoScroll && bottomPadding) {
 | 
			
		||||
		(async () => {
 | 
			
		||||
			await tick();
 | 
			
		||||
			window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
 | 
			
		||||
 | 
			
		||||
			scrollToBottom();
 | 
			
		||||
		})();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const scrollToBottom = () => {
 | 
			
		||||
		const element = document.getElementById('messages-container');
 | 
			
		||||
		element.scrollTop = element.scrollHeight;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const copyToClipboard = (text) => {
 | 
			
		||||
		if (!navigator.clipboard) {
 | 
			
		||||
			var textArea = document.createElement('textarea');
 | 
			
		||||
| 
						 | 
				
			
			@ -160,10 +166,11 @@
 | 
			
		|||
 | 
			
		||||
		await tick();
 | 
			
		||||
 | 
			
		||||
		autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
 | 
			
		||||
		const element = document.getElementById('messages-container');
 | 
			
		||||
		autoScroll = element.scrollHeight - element.scrollTop === element.clientHeight - 40;
 | 
			
		||||
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
 | 
			
		||||
			scrollToBottom();
 | 
			
		||||
		}, 100);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -208,9 +215,11 @@
 | 
			
		|||
 | 
			
		||||
		await tick();
 | 
			
		||||
 | 
			
		||||
		autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
 | 
			
		||||
		const element = document.getElementById('messages-container');
 | 
			
		||||
		autoScroll = element.scrollHeight - element.scrollTop === element.clientHeight - 40;
 | 
			
		||||
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
 | 
			
		||||
			scrollToBottom();
 | 
			
		||||
		}, 100);
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -218,95 +227,97 @@
 | 
			
		|||
{#if messages.length == 0}
 | 
			
		||||
	<Placeholder models={selectedModels} modelfiles={selectedModelfiles} />
 | 
			
		||||
{:else}
 | 
			
		||||
	{#key chatId}
 | 
			
		||||
		{#each messages as message, messageIdx}
 | 
			
		||||
			<div class=" w-full">
 | 
			
		||||
				<div
 | 
			
		||||
					class="flex flex-col justify-between px-5 mb-3 {$settings?.fullScreenMode ?? null
 | 
			
		||||
						? 'max-w-full'
 | 
			
		||||
						: 'max-w-3xl'} mx-auto rounded-lg group"
 | 
			
		||||
				>
 | 
			
		||||
					{#if message.role === 'user'}
 | 
			
		||||
						<UserMessage
 | 
			
		||||
							user={$user}
 | 
			
		||||
							{message}
 | 
			
		||||
							siblings={message.parentId !== null
 | 
			
		||||
								? history.messages[message.parentId]?.childrenIds ?? []
 | 
			
		||||
								: Object.values(history.messages)
 | 
			
		||||
										.filter((message) => message.parentId === null)
 | 
			
		||||
										.map((message) => message.id) ?? []}
 | 
			
		||||
							{confirmEditMessage}
 | 
			
		||||
							{showPreviousMessage}
 | 
			
		||||
							{showNextMessage}
 | 
			
		||||
							{copyToClipboard}
 | 
			
		||||
						/>
 | 
			
		||||
	<div class=" pb-10">
 | 
			
		||||
		{#key chatId}
 | 
			
		||||
			{#each messages as message, messageIdx}
 | 
			
		||||
				<div class=" w-full">
 | 
			
		||||
					<div
 | 
			
		||||
						class="flex flex-col justify-between px-5 mb-3 {$settings?.fullScreenMode ?? null
 | 
			
		||||
							? 'max-w-full'
 | 
			
		||||
							: 'max-w-3xl'} mx-auto rounded-lg group"
 | 
			
		||||
					>
 | 
			
		||||
						{#if message.role === 'user'}
 | 
			
		||||
							<UserMessage
 | 
			
		||||
								user={$user}
 | 
			
		||||
								{message}
 | 
			
		||||
								siblings={message.parentId !== null
 | 
			
		||||
									? history.messages[message.parentId]?.childrenIds ?? []
 | 
			
		||||
									: Object.values(history.messages)
 | 
			
		||||
											.filter((message) => message.parentId === null)
 | 
			
		||||
											.map((message) => message.id) ?? []}
 | 
			
		||||
								{confirmEditMessage}
 | 
			
		||||
								{showPreviousMessage}
 | 
			
		||||
								{showNextMessage}
 | 
			
		||||
								{copyToClipboard}
 | 
			
		||||
							/>
 | 
			
		||||
 | 
			
		||||
						{#if messages.length - 1 === messageIdx && processing !== ''}
 | 
			
		||||
							<div class="flex my-2.5 ml-12 items-center w-fit space-x-2.5">
 | 
			
		||||
								<div class=" dark:text-blue-100">
 | 
			
		||||
									<svg
 | 
			
		||||
										class=" w-4 h-4 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);
 | 
			
		||||
							{#if messages.length - 1 === messageIdx && processing !== ''}
 | 
			
		||||
								<div class="flex my-2.5 ml-12 items-center w-fit space-x-2.5">
 | 
			
		||||
									<div class=" dark:text-blue-100">
 | 
			
		||||
										<svg
 | 
			
		||||
											class=" w-4 h-4 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;
 | 
			
		||||
												}
 | 
			
		||||
												28.57% {
 | 
			
		||||
													animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
 | 
			
		||||
													transform: translateY(-6px);
 | 
			
		||||
												.spinner_oXPr {
 | 
			
		||||
													animation-delay: 0.1s;
 | 
			
		||||
												}
 | 
			
		||||
												100% {
 | 
			
		||||
													transform: translate(0);
 | 
			
		||||
												.spinner_ZTLf {
 | 
			
		||||
													animation-delay: 0.2s;
 | 
			
		||||
												}
 | 
			
		||||
											}
 | 
			
		||||
										</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
 | 
			
		||||
									>
 | 
			
		||||
												@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
 | 
			
		||||
										>
 | 
			
		||||
									</div>
 | 
			
		||||
									<div class=" text-sm font-medium">
 | 
			
		||||
										{processing}
 | 
			
		||||
									</div>
 | 
			
		||||
								</div>
 | 
			
		||||
								<div class=" text-sm font-medium">
 | 
			
		||||
									{processing}
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
							{/if}
 | 
			
		||||
						{:else}
 | 
			
		||||
							<ResponseMessage
 | 
			
		||||
								{message}
 | 
			
		||||
								modelfiles={selectedModelfiles}
 | 
			
		||||
								siblings={history.messages[message.parentId]?.childrenIds ?? []}
 | 
			
		||||
								isLastMessage={messageIdx + 1 === messages.length}
 | 
			
		||||
								{confirmEditResponseMessage}
 | 
			
		||||
								{showPreviousMessage}
 | 
			
		||||
								{showNextMessage}
 | 
			
		||||
								{rateMessage}
 | 
			
		||||
								{copyToClipboard}
 | 
			
		||||
								{continueGeneration}
 | 
			
		||||
								{regenerateResponse}
 | 
			
		||||
							/>
 | 
			
		||||
						{/if}
 | 
			
		||||
					{:else}
 | 
			
		||||
						<ResponseMessage
 | 
			
		||||
							{message}
 | 
			
		||||
							modelfiles={selectedModelfiles}
 | 
			
		||||
							siblings={history.messages[message.parentId]?.childrenIds ?? []}
 | 
			
		||||
							isLastMessage={messageIdx + 1 === messages.length}
 | 
			
		||||
							{confirmEditResponseMessage}
 | 
			
		||||
							{showPreviousMessage}
 | 
			
		||||
							{showNextMessage}
 | 
			
		||||
							{rateMessage}
 | 
			
		||||
							{copyToClipboard}
 | 
			
		||||
							{continueGeneration}
 | 
			
		||||
							{regenerateResponse}
 | 
			
		||||
						/>
 | 
			
		||||
					{/if}
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		{/each}
 | 
			
		||||
			{/each}
 | 
			
		||||
 | 
			
		||||
		{#if bottomPadding}
 | 
			
		||||
			<div class=" mb-10" />
 | 
			
		||||
		{/if}
 | 
			
		||||
	{/key}
 | 
			
		||||
			{#if bottomPadding}
 | 
			
		||||
				<div class=" mb-10" />
 | 
			
		||||
			{/if}
 | 
			
		||||
		{/key}
 | 
			
		||||
	</div>
 | 
			
		||||
{/if}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
{#if models.length > 0}
 | 
			
		||||
	<div class="m-auto text-center max-w-md pb-56 px-2">
 | 
			
		||||
	<div class="m-auto text-center max-w-md px-2">
 | 
			
		||||
		<div class="flex justify-center mt-8">
 | 
			
		||||
			<div class="flex -space-x-4 mb-1">
 | 
			
		||||
				{#each models as model, modelIdx}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue