mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-13 01:02:25 -06:00
refac
This commit is contained in:
@@ -45,7 +45,7 @@
|
||||
</script>
|
||||
|
||||
<div id="tab-about" class="flex flex-col h-full justify-between space-y-3 text-sm">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 space-y-3">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 space-y-3">
|
||||
<div>
|
||||
<div class="text-xs text-gray-400 dark:text-gray-600 mb-2.5 flex space-x-2 items-center">
|
||||
<div>
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
</script>
|
||||
|
||||
<div id="tab-account" class="flex h-full flex-col text-sm">
|
||||
<div class="flex-1 min-h-0 w-full overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 py-1">
|
||||
<div class="flex-1 min-h-0 w-full overflow-y-auto scrollbar-hover pr-1.5 py-1">
|
||||
<h2 class="mb-4 text-sm font-medium text-gray-900 dark:text-white">{$i18n.t('Account')}</h2>
|
||||
|
||||
<div class="space-y-3">
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
/>
|
||||
|
||||
<div id="tab-archived-chats" class="flex flex-col h-full text-sm">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
<div>
|
||||
<div class="text-xs text-gray-400 dark:text-gray-600 mb-2">
|
||||
{$i18n.t('Conversations')}
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
dispatch('save');
|
||||
}}
|
||||
>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 space-y-3">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 space-y-3">
|
||||
<div>
|
||||
<div class="text-xs text-gray-400 dark:text-gray-600 mb-2">
|
||||
{$i18n.t('STT Settings')}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
updateHandler();
|
||||
}}
|
||||
>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
{#if config !== null}
|
||||
<div class="">
|
||||
<div class="pr-1.5">
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
/>
|
||||
|
||||
<div id="tab-chats" class="flex flex-col h-full text-sm">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 space-y-3">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 space-y-3">
|
||||
<input
|
||||
id="chat-import-input"
|
||||
bind:this={chatImportInputElement}
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full justify-between text-sm" id="tab-general">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
<div class="">
|
||||
<div class="text-xs text-gray-400 dark:text-gray-600 mb-2">
|
||||
{$i18n.t('WebUI Settings')}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
updateHandler();
|
||||
}}
|
||||
>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
{#if servers !== null}
|
||||
<div>
|
||||
<div class="pr-1.5">
|
||||
|
||||
@@ -335,7 +335,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 space-y-3">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 space-y-3">
|
||||
<div>
|
||||
<h3 class="text-xs text-gray-400 dark:text-gray-600 mb-2">{$i18n.t('UI')}</h3>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
dispatch('save');
|
||||
}}
|
||||
>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5 py-1">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 py-1">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<Tooltip
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { shortcuts } from '$lib/shortcuts';
|
||||
import { settings } from '$lib/stores';
|
||||
import ShortcutItem from '../ShortcutItem.svelte';
|
||||
|
||||
type ShortcutDefinition = NonNullable<(typeof shortcuts)[keyof typeof shortcuts]>;
|
||||
type CategorizedShortcuts = {
|
||||
[category: string]: ShortcutDefinition[];
|
||||
};
|
||||
|
||||
const i18n: Writable<any> = getContext('i18n');
|
||||
|
||||
let categorizedShortcuts: CategorizedShortcuts = {};
|
||||
let isMac = false;
|
||||
|
||||
onMount(() => {
|
||||
isMac = /Mac/i.test(navigator.userAgent);
|
||||
});
|
||||
|
||||
$: {
|
||||
const allShortcuts = Object.values(shortcuts).filter((shortcut) => {
|
||||
if (!shortcut.setting) {
|
||||
return true;
|
||||
}
|
||||
return ($settings as Record<string, any>)[shortcut.setting.id] === shortcut.setting.value;
|
||||
});
|
||||
|
||||
categorizedShortcuts = allShortcuts.reduce<CategorizedShortcuts>((acc, shortcut) => {
|
||||
const category = shortcut.category;
|
||||
if (!acc[category]) {
|
||||
acc[category] = [];
|
||||
}
|
||||
acc[category].push(shortcut);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="tab-shortcuts" class="flex h-full flex-col text-sm">
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
<div class="flex items-center gap-2 px-1 pb-1">
|
||||
<span class="flex-1 text-[0.625rem] font-medium text-gray-400 dark:text-gray-600">
|
||||
{$i18n.t('Command')}
|
||||
</span>
|
||||
<span
|
||||
class="w-[9.5rem] shrink-0 text-right text-[0.625rem] font-medium text-gray-400 dark:text-gray-600"
|
||||
>
|
||||
{$i18n.t('Key')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{#each Object.entries(categorizedShortcuts) as [category, items], categoryIndex}
|
||||
<div class={categoryIndex > 0 ? 'mt-3' : ''}>
|
||||
<div
|
||||
class="px-1 pb-0.5 pt-1 text-[0.625rem] font-medium uppercase tracking-wide text-gray-400 dark:text-gray-600"
|
||||
>
|
||||
{$i18n.t(category)}
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100/70 dark:divide-white/[0.03]">
|
||||
<!-- {$i18n.t('Chat')} -->
|
||||
<!-- {$i18n.t('Global')} -->
|
||||
<!-- {$i18n.t('Input')} -->
|
||||
<!-- {$i18n.t('Message')} -->
|
||||
|
||||
<!-- {$i18n.t('New Chat')} -->
|
||||
<!-- {$i18n.t('New Temporary Chat')} -->
|
||||
<!-- {$i18n.t('Delete Chat')} -->
|
||||
<!-- {$i18n.t('Open Model Selector')} -->
|
||||
<!-- {$i18n.t('Toggle Dictation')} -->
|
||||
<!-- {$i18n.t('Search')} -->
|
||||
<!-- {$i18n.t('Open Settings')} -->
|
||||
<!-- {$i18n.t('Show Shortcuts')} -->
|
||||
<!-- {$i18n.t('Toggle Sidebar')} -->
|
||||
<!-- {$i18n.t('Close Modal')} -->
|
||||
<!-- {$i18n.t('Focus Chat Input')} -->
|
||||
<!-- {$i18n.t('Accept Autocomplete Generation\nJump to Prompt Variable')} -->
|
||||
<!-- {$i18n.t('Prevent File Creation')} -->
|
||||
<!-- {$i18n.t('Attach File From Knowledge')} -->
|
||||
<!-- {$i18n.t('Add Custom Prompt')} -->
|
||||
<!-- {$i18n.t('Talk to Model')} -->
|
||||
<!-- {$i18n.t('Generate Message Pair')} -->
|
||||
<!-- {$i18n.t('Regenerate Response')} -->
|
||||
<!-- {$i18n.t('Stop Generating')} -->
|
||||
<!-- {$i18n.t('Edit Last Message')} -->
|
||||
<!-- {$i18n.t('Copy Last Response')} -->
|
||||
<!-- {$i18n.t('Copy Last Code Block')} -->
|
||||
|
||||
<!-- {$i18n.t('Only active when "Paste Large Text as File" setting is toggled on.')} -->
|
||||
<!-- {$i18n.t('Only active when the chat input is in focus.')} -->
|
||||
<!-- {$i18n.t('Only active when the chat input is in focus and an LLM is generating a response.')} -->
|
||||
<!-- {$i18n.t('Only can be triggered when the chat input is in focus.')} -->
|
||||
|
||||
<!-- {$i18n.t('Voice')} -->
|
||||
<!-- {$i18n.t('Toggle Mute')} -->
|
||||
<!-- {$i18n.t('Only active during Voice Mode.')} -->
|
||||
{#each items as shortcut}
|
||||
<ShortcutItem {shortcut} {isMac} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -12,6 +12,7 @@
|
||||
import About from './Settings/About.svelte';
|
||||
import General from './Settings/General.svelte';
|
||||
import Interface from './Settings/Interface.svelte';
|
||||
import Shortcuts from './Settings/Shortcuts.svelte';
|
||||
import Audio from './Settings/Audio.svelte';
|
||||
import DataControls from './Settings/DataControls.svelte';
|
||||
import ArchivedChats from './Settings/ArchivedChats.svelte';
|
||||
@@ -31,17 +32,32 @@
|
||||
import UserBadgeCheck from '../icons/UserBadgeCheck.svelte';
|
||||
import ArchiveBox from '../icons/ArchiveBox.svelte';
|
||||
import ChevronLeft from '../icons/ChevronLeft.svelte';
|
||||
import Keyboard from '../icons/Keyboard.svelte';
|
||||
|
||||
const i18n: Writable<any> = getContext('i18n');
|
||||
|
||||
export let show: boolean | string = false;
|
||||
let modalShow = false;
|
||||
let lastShow: boolean | string = false;
|
||||
|
||||
$: if (show) {
|
||||
$: if (show !== lastShow) {
|
||||
lastShow = show;
|
||||
if (typeof show === 'string') {
|
||||
selectedTab = show;
|
||||
show = true;
|
||||
lastShow = true;
|
||||
modalShow = true;
|
||||
} else {
|
||||
modalShow = show;
|
||||
if (!show) {
|
||||
selectedTab = 'general';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
$: if (!modalShow && show !== false) {
|
||||
show = false;
|
||||
lastShow = false;
|
||||
selectedTab = 'general';
|
||||
}
|
||||
|
||||
@@ -211,6 +227,21 @@
|
||||
'web search in chat'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'shortcuts',
|
||||
title: 'Keyboard Shortcuts',
|
||||
keywords: [
|
||||
'commands',
|
||||
'hotkeys',
|
||||
'keyboard',
|
||||
'keyboard shortcuts',
|
||||
'keybindings',
|
||||
'keys',
|
||||
'shortcut',
|
||||
'shortcuts',
|
||||
'show shortcuts'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'connections',
|
||||
title: 'Connections',
|
||||
@@ -593,8 +624,8 @@
|
||||
<Modal
|
||||
size="full"
|
||||
containerClassName="p-4 sm:p-6 lg:p-8"
|
||||
className="w-full max-w-[88rem] h-[min(50rem,calc(100dvh-4rem))] max-h-[calc(100dvh-4rem)] flex flex-col md:flex-row bg-white dark:bg-gray-900 rounded-4xl"
|
||||
bind:show
|
||||
className="!w-[calc(100vw-2rem)] sm:!w-[calc(100vw-3rem)] lg:!w-[calc(100vw-4rem)] !max-w-[76rem] h-[min(50rem,calc(100dvh-4rem))] max-h-[calc(100dvh-4rem)] flex flex-col md:flex-row bg-white dark:bg-gray-900 rounded-4xl"
|
||||
bind:show={modalShow}
|
||||
>
|
||||
<nav
|
||||
id="settings-tabs-container"
|
||||
@@ -668,6 +699,19 @@
|
||||
<AppNotification className="size-3.5" strokeWidth="2" />
|
||||
<span>{$i18n.t('Interface')}</span>
|
||||
</button>
|
||||
{:else if tabId === 'shortcuts'}
|
||||
<button
|
||||
role="tab"
|
||||
aria-controls="tab-shortcuts"
|
||||
aria-selected={selectedTab === 'shortcuts'}
|
||||
class={tabButtonClass(selectedTab === 'shortcuts')}
|
||||
on:click={() => {
|
||||
selectedTab = 'shortcuts';
|
||||
}}
|
||||
>
|
||||
<Keyboard className="size-3.5" strokeWidth="2" />
|
||||
<span>{$i18n.t('Keyboard Shortcuts')}</span>
|
||||
</button>
|
||||
{:else if tabId === 'connections'}
|
||||
{#if $user?.role === 'admin' || ($user?.role === 'user' && $config?.features?.enable_direct_connections)}
|
||||
<button
|
||||
@@ -829,6 +873,8 @@
|
||||
toast.success($i18n.t('Settings saved successfully!'));
|
||||
}}
|
||||
/>
|
||||
{:else if selectedTab === 'shortcuts'}
|
||||
<Shortcuts />
|
||||
{:else if selectedTab === 'connections'}
|
||||
<Connections
|
||||
saveSettings={async (updated: Record<string, any>) => {
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import type { Shortcut } from '$lib/shortcuts';
|
||||
import { shortcuts } from '$lib/shortcuts';
|
||||
|
||||
export let shortcut: Shortcut;
|
||||
type ShortcutDefinition = NonNullable<(typeof shortcuts)[keyof typeof shortcuts]>;
|
||||
|
||||
export let shortcut: ShortcutDefinition;
|
||||
export let isMac: boolean;
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n: Writable<any> = getContext('i18n');
|
||||
let keyboardLayoutMap: Map<string, string> | undefined;
|
||||
|
||||
onMount(async () => {
|
||||
if (navigator.keyboard && 'getLayoutMap' in navigator.keyboard) {
|
||||
const nav = navigator as Navigator & {
|
||||
keyboard?: { getLayoutMap?: () => Promise<Map<string, string>> };
|
||||
};
|
||||
|
||||
if (nav.keyboard?.getLayoutMap) {
|
||||
try {
|
||||
keyboardLayoutMap = await navigator.keyboard.getLayoutMap();
|
||||
keyboardLayoutMap = await nav.keyboard.getLayoutMap();
|
||||
} catch (error) {
|
||||
console.error('Failed to get keyboard layout map:', error);
|
||||
}
|
||||
@@ -70,27 +77,34 @@
|
||||
return key.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
function visibleKeys(keys: string[]): string[] {
|
||||
return keys.filter((key) => !(key.toLowerCase() === 'delete' && keys.includes('Backspace')));
|
||||
}
|
||||
|
||||
function formatKeys(keys: string[]): string {
|
||||
return visibleKeys(keys)
|
||||
.map(formatKey)
|
||||
.join(isMac ? '' : ' + ');
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full flex justify-between">
|
||||
<div class="text-sm whitespace-pre-line">
|
||||
<div class="flex min-h-8 w-full items-center gap-3 px-1 py-1.5">
|
||||
<div class="min-w-0 flex-1 text-[0.71875rem] leading-tight text-gray-700 dark:text-gray-300">
|
||||
{#if shortcut.tooltip}
|
||||
<Tooltip content={$i18n.t(shortcut.tooltip)}>
|
||||
<span class="whitespace-nowrap">
|
||||
{$i18n.t(shortcut.name)}<span class="text-xs"> *</span>
|
||||
<span class="inline-flex max-w-full items-baseline gap-1">
|
||||
<span class="truncate whitespace-pre-line">{$i18n.t(shortcut.name)}</span>
|
||||
<span class="text-[0.625rem] text-gray-400 dark:text-gray-600">*</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
{$i18n.t(shortcut.name)}
|
||||
<span class="whitespace-pre-line">{$i18n.t(shortcut.name)}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex-shrink-0 flex justify-end self-start h-full space-x-1 text-xs">
|
||||
{#each shortcut.keys.filter((key) => !(key.toLowerCase() === 'delete' && shortcut.keys.includes('Backspace'))) as key}
|
||||
<div
|
||||
class="h-fit px-1 py-0.5 flex items-start justify-center rounded-sm border border-black/10 capitalize text-gray-600 dark:border-white/10 dark:text-gray-300"
|
||||
>
|
||||
{formatKey(key)}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<span
|
||||
class="inline-flex min-h-[1.125rem] max-w-[9.5rem] shrink-0 items-center justify-center rounded-full bg-gray-100 px-[0.4375rem] py-0.5 text-center text-[0.625rem] font-medium leading-none text-gray-500 dark:bg-white/6 dark:text-gray-400"
|
||||
>
|
||||
{formatKeys(shortcut.keys)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import Modal from '../common/Modal.svelte';
|
||||
import { shortcuts } from '$lib/shortcuts';
|
||||
import { settings } from '$lib/stores';
|
||||
import ShortcutItem from './ShortcutItem.svelte';
|
||||
import XMark from '$lib/components/icons/XMark.svelte';
|
||||
|
||||
type CategorizedShortcuts = {
|
||||
[category: string]: {
|
||||
left: Shortcut[];
|
||||
right: Shortcut[];
|
||||
};
|
||||
};
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let show = false;
|
||||
|
||||
let categorizedShortcuts: CategorizedShortcuts = {};
|
||||
let isMac = false;
|
||||
|
||||
onMount(() => {
|
||||
isMac = /Mac/i.test(navigator.userAgent);
|
||||
});
|
||||
|
||||
$: {
|
||||
const allShortcuts = Object.values(shortcuts).filter((shortcut) => {
|
||||
if (!shortcut.setting) {
|
||||
return true;
|
||||
}
|
||||
return $settings[shortcut.setting.id] === shortcut.setting.value;
|
||||
});
|
||||
|
||||
categorizedShortcuts = allShortcuts.reduce((acc, shortcut) => {
|
||||
const category = shortcut.category;
|
||||
if (!acc[category]) {
|
||||
acc[category] = [];
|
||||
}
|
||||
acc[category].push(shortcut);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:show>
|
||||
<div class="text-gray-700 dark:text-gray-100 px-5 py-4">
|
||||
<div class="flex justify-between dark:text-gray-300 pb-2">
|
||||
<div class="text-lg font-normal self-center">{$i18n.t('Keyboard Shortcuts')}</div>
|
||||
<button class="self-center" aria-label={$i18n.t('Close')} on:click={() => (show = false)}>
|
||||
<XMark className={'size-5'} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#each Object.entries(categorizedShortcuts) as [category, items], categoryIndex}
|
||||
{#if categoryIndex > 0}
|
||||
<div class="py-3">
|
||||
<div class="w-full border-t dark:border-gray-850 border-gray-50" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-between dark:text-gray-300 pb-2">
|
||||
<div class="text-base self-center">{$i18n.t(category)}</div>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row w-full md:space-x-2 dark:text-gray-200">
|
||||
<div class="flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
|
||||
<div class=" grid grid-cols-1 sm:grid-cols-2 gap-2 gap-x-4 w-full">
|
||||
<!-- {$i18n.t('Chat')} -->
|
||||
<!-- {$i18n.t('Global')} -->
|
||||
<!-- {$i18n.t('Input')} -->
|
||||
<!-- {$i18n.t('Message')} -->
|
||||
|
||||
<!-- {$i18n.t('New Chat')} -->
|
||||
<!-- {$i18n.t('New Temporary Chat')} -->
|
||||
<!-- {$i18n.t('Delete Chat')} -->
|
||||
<!-- {$i18n.t('Open Model Selector')} -->
|
||||
<!-- {$i18n.t('Toggle Dictation')} -->
|
||||
<!-- {$i18n.t('Search')} -->
|
||||
<!-- {$i18n.t('Open Settings')} -->
|
||||
<!-- {$i18n.t('Show Shortcuts')} -->
|
||||
<!-- {$i18n.t('Toggle Sidebar')} -->
|
||||
<!-- {$i18n.t('Close Modal')} -->
|
||||
<!-- {$i18n.t('Focus Chat Input')} -->
|
||||
<!-- {$i18n.t('Accept Autocomplete Generation\nJump to Prompt Variable')} -->
|
||||
<!-- {$i18n.t('Prevent File Creation')} -->
|
||||
<!-- {$i18n.t('Attach File From Knowledge')} -->
|
||||
<!-- {$i18n.t('Add Custom Prompt')} -->
|
||||
<!-- {$i18n.t('Talk to Model')} -->
|
||||
<!-- {$i18n.t('Generate Message Pair')} -->
|
||||
<!-- {$i18n.t('Regenerate Response')} -->
|
||||
<!-- {$i18n.t('Stop Generating')} -->
|
||||
<!-- {$i18n.t('Edit Last Message')} -->
|
||||
<!-- {$i18n.t('Copy Last Response')} -->
|
||||
<!-- {$i18n.t('Copy Last Code Block')} -->
|
||||
|
||||
<!-- {$i18n.t('Only active when "Paste Large Text as File" setting is toggled on.')} -->
|
||||
<!-- {$i18n.t('Only active when the chat input is in focus.')} -->
|
||||
<!-- {$i18n.t('Only active when the chat input is in focus and an LLM is generating a response.')} -->
|
||||
<!-- {$i18n.t('Only can be triggered when the chat input is in focus.')} -->
|
||||
|
||||
<!-- {$i18n.t('Voice')} -->
|
||||
<!-- {$i18n.t('Toggle Mute')} -->
|
||||
<!-- {$i18n.t('Only active during Voice Mode.')} -->
|
||||
{#each items as shortcut}
|
||||
<div class="col-span-1 flex items-start">
|
||||
<ShortcutItem {shortcut} {isMac} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
</style>
|
||||
@@ -7,15 +7,7 @@
|
||||
import { getUsage } from '$lib/apis';
|
||||
import { getSessionUser, userSignOut } from '$lib/apis/auths';
|
||||
|
||||
import {
|
||||
showSettings,
|
||||
mobile,
|
||||
showSidebar,
|
||||
showShortcuts,
|
||||
user,
|
||||
config,
|
||||
settings
|
||||
} from '$lib/stores';
|
||||
import { showSettings, mobile, showSidebar, user, config, settings } from '$lib/stores';
|
||||
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
|
||||
@@ -25,7 +17,6 @@
|
||||
import QuestionMarkCircle from '$lib/components/icons/QuestionMarkCircle.svelte';
|
||||
import Map from '$lib/components/icons/Map.svelte';
|
||||
import Keyboard from '$lib/components/icons/Keyboard.svelte';
|
||||
import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
|
||||
import Settings from '$lib/components/icons/Settings.svelte';
|
||||
import Code from '$lib/components/icons/Code.svelte';
|
||||
import UserGroup from '$lib/components/icons/UserGroup.svelte';
|
||||
@@ -109,7 +100,6 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<ShortcutsModal bind:show={$showShortcuts} />
|
||||
<UserStatusModal
|
||||
bind:show={showUserStatusModal}
|
||||
onSave={async () => {
|
||||
@@ -546,7 +536,7 @@
|
||||
id="chat-share-button"
|
||||
on:click={async () => {
|
||||
show = false;
|
||||
showShortcuts.set(!$showShortcuts);
|
||||
showSettings.set('shortcuts');
|
||||
|
||||
if ($mobile) {
|
||||
await tick();
|
||||
|
||||
@@ -92,7 +92,6 @@ export const sidebarWidth = writable(245);
|
||||
export const showSidebar = writable(false);
|
||||
export const showSearch = writable(false);
|
||||
export const showSettings: Writable<boolean | string> = writable(false);
|
||||
export const showShortcuts = writable(false);
|
||||
export const showChangelog = writable(false);
|
||||
|
||||
export const showControls = writable(false);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
tags,
|
||||
banners,
|
||||
showSettings,
|
||||
showShortcuts,
|
||||
showChangelog,
|
||||
temporaryChatEnabled,
|
||||
toolServers,
|
||||
@@ -281,12 +280,11 @@
|
||||
} else if (isShortcutMatch(event, shortcuts[Shortcut.SHOW_SHORTCUTS])) {
|
||||
console.log('Shortcut triggered: SHOW_SHORTCUTS');
|
||||
event.preventDefault();
|
||||
showShortcuts.set(!$showShortcuts);
|
||||
showSettings.set('shortcuts');
|
||||
} else if (isShortcutMatch(event, shortcuts[Shortcut.CLOSE_MODAL])) {
|
||||
console.log('Shortcut triggered: CLOSE_MODAL');
|
||||
event.preventDefault();
|
||||
showSettings.set(false);
|
||||
showShortcuts.set(false);
|
||||
} else if (isShortcutMatch(event, shortcuts[Shortcut.OPEN_MODEL_SELECTOR])) {
|
||||
console.log('Shortcut triggered: OPEN_MODEL_SELECTOR');
|
||||
event.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user