refac
This commit is contained in:
@@ -469,9 +469,14 @@ async def get_default_user_permissions_defaults(user=Depends(get_admin_user)):
|
||||
|
||||
@router.get('/user/settings', response_model=UserSettings | None)
|
||||
async def get_user_settings_by_session_user(
|
||||
user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)
|
||||
raw: bool = False,
|
||||
user=Depends(get_verified_user),
|
||||
db: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
# user already fetched by get_verified_user — no need to refetch
|
||||
if raw:
|
||||
return user.settings
|
||||
|
||||
default_interface_settings = await Config.get('ui.default_interface_settings')
|
||||
if not isinstance(default_interface_settings, dict) or not default_interface_settings:
|
||||
return user.settings
|
||||
|
||||
@@ -271,9 +271,9 @@ export const getAllUsers = async (token: string) => {
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getUserSettings = async (token: string) => {
|
||||
export const getUserSettings = async (token: string, raw = false) => {
|
||||
let error = null;
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/users/user/settings`, {
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/users/user/settings${raw ? '?raw=true' : ''}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
const i18n: any = getContext('i18n');
|
||||
|
||||
export let saveSettings: Function;
|
||||
export let personalSettingsValue: Record<string, any> = {};
|
||||
|
||||
let interfaceSettings: any;
|
||||
</script>
|
||||
@@ -21,7 +22,7 @@
|
||||
<h2 class="text-sm font-medium text-gray-900 dark:text-white mb-4">{$i18n.t('Interface')}</h2>
|
||||
|
||||
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5">
|
||||
<InterfaceSettings bind:this={interfaceSettings} {saveSettings} />
|
||||
<InterfaceSettings bind:this={interfaceSettings} {saveSettings} {personalSettingsValue} />
|
||||
</div>
|
||||
|
||||
<div class="shrink-0 flex justify-end text-sm font-normal">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { config, models, settings, user } from '$lib/stores';
|
||||
import type { SettingsModalRequest } from '$lib/stores';
|
||||
import { updateUserSettings } from '$lib/apis/users';
|
||||
import { getUserSettings, updateUserSettings } from '$lib/apis/users';
|
||||
import { getBackendConfig, getModels as _getModels } from '$lib/apis';
|
||||
|
||||
import Modal from '../common/Modal.svelte';
|
||||
@@ -61,6 +61,18 @@
|
||||
let modalShow = false;
|
||||
let lastShow: boolean | string | SettingsModalRequest = false;
|
||||
let tabState: Record<string, unknown> | null = null;
|
||||
let personalUiSettings: Record<string, any> = {};
|
||||
|
||||
const loadPersonalUiSettings = async () => {
|
||||
const userSettings = await getUserSettings(localStorage.token, true).catch((error) => {
|
||||
console.error(error);
|
||||
return null;
|
||||
});
|
||||
personalUiSettings =
|
||||
userSettings?.ui && typeof userSettings.ui === 'object' && !Array.isArray(userSettings.ui)
|
||||
? userSettings.ui
|
||||
: {};
|
||||
};
|
||||
|
||||
$: if (show !== lastShow) {
|
||||
lastShow = show;
|
||||
@@ -70,13 +82,18 @@
|
||||
show = true;
|
||||
lastShow = true;
|
||||
modalShow = true;
|
||||
loadPersonalUiSettings();
|
||||
} else if (typeof show === 'string') {
|
||||
selectedTab = show;
|
||||
show = true;
|
||||
lastShow = true;
|
||||
modalShow = true;
|
||||
loadPersonalUiSettings();
|
||||
} else {
|
||||
modalShow = show;
|
||||
if (show) {
|
||||
loadPersonalUiSettings();
|
||||
}
|
||||
if (!show) {
|
||||
selectedTab = 'general';
|
||||
tabState = null;
|
||||
@@ -818,7 +835,9 @@
|
||||
console.log(updated);
|
||||
await settings.set({ ...$settings, ...updated });
|
||||
await models.set(await getModels());
|
||||
await updateUserSettings(localStorage.token, { ui: $settings });
|
||||
const saved = await updateUserSettings(localStorage.token, { ui: $settings });
|
||||
personalUiSettings =
|
||||
saved?.ui && typeof saved.ui === 'object' && !Array.isArray(saved.ui) ? saved.ui : {};
|
||||
};
|
||||
|
||||
const getModels = async () => {
|
||||
@@ -1169,6 +1188,7 @@
|
||||
{:else if selectedTab === 'interface'}
|
||||
<Interface
|
||||
{saveSettings}
|
||||
personalSettingsValue={personalUiSettings}
|
||||
on:save={() => {
|
||||
toast.success($i18n.t('Settings saved successfully!'));
|
||||
}}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
export let saveSettings: Function;
|
||||
export let settingsValue: Record<string, any> | null = null;
|
||||
export let personalSettingsValue: Record<string, any> = {};
|
||||
|
||||
$: currentSettings = (settingsValue ?? $settings ?? {}) as Record<string, any>;
|
||||
$: externalSettings = settingsValue !== null;
|
||||
@@ -118,10 +119,29 @@
|
||||
const actionButtonClass =
|
||||
'text-xs text-gray-500 transition-colors hover:text-gray-900 dark:text-gray-500 dark:hover:text-white';
|
||||
|
||||
const matchesDefaultSetting = (key: string, value: unknown) =>
|
||||
!externalSettings &&
|
||||
Object.prototype.hasOwnProperty.call(defaultSettings, key) &&
|
||||
JSON.stringify(defaultSettings[key]) === JSON.stringify(value);
|
||||
const hasSettingPath = (source: Record<string, any>, path: string) => {
|
||||
let current: any = source;
|
||||
for (const part of path.split('.')) {
|
||||
if (!current || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) {
|
||||
return false;
|
||||
}
|
||||
current = current[part];
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const settingPathByState: Record<string, string> = {
|
||||
titleAutoGenerate: 'title.auto'
|
||||
};
|
||||
|
||||
const isDefaultSetting = (stateKey: string) => {
|
||||
const path = settingPathByState[stateKey] ?? stateKey;
|
||||
return (
|
||||
!externalSettings &&
|
||||
hasSettingPath(defaultSettings, path) &&
|
||||
!hasSettingPath(personalSettingsValue, path)
|
||||
);
|
||||
};
|
||||
|
||||
const toggleLandingPageMode = async () => {
|
||||
landingPageMode = landingPageMode === '' ? 'chat' : '';
|
||||
@@ -315,7 +335,7 @@
|
||||
lastSettingsValue = settingsValue;
|
||||
init();
|
||||
}
|
||||
$: textScaleUsesDefault = textScale === null || matchesDefaultSetting('textScale', textScale);
|
||||
$: textScaleUsesDefault = textScale === null || isDefaultSetting('textScale');
|
||||
|
||||
onMount(async () => {
|
||||
init();
|
||||
@@ -463,6 +483,7 @@
|
||||
ariaLabelledbyId="high-contrast-mode-label"
|
||||
tooltip={true}
|
||||
bind:state={highContrastMode}
|
||||
inherited={isDefaultSetting('highContrastMode')}
|
||||
on:change={() => {
|
||||
saveSettings({ highContrastMode });
|
||||
}}
|
||||
@@ -485,6 +506,7 @@
|
||||
ariaLabelledbyId="use-chat-title-as-tab-title-label"
|
||||
tooltip={true}
|
||||
bind:state={showChatTitleInTab}
|
||||
inherited={isDefaultSetting('showChatTitleInTab')}
|
||||
on:change={() => {
|
||||
saveSettings({ showChatTitleInTab });
|
||||
}}
|
||||
@@ -505,6 +527,7 @@
|
||||
ariaLabelledbyId="allow-user-location-label"
|
||||
tooltip={true}
|
||||
bind:state={userLocation}
|
||||
inherited={isDefaultSetting('userLocation')}
|
||||
on:change={() => {
|
||||
toggleUserLocation();
|
||||
}}
|
||||
@@ -527,6 +550,7 @@
|
||||
ariaLabelledbyId="haptic-feedback-label"
|
||||
tooltip={true}
|
||||
bind:state={hapticFeedback}
|
||||
inherited={isDefaultSetting('hapticFeedback')}
|
||||
on:change={() => {
|
||||
saveSettings({ hapticFeedback });
|
||||
}}
|
||||
@@ -549,6 +573,7 @@
|
||||
ariaLabelledbyId="copy-formatted-label"
|
||||
tooltip={true}
|
||||
bind:state={copyFormatted}
|
||||
inherited={isDefaultSetting('copyFormatted')}
|
||||
on:change={() => {
|
||||
saveSettings({ copyFormatted });
|
||||
}}
|
||||
@@ -572,6 +597,7 @@
|
||||
ariaLabelledbyId="toast-notifications-label"
|
||||
tooltip={true}
|
||||
bind:state={showUpdateToast}
|
||||
inherited={isDefaultSetting('showUpdateToast')}
|
||||
on:change={() => {
|
||||
saveSettings({ showUpdateToast });
|
||||
}}
|
||||
@@ -594,6 +620,7 @@
|
||||
ariaLabelledbyId="whats-new-label"
|
||||
tooltip={true}
|
||||
bind:state={showChangelog}
|
||||
inherited={isDefaultSetting('showChangelog')}
|
||||
on:change={() => {
|
||||
saveSettings({ showChangelog });
|
||||
}}
|
||||
@@ -619,6 +646,7 @@
|
||||
ariaLabelledbyId="enable-message-queue-label"
|
||||
tooltip={true}
|
||||
bind:state={enableMessageQueue}
|
||||
inherited={isDefaultSetting('enableMessageQueue')}
|
||||
on:change={() => {
|
||||
saveSettings({ enableMessageQueue });
|
||||
}}
|
||||
@@ -720,6 +748,7 @@
|
||||
tooltip={true}
|
||||
ariaLabelledbyId="chat-bubble-ui-label"
|
||||
bind:state={chatBubble}
|
||||
inherited={isDefaultSetting('chatBubble')}
|
||||
on:change={() => {
|
||||
saveSettings({ chatBubble });
|
||||
}}
|
||||
@@ -743,6 +772,7 @@
|
||||
ariaLabelledbyId="chat-bubble-username-label"
|
||||
tooltip={true}
|
||||
bind:state={showUsername}
|
||||
inherited={isDefaultSetting('showUsername')}
|
||||
on:change={() => {
|
||||
saveSettings({ showUsername });
|
||||
}}
|
||||
@@ -766,6 +796,7 @@
|
||||
ariaLabelledbyId="widescreen-mode-label"
|
||||
tooltip={true}
|
||||
bind:state={widescreenMode}
|
||||
inherited={isDefaultSetting('widescreenMode')}
|
||||
on:change={() => {
|
||||
saveSettings({ widescreenMode });
|
||||
}}
|
||||
@@ -789,6 +820,7 @@
|
||||
ariaLabelledbyId="temp-chat-default-label"
|
||||
tooltip={true}
|
||||
bind:state={temporaryChatByDefault}
|
||||
inherited={isDefaultSetting('temporaryChatByDefault')}
|
||||
on:change={() => {
|
||||
saveSettings({ temporaryChatByDefault });
|
||||
}}
|
||||
@@ -812,6 +844,7 @@
|
||||
ariaLabelledbyId="fade-streaming-label"
|
||||
tooltip={true}
|
||||
bind:state={chatFadeStreamingText}
|
||||
inherited={isDefaultSetting('chatFadeStreamingText')}
|
||||
on:change={() => {
|
||||
saveSettings({ chatFadeStreamingText });
|
||||
}}
|
||||
@@ -834,6 +867,7 @@
|
||||
ariaLabelledbyId="render-markdown-user-label"
|
||||
tooltip={true}
|
||||
bind:state={renderMarkdownInUserMessages}
|
||||
inherited={isDefaultSetting('renderMarkdownInUserMessages')}
|
||||
on:change={() => {
|
||||
saveSettings({ renderMarkdownInUserMessages });
|
||||
}}
|
||||
@@ -856,6 +890,7 @@
|
||||
ariaLabelledbyId="render-markdown-assistant-label"
|
||||
tooltip={true}
|
||||
bind:state={renderMarkdownInAssistantMessages}
|
||||
inherited={isDefaultSetting('renderMarkdownInAssistantMessages')}
|
||||
on:change={() => {
|
||||
saveSettings({ renderMarkdownInAssistantMessages });
|
||||
}}
|
||||
@@ -878,6 +913,7 @@
|
||||
ariaLabelledbyId="auto-generation-label"
|
||||
tooltip={true}
|
||||
bind:state={titleAutoGenerate}
|
||||
inherited={isDefaultSetting('titleAutoGenerate')}
|
||||
on:change={() => {
|
||||
toggleTitleAutoGenerate();
|
||||
}}
|
||||
@@ -900,6 +936,7 @@
|
||||
ariaLabelledbyId="follow-up-auto-generation-label"
|
||||
tooltip={true}
|
||||
bind:state={autoFollowUps}
|
||||
inherited={isDefaultSetting('autoFollowUps')}
|
||||
on:change={() => {
|
||||
saveSettings({ autoFollowUps });
|
||||
}}
|
||||
@@ -922,6 +959,7 @@
|
||||
ariaLabelledbyId="chat-tags-label"
|
||||
tooltip={true}
|
||||
bind:state={autoTags}
|
||||
inherited={isDefaultSetting('autoTags')}
|
||||
on:change={() => {
|
||||
saveSettings({ autoTags });
|
||||
}}
|
||||
@@ -944,6 +982,7 @@
|
||||
ariaLabelledbyId="auto-copy-label"
|
||||
tooltip={true}
|
||||
bind:state={responseAutoCopy}
|
||||
inherited={isDefaultSetting('responseAutoCopy')}
|
||||
on:change={() => {
|
||||
toggleResponseAutoCopy();
|
||||
}}
|
||||
@@ -966,6 +1005,7 @@
|
||||
ariaLabelledbyId="response-auto-scroll-label"
|
||||
tooltip={true}
|
||||
bind:state={scrollOnResponseGeneration}
|
||||
inherited={isDefaultSetting('scrollOnResponseGeneration')}
|
||||
on:change={() => {
|
||||
saveSettings({ scrollOnResponseGeneration });
|
||||
}}
|
||||
@@ -988,6 +1028,7 @@
|
||||
ariaLabelledbyId="insert-suggestion-prompt-label"
|
||||
tooltip={true}
|
||||
bind:state={insertSuggestionPrompt}
|
||||
inherited={isDefaultSetting('insertSuggestionPrompt')}
|
||||
on:change={() => {
|
||||
saveSettings({ insertSuggestionPrompt });
|
||||
}}
|
||||
@@ -1010,6 +1051,7 @@
|
||||
ariaLabelledbyId="keep-follow-up-prompts-label"
|
||||
tooltip={true}
|
||||
bind:state={keepFollowUpPrompts}
|
||||
inherited={isDefaultSetting('keepFollowUpPrompts')}
|
||||
on:change={() => {
|
||||
saveSettings({ keepFollowUpPrompts });
|
||||
}}
|
||||
@@ -1032,6 +1074,7 @@
|
||||
ariaLabelledbyId="insert-follow-up-prompt-label"
|
||||
tooltip={true}
|
||||
bind:state={insertFollowUpPrompt}
|
||||
inherited={isDefaultSetting('insertFollowUpPrompt')}
|
||||
on:change={() => {
|
||||
saveSettings({ insertFollowUpPrompt });
|
||||
}}
|
||||
@@ -1054,6 +1097,7 @@
|
||||
ariaLabelledbyId="regenerate-menu-label"
|
||||
tooltip={true}
|
||||
bind:state={regenerateMenu}
|
||||
inherited={isDefaultSetting('regenerateMenu')}
|
||||
on:change={() => {
|
||||
saveSettings({ regenerateMenu });
|
||||
}}
|
||||
@@ -1076,6 +1120,7 @@
|
||||
ariaLabelledbyId="always-collapse-label"
|
||||
tooltip={true}
|
||||
bind:state={collapseCodeBlocks}
|
||||
inherited={isDefaultSetting('collapseCodeBlocks')}
|
||||
on:change={() => {
|
||||
saveSettings({ collapseCodeBlocks });
|
||||
}}
|
||||
@@ -1098,6 +1143,7 @@
|
||||
ariaLabelledbyId="always-expand-label"
|
||||
tooltip={true}
|
||||
bind:state={expandDetails}
|
||||
inherited={isDefaultSetting('expandDetails')}
|
||||
on:change={() => {
|
||||
saveSettings({ expandDetails });
|
||||
}}
|
||||
@@ -1120,6 +1166,7 @@
|
||||
ariaLabelledbyId="render-markdown-in-previews-label"
|
||||
tooltip={true}
|
||||
bind:state={renderMarkdownInPreviews}
|
||||
inherited={isDefaultSetting('renderMarkdownInPreviews')}
|
||||
on:change={() => {
|
||||
saveSettings({ renderMarkdownInPreviews });
|
||||
}}
|
||||
@@ -1142,6 +1189,7 @@
|
||||
ariaLabelledbyId="keep-followup-prompts-label"
|
||||
tooltip={true}
|
||||
bind:state={displayMultiModelResponsesInTabs}
|
||||
inherited={isDefaultSetting('displayMultiModelResponsesInTabs')}
|
||||
on:change={() => {
|
||||
saveSettings({ displayMultiModelResponsesInTabs });
|
||||
}}
|
||||
@@ -1164,6 +1212,7 @@
|
||||
ariaLabelledbyId="scroll-on-branch-change-label"
|
||||
tooltip={true}
|
||||
bind:state={scrollOnBranchChange}
|
||||
inherited={isDefaultSetting('scrollOnBranchChange')}
|
||||
on:change={() => {
|
||||
saveSettings({ scrollOnBranchChange });
|
||||
}}
|
||||
@@ -1186,6 +1235,7 @@
|
||||
ariaLabelledbyId="show-files-on-terminal-select-label"
|
||||
tooltip={true}
|
||||
bind:state={showFilesOnTerminalSelect}
|
||||
inherited={isDefaultSetting('showFilesOnTerminalSelect')}
|
||||
on:change={() => {
|
||||
saveSettings({ showFilesOnTerminalSelect });
|
||||
}}
|
||||
@@ -1208,6 +1258,7 @@
|
||||
ariaLabelledbyId="stylized-pdf-export-label"
|
||||
tooltip={true}
|
||||
bind:state={stylizedPdfExport}
|
||||
inherited={isDefaultSetting('stylizedPdfExport')}
|
||||
on:change={() => {
|
||||
saveSettings({ stylizedPdfExport });
|
||||
}}
|
||||
@@ -1243,6 +1294,7 @@
|
||||
ariaLabelledbyId="floating-action-buttons-label"
|
||||
tooltip={true}
|
||||
bind:state={showFloatingActionButtons}
|
||||
inherited={isDefaultSetting('showFloatingActionButtons')}
|
||||
on:change={() => {
|
||||
saveSettings({ showFloatingActionButtons });
|
||||
}}
|
||||
@@ -1317,6 +1369,7 @@
|
||||
tooltip={true}
|
||||
ariaLabelledbyId="rich-input-label"
|
||||
bind:state={richTextInput}
|
||||
inherited={isDefaultSetting('richTextInput')}
|
||||
on:change={() => {
|
||||
saveSettings({ richTextInput });
|
||||
}}
|
||||
@@ -1340,6 +1393,7 @@
|
||||
ariaLabelledbyId="prompt-autocompletion-label"
|
||||
tooltip={true}
|
||||
bind:state={promptAutocomplete}
|
||||
inherited={isDefaultSetting('promptAutocomplete')}
|
||||
on:change={() => {
|
||||
saveSettings({ promptAutocomplete });
|
||||
}}
|
||||
@@ -1364,6 +1418,7 @@
|
||||
ariaLabelledbyId="show-formatting-toolbar-label"
|
||||
tooltip={true}
|
||||
bind:state={showFormattingToolbar}
|
||||
inherited={isDefaultSetting('showFormattingToolbar')}
|
||||
on:change={() => {
|
||||
saveSettings({ showFormattingToolbar });
|
||||
}}
|
||||
@@ -1386,6 +1441,7 @@
|
||||
ariaLabelledbyId="insert-prompt-as-rich-text-label"
|
||||
tooltip={true}
|
||||
bind:state={insertPromptAsRichText}
|
||||
inherited={isDefaultSetting('insertPromptAsRichText')}
|
||||
on:change={() => {
|
||||
saveSettings({ insertPromptAsRichText });
|
||||
}}
|
||||
@@ -1409,6 +1465,7 @@
|
||||
tooltip={true}
|
||||
ariaLabelledbyId="paste-large-label"
|
||||
bind:state={largeTextAsFile}
|
||||
inherited={isDefaultSetting('largeTextAsFile')}
|
||||
on:change={() => {
|
||||
saveSettings({ largeTextAsFile });
|
||||
}}
|
||||
@@ -1433,6 +1490,7 @@
|
||||
ariaLabelledbyId="detect-artifacts-label"
|
||||
tooltip={true}
|
||||
bind:state={detectArtifacts}
|
||||
inherited={isDefaultSetting('detectArtifacts')}
|
||||
on:change={() => {
|
||||
saveSettings({ detectArtifacts });
|
||||
}}
|
||||
@@ -1455,6 +1513,7 @@
|
||||
ariaLabelledbyId="iframe-sandbox-allow-same-origin-label"
|
||||
tooltip={true}
|
||||
bind:state={iframeSandboxAllowSameOrigin}
|
||||
inherited={isDefaultSetting('iframeSandboxAllowSameOrigin')}
|
||||
on:change={() => {
|
||||
saveSettings({ iframeSandboxAllowSameOrigin });
|
||||
}}
|
||||
@@ -1477,6 +1536,7 @@
|
||||
ariaLabelledbyId="iframe-sandbox-allow-forms-label"
|
||||
tooltip={true}
|
||||
bind:state={iframeSandboxAllowForms}
|
||||
inherited={isDefaultSetting('iframeSandboxAllowForms')}
|
||||
on:change={() => {
|
||||
saveSettings({ iframeSandboxAllowForms });
|
||||
}}
|
||||
@@ -1501,6 +1561,7 @@
|
||||
ariaLabelledbyId="allow-voice-interruption-in-call-label"
|
||||
tooltip={true}
|
||||
bind:state={voiceInterruption}
|
||||
inherited={isDefaultSetting('voiceInterruption')}
|
||||
on:change={() => {
|
||||
saveSettings({ voiceInterruption });
|
||||
}}
|
||||
@@ -1523,6 +1584,7 @@
|
||||
ariaLabelledbyId="display-emoji-label"
|
||||
tooltip={true}
|
||||
bind:state={showEmojiInCall}
|
||||
inherited={isDefaultSetting('showEmojiInCall')}
|
||||
on:change={() => {
|
||||
saveSettings({ showEmojiInCall });
|
||||
}}
|
||||
@@ -1587,6 +1649,7 @@
|
||||
ariaLabelledbyId="image-compression-label"
|
||||
tooltip={true}
|
||||
bind:state={imageCompression}
|
||||
inherited={isDefaultSetting('imageCompression')}
|
||||
on:change={() => {
|
||||
saveSettings({ imageCompression });
|
||||
}}
|
||||
@@ -1610,6 +1673,7 @@
|
||||
ariaLabelledbyId="image-compression-in-channels-label"
|
||||
tooltip={true}
|
||||
bind:state={imageCompressionInChannels}
|
||||
inherited={isDefaultSetting('imageCompressionInChannels')}
|
||||
on:change={() => {
|
||||
saveSettings({ imageCompressionInChannels });
|
||||
}}
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
export let ariaLabelledbyId = '';
|
||||
export let ariaLabel = '';
|
||||
export let tooltip = false;
|
||||
export let inherited = false;
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n: any = getContext('i18n');
|
||||
const dispatch = createEventDispatcher();
|
||||
</script>
|
||||
|
||||
@@ -25,24 +26,30 @@
|
||||
: ''}
|
||||
placement="top"
|
||||
>
|
||||
<Switch.Root
|
||||
bind:checked={state}
|
||||
{id}
|
||||
aria-labelledby={ariaLabelledbyId || undefined}
|
||||
aria-label={ariaLabel || undefined}
|
||||
class="relative h-4 min-h-4 w-7 shrink-0 cursor-pointer rounded-full mx-[0.0625rem] transition-colors duration-150 {($settings?.highContrastMode ??
|
||||
false)
|
||||
? 'focus:outline focus:outline-2 focus:outline-gray-800 focus:dark:outline-gray-200'
|
||||
: 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 dark:focus-visible:outline-gray-500'} {state
|
||||
? 'bg-gray-900 dark:bg-white'
|
||||
: 'bg-gray-300 dark:bg-gray-700'}"
|
||||
onCheckedChange={async () => {
|
||||
await tick();
|
||||
dispatch('change', state);
|
||||
}}
|
||||
>
|
||||
<Switch.Thumb
|
||||
class="pointer-events-none absolute top-[0.125rem] block h-3 w-3 shrink-0 rounded-full transition-all duration-150 data-[state=checked]:left-[0.875rem] data-[state=checked]:bg-white data-[state=checked]:dark:bg-black data-[state=unchecked]:left-[0.125rem] data-[state=unchecked]:bg-white data-[state=unchecked]:dark:bg-gray-500"
|
||||
/>
|
||||
</Switch.Root>
|
||||
<div class="flex items-center gap-1.5">
|
||||
{#if inherited}
|
||||
<span class="text-[0.6875rem] text-gray-400 dark:text-gray-600">{$i18n.t('Default')}</span>
|
||||
{/if}
|
||||
|
||||
<Switch.Root
|
||||
bind:checked={state}
|
||||
{id}
|
||||
aria-labelledby={ariaLabelledbyId || undefined}
|
||||
aria-label={ariaLabel || undefined}
|
||||
class="relative h-4 min-h-4 w-7 shrink-0 cursor-pointer rounded-full mx-[0.0625rem] transition-colors duration-150 {($settings?.highContrastMode ??
|
||||
false)
|
||||
? 'focus:outline focus:outline-2 focus:outline-gray-800 focus:dark:outline-gray-200'
|
||||
: 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 dark:focus-visible:outline-gray-500'} {state
|
||||
? 'bg-gray-900 dark:bg-white'
|
||||
: 'bg-gray-300 dark:bg-gray-700'}"
|
||||
onCheckedChange={async () => {
|
||||
await tick();
|
||||
dispatch('change', state);
|
||||
}}
|
||||
>
|
||||
<Switch.Thumb
|
||||
class="pointer-events-none absolute top-[0.125rem] block h-3 w-3 shrink-0 rounded-full transition-all duration-150 data-[state=checked]:left-[0.875rem] data-[state=checked]:bg-white data-[state=checked]:dark:bg-black data-[state=unchecked]:left-[0.125rem] data-[state=unchecked]:bg-white data-[state=unchecked]:dark:bg-gray-500"
|
||||
/>
|
||||
</Switch.Root>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
Reference in New Issue
Block a user