enh: custom action buttons

This commit is contained in:
Timothy Jaeryang Baek 2025-08-07 02:11:27 +04:00
parent 5d670cb7ce
commit 2e733b46b0
2 changed files with 26 additions and 18 deletions

View file

@ -17,6 +17,7 @@
export let id = '';
export let model = null;
export let messages = [];
export let actions = [];
export let onAdd = (e) => {};
let floatingInput = false;
@ -30,20 +31,11 @@
let responseDone = false;
let controller = null;
const autoScroll = async () => {
const responseContainer = document.getElementById('response-container');
if (responseContainer) {
// Scroll to bottom only if the scroll is at the bottom give 50px buffer
if (
responseContainer.scrollHeight - responseContainer.clientHeight <=
responseContainer.scrollTop + 50
) {
responseContainer.scrollTop = responseContainer.scrollHeight;
}
}
};
$: if (actions.length === 0) {
actions = DEFAULT_ACTIONS;
}
const ACTIONS = [
const DEFAULT_ACTIONS = [
{
id: 'ask',
label: $i18n.t('Ask'),
@ -59,6 +51,19 @@
}
];
const autoScroll = async () => {
const responseContainer = document.getElementById('response-container');
if (responseContainer) {
// Scroll to bottom only if the scroll is at the bottom give 50px buffer
if (
responseContainer.scrollHeight - responseContainer.clientHeight <=
responseContainer.scrollTop + 50
) {
responseContainer.scrollTop = responseContainer.scrollHeight;
}
}
};
const actionHandler = async (actionId) => {
if (!model) {
toast.error('Model not selected');
@ -70,14 +75,14 @@
.map((line) => `> ${line}`)
.join('\n');
let selectedAction = ACTIONS.find((action) => action.id === actionId);
let selectedAction = actions.find((action) => action.id === actionId);
if (!selectedAction) {
toast.error('Action not found');
return;
}
let prompt = selectedAction?.prompt ?? '';
if (selectedAction.input) {
if (prompt.includes('{{INPUT_CONTENT}}') && !floatingInput) {
prompt = prompt.replace('{{INPUT_CONTENT}}', floatingInputValue);
floatingInputValue = '';
}
@ -212,14 +217,14 @@
<div
class="flex flex-row gap-0.5 shrink-0 p-1 bg-white dark:bg-gray-850 dark:text-gray-100 text-medium rounded-lg shadow-xl"
>
{#each ACTIONS as action}
{#each actions as action}
<button
class="px-1 hover:bg-gray-50 dark:hover:bg-gray-800 rounded-sm flex items-center gap-1 min-w-fit"
on:click={async () => {
selectedText = window.getSelection().toString();
selectedAction = action;
if (action.input) {
if (action.prompt.includes('{{INPUT_CONTENT}}')) {
floatingInput = true;
floatingInputValue = '';
@ -235,7 +240,9 @@
}
}}
>
<svelte:component this={action.icon} className="size-3 shrink-0" />
{#if action.icon}
<svelte:component this={action.icon} className="size-3 shrink-0" />
{/if}
<div class="shrink-0">{action.label}</div>
</button>
{/each}

View file

@ -194,6 +194,7 @@
<FloatingButtons
bind:this={floatingButtonsElement}
{id}
actions={$settings?.floatingActionButtons ?? []}
model={(selectedModels ?? []).includes(model?.id)
? model?.id
: (selectedModels ?? []).length > 0