mirror of
https://github.com/open-webui/open-webui
synced 2025-04-21 06:50:44 +00:00
commit
8a94d8a226
@ -21,7 +21,7 @@ Open WebUI is an extensible, feature-rich, and user-friendly self-hosted WebUI d
|
|||||||
|
|
||||||
- 🤝 **Ollama/OpenAI API Integration**: Effortlessly integrate OpenAI-compatible APIs for versatile conversations alongside Ollama models. Customize the OpenAI API URL to link with **LMStudio, GroqCloud, Mistral, OpenRouter, and more**.
|
- 🤝 **Ollama/OpenAI API Integration**: Effortlessly integrate OpenAI-compatible APIs for versatile conversations alongside Ollama models. Customize the OpenAI API URL to link with **LMStudio, GroqCloud, Mistral, OpenRouter, and more**.
|
||||||
|
|
||||||
- 🧩 **Pipelines, Open WebUI Plugin Support**: Seamlessly integrate custom logic and Python libraries into Open WebUI using [Pipelines Plugin Framework](https://github.com/open-webui/pipelines). Launch your Pipelines instance, set the OpenAI URL to the Pipelines URL, and explore endless possibilities. [Examples](https://github.com/open-webui/pipelines/examples) include **Function Calling**, User **Rate Limiting** to control access, **Usage Monitoring** with tools like Langfuse, **Live Translation with LibreTranslate** for multilingual support, **Toxic Message Filtering** and much more.
|
- 🧩 **Pipelines, Open WebUI Plugin Support**: Seamlessly integrate custom logic and Python libraries into Open WebUI using [Pipelines Plugin Framework](https://github.com/open-webui/pipelines). Launch your Pipelines instance, set the OpenAI URL to the Pipelines URL, and explore endless possibilities. [Examples](https://github.com/open-webui/pipelines/tree/main/examples) include **Function Calling**, User **Rate Limiting** to control access, **Usage Monitoring** with tools like Langfuse, **Live Translation with LibreTranslate** for multilingual support, **Toxic Message Filtering** and much more.
|
||||||
|
|
||||||
- 📱 **Responsive Design**: Enjoy a seamless experience across Desktop PC, Laptop, and Mobile devices.
|
- 📱 **Responsive Design**: Enjoy a seamless experience across Desktop PC, Laptop, and Mobile devices.
|
||||||
|
|
||||||
|
19
src/lib/components/icons/Keyboard.svelte
Normal file
19
src/lib/components/icons/Keyboard.svelte
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let className = 'size-4';
|
||||||
|
export let strokeWidth = '2';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
class={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M2 7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V7Zm5.01 1H5v2.01h2.01V8Zm3 0H8v2.01h2.01V8Zm3 0H11v2.01h2.01V8Zm3 0H14v2.01h2.01V8Zm3 0H17v2.01h2.01V8Zm-12 3H5v2.01h2.01V11Zm3 0H8v2.01h2.01V11Zm3 0H11v2.01h2.01V11Zm3 0H14v2.01h2.01V11Zm3 0H17v2.01h2.01V11Zm-12 3H5v2.01h2.01V14ZM8 14l-.001 2 8.011.01V14H8Zm11.01 0H17v2.01h2.01V14Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
19
src/lib/components/icons/Lifebuoy.svelte
Normal file
19
src/lib/components/icons/Lifebuoy.svelte
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let className = 'w-4 h-4';
|
||||||
|
export let strokeWidth = '2';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
stroke="currentColor"
|
||||||
|
class={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M16.712 4.33a9.027 9.027 0 0 1 1.652 1.306c.51.51.944 1.064 1.306 1.652M16.712 4.33l-3.448 4.138m3.448-4.138a9.014 9.014 0 0 0-9.424 0M19.67 7.288l-4.138 3.448m4.138-3.448a9.014 9.014 0 0 1 0 9.424m-4.138-5.976a3.736 3.736 0 0 0-.88-1.388 3.737 3.737 0 0 0-1.388-.88m2.268 2.268a3.765 3.765 0 0 1 0 2.528m-2.268-4.796a3.765 3.765 0 0 0-2.528 0m4.796 4.796c-.181.506-.475.982-.88 1.388a3.736 3.736 0 0 1-1.388.88m2.268-2.268 4.138 3.448m0 0a9.027 9.027 0 0 1-1.306 1.652c-.51.51-1.064.944-1.652 1.306m0 0-3.448-4.138m3.448 4.138a9.014 9.014 0 0 1-9.424 0m5.976-4.138a3.765 3.765 0 0 1-2.528 0m0 0a3.736 3.736 0 0 1-1.388-.88 3.737 3.737 0 0 1-.88-1.388m2.268 2.268L7.288 19.67m0 0a9.024 9.024 0 0 1-1.652-1.306 9.027 9.027 0 0 1-1.306-1.652m0 0 4.138-3.448M4.33 16.712a9.014 9.014 0 0 1 0-9.424m4.138 5.976a3.765 3.765 0 0 1 0-2.528m0 0c.181-.506.475-.982.88-1.388a3.736 3.736 0 0 1 1.388-.88m-2.268 2.268L4.33 7.288m6.406 1.18L7.288 4.33m0 0a9.024 9.024 0 0 0-1.652 1.306A9.025 9.025 0 0 0 4.33 7.288"
|
||||||
|
/>
|
||||||
|
</svg>
|
19
src/lib/components/icons/QuestionMarkCircle.svelte
Normal file
19
src/lib/components/icons/QuestionMarkCircle.svelte
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let className = 'w-4 h-4';
|
||||||
|
export let strokeWidth = '2';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
stroke="currentColor"
|
||||||
|
class={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
40
src/lib/components/layout/Help.svelte
Normal file
40
src/lib/components/layout/Help.svelte
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount, tick, getContext } from 'svelte';
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
import ShortcutsModal from '../chat/ShortcutsModal.svelte';
|
||||||
|
import Tooltip from '../common/Tooltip.svelte';
|
||||||
|
import HelpMenu from './Help/HelpMenu.svelte';
|
||||||
|
|
||||||
|
let showShortcuts = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class=" hidden lg:flex fixed bottom-0 right-0 px-2 py-2 z-10">
|
||||||
|
<button
|
||||||
|
id="show-shortcuts-button"
|
||||||
|
class="hidden"
|
||||||
|
on:click={() => {
|
||||||
|
showShortcuts = !showShortcuts;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<HelpMenu
|
||||||
|
showDocsHandler={() => {
|
||||||
|
showShortcuts = !showShortcuts;
|
||||||
|
}}
|
||||||
|
showShortcutsHandler={() => {
|
||||||
|
showShortcuts = !showShortcuts;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip content={$i18n.t('Help')} placement="left">
|
||||||
|
<button
|
||||||
|
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 size-5 flex items-center justify-center text-[0.7rem] rounded-full"
|
||||||
|
>
|
||||||
|
?
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
</HelpMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShortcutsModal bind:show={showShortcuts} />
|
60
src/lib/components/layout/Help/HelpMenu.svelte
Normal file
60
src/lib/components/layout/Help/HelpMenu.svelte
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu } from 'bits-ui';
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
|
||||||
|
import { showSettings } from '$lib/stores';
|
||||||
|
import { flyAndScale } from '$lib/utils/transitions';
|
||||||
|
|
||||||
|
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||||
|
import QuestionMarkCircle from '$lib/components/icons/QuestionMarkCircle.svelte';
|
||||||
|
import Lifebuoy from '$lib/components/icons/Lifebuoy.svelte';
|
||||||
|
import Keyboard from '$lib/components/icons/Keyboard.svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
export let showDocsHandler: Function;
|
||||||
|
export let showShortcutsHandler: Function;
|
||||||
|
|
||||||
|
export let onClose: Function = () => {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
on:change={(e) => {
|
||||||
|
if (e.detail === false) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<div slot="content">
|
||||||
|
<DropdownMenu.Content
|
||||||
|
class="w-full max-w-[200px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
|
||||||
|
sideOffset={4}
|
||||||
|
side="top"
|
||||||
|
align="end"
|
||||||
|
transition={flyAndScale}
|
||||||
|
>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||||
|
id="chat-share-button"
|
||||||
|
on:click={() => {
|
||||||
|
window.open('https://docs.openwebui.com', '_blank');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<QuestionMarkCircle className="size-5" />
|
||||||
|
<div class="flex items-center">{$i18n.t('Documentation')}</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
|
<DropdownMenu.Item
|
||||||
|
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||||
|
id="chat-share-button"
|
||||||
|
on:click={() => {
|
||||||
|
showShortcutsHandler();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Keyboard className="size-5" />
|
||||||
|
<div class="flex items-center">{$i18n.t('Keyboard shortcuts')}</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
@ -3,7 +3,7 @@
|
|||||||
"(Beta)": "(Beta)",
|
"(Beta)": "(Beta)",
|
||||||
"(e.g. `sh webui.sh --api`)": "(örn. `sh webui.sh --api`)",
|
"(e.g. `sh webui.sh --api`)": "(örn. `sh webui.sh --api`)",
|
||||||
"(latest)": "(en son)",
|
"(latest)": "(en son)",
|
||||||
"{{ models }}": "{{ modeller }}",
|
"{{ models }}": "{{ models }}",
|
||||||
"{{ owner }}: You cannot delete a base model": "{{ owner }}: Temel modeli silemezsiniz",
|
"{{ owner }}: You cannot delete a base model": "{{ owner }}: Temel modeli silemezsiniz",
|
||||||
"{{modelName}} is thinking...": "{{modelName}} düşünüyor...",
|
"{{modelName}} is thinking...": "{{modelName}} düşünüyor...",
|
||||||
"{{user}}'s Chats": "{{user}} Sohbetleri",
|
"{{user}}'s Chats": "{{user}} Sohbetleri",
|
||||||
@ -37,7 +37,7 @@
|
|||||||
"All Users": "Tüm Kullanıcılar",
|
"All Users": "Tüm Kullanıcılar",
|
||||||
"Allow": "İzin ver",
|
"Allow": "İzin ver",
|
||||||
"Allow Chat Deletion": "Sohbet Silmeye İzin Ver",
|
"Allow Chat Deletion": "Sohbet Silmeye İzin Ver",
|
||||||
"Allow non-local voices": "",
|
"Allow non-local voices": "Yerel olmayan seslere izin verin",
|
||||||
"alphanumeric characters and hyphens": "alfanumerik karakterler ve tireler",
|
"alphanumeric characters and hyphens": "alfanumerik karakterler ve tireler",
|
||||||
"Already have an account?": "Zaten bir hesabınız mı var?",
|
"Already have an account?": "Zaten bir hesabınız mı var?",
|
||||||
"an assistant": "bir asistan",
|
"an assistant": "bir asistan",
|
||||||
@ -68,7 +68,7 @@
|
|||||||
"Base Model (From)": "Temel Model ('den)",
|
"Base Model (From)": "Temel Model ('den)",
|
||||||
"before": "önce",
|
"before": "önce",
|
||||||
"Being lazy": "Tembelleşiyor",
|
"Being lazy": "Tembelleşiyor",
|
||||||
"Brave Search API Key": "Cesur Arama API Anahtarı",
|
"Brave Search API Key": "Brave Search API Anahtarı",
|
||||||
"Bypass SSL verification for Websites": "Web Siteleri için SSL doğrulamasını atlayın",
|
"Bypass SSL verification for Websites": "Web Siteleri için SSL doğrulamasını atlayın",
|
||||||
"Cancel": "İptal",
|
"Cancel": "İptal",
|
||||||
"Capabilities": "Yetenekler",
|
"Capabilities": "Yetenekler",
|
||||||
@ -170,7 +170,7 @@
|
|||||||
"Edit Doc": "Belgeyi Düzenle",
|
"Edit Doc": "Belgeyi Düzenle",
|
||||||
"Edit User": "Kullanıcıyı Düzenle",
|
"Edit User": "Kullanıcıyı Düzenle",
|
||||||
"Email": "E-posta",
|
"Email": "E-posta",
|
||||||
"Embedding Batch Size": "",
|
"Embedding Batch Size": "Gömme Yığın Boyutu",
|
||||||
"Embedding Model": "Gömme Modeli",
|
"Embedding Model": "Gömme Modeli",
|
||||||
"Embedding Model Engine": "Gömme Modeli Motoru",
|
"Embedding Model Engine": "Gömme Modeli Motoru",
|
||||||
"Embedding model set to \"{{embedding_model}}\"": "Gömme modeli \"{{embedding_model}}\" olarak ayarlandı",
|
"Embedding model set to \"{{embedding_model}}\"": "Gömme modeli \"{{embedding_model}}\" olarak ayarlandı",
|
||||||
@ -187,7 +187,7 @@
|
|||||||
"Enter Chunk Size": "Chunk Boyutunu Girin",
|
"Enter Chunk Size": "Chunk Boyutunu Girin",
|
||||||
"Enter Github Raw URL": "Github Raw URL'sini girin",
|
"Enter Github Raw URL": "Github Raw URL'sini girin",
|
||||||
"Enter Google PSE API Key": "Google PSE API Anahtarını Girin",
|
"Enter Google PSE API Key": "Google PSE API Anahtarını Girin",
|
||||||
"Enter Google PSE Engine Id": "Google PSE Motor Kimliğini Girin",
|
"Enter Google PSE Engine Id": "Google PSE Engine Id'sini Girin",
|
||||||
"Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)",
|
"Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)",
|
||||||
"Enter language codes": "Dil kodlarını girin",
|
"Enter language codes": "Dil kodlarını girin",
|
||||||
"Enter model tag (e.g. {{modelTag}})": "Model etiketini girin (örn. {{modelTag}})",
|
"Enter model tag (e.g. {{modelTag}})": "Model etiketini girin (örn. {{modelTag}})",
|
||||||
@ -206,9 +206,9 @@
|
|||||||
"Enter Your Role": "Rolünüzü Girin",
|
"Enter Your Role": "Rolünüzü Girin",
|
||||||
"Error": "Hata",
|
"Error": "Hata",
|
||||||
"Experimental": "Deneysel",
|
"Experimental": "Deneysel",
|
||||||
"Export": "Ihracat",
|
"Export": "Dışa Aktar",
|
||||||
"Export All Chats (All Users)": "Tüm Sohbetleri Dışa Aktar (Tüm Kullanıcılar)",
|
"Export All Chats (All Users)": "Tüm Sohbetleri Dışa Aktar (Tüm Kullanıcılar)",
|
||||||
"Export chat (.json)": "",
|
"Export chat (.json)": "Sohbeti dışa aktar (.json)",
|
||||||
"Export Chats": "Sohbetleri Dışa Aktar",
|
"Export Chats": "Sohbetleri Dışa Aktar",
|
||||||
"Export Documents Mapping": "Belge Eşlemesini Dışa Aktar",
|
"Export Documents Mapping": "Belge Eşlemesini Dışa Aktar",
|
||||||
"Export Models": "Modelleri Dışa Aktar",
|
"Export Models": "Modelleri Dışa Aktar",
|
||||||
@ -232,7 +232,7 @@
|
|||||||
"Generation Info": "Üretim Bilgisi",
|
"Generation Info": "Üretim Bilgisi",
|
||||||
"Good Response": "İyi Yanıt",
|
"Good Response": "İyi Yanıt",
|
||||||
"Google PSE API Key": "Google PSE API Anahtarı",
|
"Google PSE API Key": "Google PSE API Anahtarı",
|
||||||
"Google PSE Engine Id": "Google PSE Motor Kimliği",
|
"Google PSE Engine Id": "Google PSE Engine Id",
|
||||||
"h:mm a": "h:mm a",
|
"h:mm a": "h:mm a",
|
||||||
"has no conversations.": "hiç konuşması yok.",
|
"has no conversations.": "hiç konuşması yok.",
|
||||||
"Hello, {{name}}": "Merhaba, {{name}}",
|
"Hello, {{name}}": "Merhaba, {{name}}",
|
||||||
@ -292,7 +292,7 @@
|
|||||||
"Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.",
|
"Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.",
|
||||||
"Model {{modelId}} not found": "{{modelId}} bulunamadı",
|
"Model {{modelId}} not found": "{{modelId}} bulunamadı",
|
||||||
"Model {{modelName}} is not vision capable": "Model {{modelName}} görüntü yeteneğine sahip değil",
|
"Model {{modelName}} is not vision capable": "Model {{modelName}} görüntü yeteneğine sahip değil",
|
||||||
"Model {{name}} is now {{status}}": "{{name}} modeli artık {{status}} oldu",
|
"Model {{name}} is now {{status}}": "{{name}} modeli artık {{status}}",
|
||||||
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
|
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
|
||||||
"Model ID": "Model ID",
|
"Model ID": "Model ID",
|
||||||
"Model not selected": "Model seçilmedi",
|
"Model not selected": "Model seçilmedi",
|
||||||
@ -347,8 +347,8 @@
|
|||||||
"pending": "beklemede",
|
"pending": "beklemede",
|
||||||
"Permission denied when accessing microphone: {{error}}": "Mikrofona erişim izni reddedildi: {{error}}",
|
"Permission denied when accessing microphone: {{error}}": "Mikrofona erişim izni reddedildi: {{error}}",
|
||||||
"Personalization": "Kişiselleştirme",
|
"Personalization": "Kişiselleştirme",
|
||||||
"Pipelines": "Boru hattı",
|
"Pipelines": "Pipelinelar",
|
||||||
"Pipelines Valves": "Boru Hatları Vanaları",
|
"Pipelines Valves": "Pipeline Valvleri",
|
||||||
"Plain text (.txt)": "Düz metin (.txt)",
|
"Plain text (.txt)": "Düz metin (.txt)",
|
||||||
"Playground": "Oyun Alanı",
|
"Playground": "Oyun Alanı",
|
||||||
"Positive attitude": "Olumlu yaklaşım",
|
"Positive attitude": "Olumlu yaklaşım",
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import { getBanners } from '$lib/apis/configs';
|
import { getBanners } from '$lib/apis/configs';
|
||||||
import { getUserSettings } from '$lib/apis/users';
|
import { getUserSettings } from '$lib/apis/users';
|
||||||
|
import Help from '$lib/components/layout/Help.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -160,7 +161,7 @@
|
|||||||
if (isCtrlPressed && event.key === '/') {
|
if (isCtrlPressed && event.key === '/') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
console.log('showShortcuts');
|
console.log('showShortcuts');
|
||||||
showShortcutsButtonElement.click();
|
document.getElementById('show-shortcuts-button')?.click();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -175,22 +176,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" hidden lg:flex fixed bottom-0 right-0 px-2 py-2 z-10">
|
<Help />
|
||||||
<Tooltip content={$i18n.t('Help')} placement="left">
|
|
||||||
<button
|
|
||||||
id="show-shortcuts-button"
|
|
||||||
bind:this={showShortcutsButtonElement}
|
|
||||||
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 size-5 flex items-center justify-center text-[0.7rem] rounded-full"
|
|
||||||
on:click={() => {
|
|
||||||
showShortcuts = !showShortcuts;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
?
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ShortcutsModal bind:show={showShortcuts} />
|
|
||||||
<SettingsModal bind:show={$showSettings} />
|
<SettingsModal bind:show={$showSettings} />
|
||||||
<ChangelogModal bind:show={$showChangelog} />
|
<ChangelogModal bind:show={$showChangelog} />
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user