-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eea5481
commit 4b64f1d
Showing
7 changed files
with
207 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<script lang="ts" context="module"> | ||
import { debounce } from 'throttle-debounce'; | ||
export const updateCursor = debounce(200, (field: HTMLElement, autofocus = false) => { | ||
const sel = window.getSelection(); | ||
if (!sel || !field.childNodes.length) return; | ||
const range = document.createRange(); | ||
range.setStart(field.childNodes[0], field.innerText.length); | ||
range.setEnd(field.childNodes[0], field.innerText.length); | ||
sel.removeAllRanges(); | ||
sel.addRange(range); | ||
if (autofocus) field.focus(); | ||
}); | ||
</script> | ||
|
||
<script lang="ts"> | ||
import { createEventDispatcher, tick } from 'svelte'; | ||
import cs from 'clsx'; | ||
export let searchTerm = ''; | ||
export let autofocus = true; | ||
export let showIcon = true; | ||
export let placeholder = ''; | ||
export let disabled = false; | ||
export let iconPosition: 'left' | 'right' = 'right'; | ||
export let submitOnBlur = false; | ||
export function hasFocus() { | ||
return document.activeElement === inputEl; | ||
} | ||
export function setFocus() { | ||
tick().then(() => inputEl?.focus()); | ||
} | ||
const dispatch = createEventDispatcher<{ keypress: void }>(); | ||
let inputEl: HTMLDivElement | undefined; | ||
$: autofocus && setFocus(); | ||
$: placeholder = searchTerm ? '' : placeholder; | ||
$: if (inputEl && searchTerm) { | ||
inputEl.removeAttribute('data-placeholder'); | ||
} else if (inputEl) { | ||
inputEl.setAttribute('data-placeholder', placeholder); | ||
} | ||
$: inputEl && updateCursor(inputEl, autofocus); | ||
function handleKeyPress(ev: KeyboardEvent) { | ||
if (ev.key === 'Enter' && !ev.shiftKey && searchTerm) { | ||
ev.preventDefault(); | ||
dispatch('keypress'); | ||
} | ||
} | ||
function onInput() { | ||
if (!inputEl) return; | ||
if (inputEl.innerHTML.trim() === '<br>') { | ||
inputEl.innerHTML = ''; | ||
} | ||
} | ||
</script> | ||
|
||
<div | ||
class="relative flex min-h-14 w-full gap-x-2 rounded-md border-2 border-zinc-500 p-1 pl-2.5 focus-within:border-emerald-600" | ||
> | ||
{#if showIcon && iconPosition === 'left'} | ||
<slot name="icon-left" {disabled} /> | ||
{/if} | ||
|
||
<div class="flex w-[90%] overflow-y-auto overflow-x-hidden pl-0.5 pr-0 pt-2 outline-none"> | ||
<div | ||
id="contentDiv" | ||
role="textbox" | ||
tabindex="0" | ||
contenteditable | ||
class={cs( | ||
'peer block h-full w-full break-words border-none bg-transparent text-left text-[16px] outline-none', | ||
{ 'pointer-events-none': disabled } | ||
)} | ||
data-placeholder={placeholder} | ||
spellcheck={false} | ||
bind:this={inputEl} | ||
bind:textContent={searchTerm} | ||
on:keypress={handleKeyPress} | ||
on:blur={() => submitOnBlur && dispatch('keypress')} | ||
on:input={onInput} | ||
/> | ||
</div> | ||
<div class:hidden={!$$slots['icon-right']} class="absolute bottom-0 right-0 flex h-full pr-2"> | ||
{#if showIcon && iconPosition === 'right'} | ||
<span class="self-end"> | ||
<slot name="icon-right" {disabled} /> | ||
</span> | ||
{/if} | ||
</div> | ||
</div> | ||
|
||
<style lang="postcss"> | ||
#contentDiv[data-placeholder]::before { | ||
content: attr(data-placeholder); | ||
color: rgba(var(--fg)); | ||
opacity: 0.6; | ||
font-size: 16px; | ||
pointer-events: none; | ||
display: inline-block; | ||
} | ||
#contentDiv[data-placeholder]::before { | ||
@apply bg-gradient-to-r from-gray-400 to-emerald-200 bg-clip-text text-transparent; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<script lang="ts"> | ||
import { SearchIcon, SendIcon } from 'lucide-svelte'; | ||
import cs from 'clsx'; | ||
import Spinner from './Spinner.svelte'; | ||
export let loading = false; | ||
export let disabled = false; | ||
export let searchTerm = ''; | ||
export let iconType: 'search' | 'send' = 'search'; | ||
</script> | ||
|
||
<button | ||
class={cs( | ||
'my-2 flex h-8 w-8 items-center justify-center rounded-md outline-none transition duration-200 ease-in-out hover:scale-[1.02] active:translate-y-1', | ||
{ | ||
'p-1': iconType === 'search', | ||
'p-2': iconType === 'send', | ||
'bg-gray-600': (searchTerm || loading) && iconType === 'send' | ||
} | ||
)} | ||
disabled={disabled || !searchTerm} | ||
on:click | ||
> | ||
{#if loading} | ||
<span class:text-white={iconType === 'send'}> | ||
<Spinner small /> | ||
</span> | ||
{:else if iconType === 'send'} | ||
<svg | ||
class="h-6 w-6 fill-gray-600 transition-colors duration-200" | ||
class:opacity-50={!searchTerm} | ||
class:text-white={searchTerm} | ||
fill="none" | ||
viewBox="0 0 24 24" | ||
stroke="currentColor" | ||
> | ||
<path fill="currentColor" d="m2 21l21-9L2 3v7l15 2l-15 2v7Z" /> | ||
</svg> | ||
{:else} | ||
<SendIcon | ||
class="h-full w-full rounded-sm opacity-70 transition-colors duration-200 hover:bg-gray-400/40" | ||
/> | ||
{/if} | ||
</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<script> | ||
import cs from 'clsx'; | ||
export let small = false; | ||
</script> | ||
|
||
<spinner> | ||
<svg | ||
class={cs('animate-spin', { | ||
'h-4 w-4': small, | ||
'h-6 w-6': !small | ||
})} | ||
viewBox="0 0 256 256" | ||
> | ||
<path | ||
fill="currentColor" | ||
d="M140 32v32a12 12 0 0 1-24 0V32a12 12 0 0 1 24 0Zm33.25 62.75a12 12 0 0 0 8.49-3.52l22.63-22.63a12 12 0 0 0-17-17l-22.6 22.66a12 12 0 0 0 8.48 20.49ZM224 116h-32a12 12 0 0 0 0 24h32a12 12 0 0 0 0-24Zm-42.26 48.77a12 12 0 1 0-17 17l22.63 22.63a12 12 0 0 0 17-17ZM128 180a12 12 0 0 0-12 12v32a12 12 0 0 0 24 0v-32a12 12 0 0 0-12-12Zm-53.74-15.23L51.63 187.4a12 12 0 0 0 17 17l22.63-22.63a12 12 0 1 0-17-17ZM76 128a12 12 0 0 0-12-12H32a12 12 0 0 0 0 24h32a12 12 0 0 0 12-12Zm-7.4-76.37a12 12 0 1 0-17 17l22.66 22.6a12 12 0 0 0 17-17Z" | ||
/> | ||
</svg> | ||
</spinner> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,20 @@ | ||
<script> | ||
import ChatContainer from '@/components/ChatContainer.svelte'; | ||
export let data; | ||
import ChatBox from '@/components/ChatBox.svelte'; | ||
export let data; | ||
$: category = data.category; | ||
$: sessionId = data.sessionId; | ||
let searchTerm = ''; | ||
</script> | ||
|
||
<ChatContainer> | ||
<div slot="content"> | ||
{sessionId}: {category} | ||
</div> | ||
|
||
<div slot="chat_input" class="h-[16%] fixed w-[calc(100%-24.5rem)] bottom-0 shrink-0"> | ||
Chat Input Section | ||
<div slot="chat_box"> | ||
<ChatBox bind:searchTerm placeholder="What would you like to listen to?" /> | ||
</div> | ||
</ChatContainer> |