feat(i18n): Hebrew locale + full RTL support
This commit is contained in:
@@ -36,7 +36,7 @@ function VersionUpdateTag() {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-2 inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-medium align-middle",
|
||||
"ms-2 inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-medium align-middle",
|
||||
important
|
||||
? "bg-red-500/15 text-red-700 dark:text-red-300"
|
||||
: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
@@ -121,7 +121,7 @@ export function AboutDataSettings() {
|
||||
{showGame && <SpamSiegeGame onClose={() => setShowGame(false)} />}
|
||||
<div className="rounded-lg border border-border bg-card p-5 mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<button onClick={handleLogoClick} className="flex items-center gap-4 flex-1 text-left focus:outline-none group/about cursor-pointer" aria-label="About">
|
||||
<button onClick={handleLogoClick} className="flex items-center gap-4 flex-1 text-start focus:outline-none group/about cursor-pointer" aria-label="About">
|
||||
<div className="shrink-0">
|
||||
<img
|
||||
src={`${getPathPrefix()}/branding/Bulwark_Logo_Color.svg`}
|
||||
|
||||
@@ -69,7 +69,7 @@ function PasswordChangeSection() {
|
||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||
required
|
||||
autoComplete="current-password"
|
||||
className="pr-10"
|
||||
className="pe-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -90,7 +90,7 @@ function PasswordChangeSection() {
|
||||
required
|
||||
minLength={8}
|
||||
autoComplete="new-password"
|
||||
className="pr-10"
|
||||
className="pe-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -120,7 +120,7 @@ function PasswordChangeSection() {
|
||||
size="sm"
|
||||
disabled={isSaving || !currentPassword || !newPassword || !confirmPassword}
|
||||
>
|
||||
{isSaving ? <Loader2 className="w-4 h-4 mr-2 animate-spin" /> : null}
|
||||
{isSaving ? <Loader2 className="w-4 h-4 me-2 animate-spin" /> : null}
|
||||
{t('password.submit')}
|
||||
</Button>
|
||||
</form>
|
||||
@@ -294,7 +294,7 @@ function TotpSection() {
|
||||
</SettingItem>
|
||||
|
||||
{setupUrl && (
|
||||
<div className="ml-4 p-3 bg-muted rounded-md space-y-3">
|
||||
<div className="ms-4 p-3 bg-muted rounded-md space-y-3">
|
||||
<p className="text-xs text-muted-foreground">{t('totp.setup_instructions')}</p>
|
||||
{qrDataUrl && (
|
||||
<div className="flex justify-center">
|
||||
@@ -315,7 +315,7 @@ function TotpSection() {
|
||||
{setupError && <p className="text-xs text-destructive">{setupError}</p>}
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" onClick={confirmSetup} disabled={isSaving || !password || !otpCode}>
|
||||
{isSaving ? <Loader2 className="w-4 h-4 mr-1 animate-spin" /> : null}
|
||||
{isSaving ? <Loader2 className="w-4 h-4 me-1 animate-spin" /> : null}
|
||||
{t('totp.confirm')}
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" onClick={cancelSetup}>{t('app_passwords.cancel')}</Button>
|
||||
@@ -324,7 +324,7 @@ function TotpSection() {
|
||||
)}
|
||||
|
||||
{disableOpen && (
|
||||
<div className="ml-4 p-3 bg-muted rounded-md space-y-2">
|
||||
<div className="ms-4 p-3 bg-muted rounded-md space-y-2">
|
||||
<p className="text-xs text-muted-foreground">{t('totp.disable_confirm_prompt')}</p>
|
||||
<Input
|
||||
type="password"
|
||||
@@ -336,7 +336,7 @@ function TotpSection() {
|
||||
{setupError && <p className="text-xs text-destructive">{setupError}</p>}
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="destructive" onClick={handleDisable} disabled={isSaving || !password}>
|
||||
{isSaving ? <Loader2 className="w-4 h-4 mr-1 animate-spin" /> : null}
|
||||
{isSaving ? <Loader2 className="w-4 h-4 me-1 animate-spin" /> : null}
|
||||
{t('totp.disable')}
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" onClick={() => { setDisableOpen(false); setPassword(''); setSetupError(null); }}>
|
||||
@@ -470,7 +470,7 @@ function CredentialSection({ icon: Icon, i18nNamespace, entries, onCreate, onRem
|
||||
<h4 className="text-sm font-medium text-foreground">{tk('title')}</h4>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onClick={() => setShowAdd(!showAdd)}>
|
||||
<Plus className="w-3 h-3 mr-1" />
|
||||
<Plus className="w-3 h-3 me-1" />
|
||||
{t('app_passwords.add')}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -521,7 +521,7 @@ function CredentialSection({ icon: Icon, i18nNamespace, entries, onCreate, onRem
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button type="submit" size="sm" disabled={isSaving || !newDescription.trim()}>
|
||||
{isSaving ? <Loader2 className="w-4 h-4 mr-1 animate-spin" /> : null}
|
||||
{isSaving ? <Loader2 className="w-4 h-4 me-1 animate-spin" /> : null}
|
||||
{t('app_passwords.create')}
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" size="sm" onClick={() => setShowAdd(false)}>
|
||||
@@ -768,9 +768,9 @@ function LinkDeviceSection() {
|
||||
|
||||
<Button variant="outline" size="sm" onClick={() => void generate()} disabled={loading}>
|
||||
{loading ? (
|
||||
<Loader2 className="w-3 h-3 mr-1 animate-spin" />
|
||||
<Loader2 className="w-3 h-3 me-1 animate-spin" />
|
||||
) : (
|
||||
<QrCode className="w-3 h-3 mr-1" />
|
||||
<QrCode className="w-3 h-3 me-1" />
|
||||
)}
|
||||
{hasGenerated ? t('link_device.regenerate') : t('link_device.generate')}
|
||||
</Button>
|
||||
|
||||
@@ -223,7 +223,7 @@ export function AccountSettings() {
|
||||
onClick={handleAddAccount}
|
||||
className="w-full"
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
<Plus className="w-4 h-4 me-2" />
|
||||
{t('accounts.add')}
|
||||
</Button>
|
||||
)}
|
||||
@@ -245,7 +245,7 @@ export function AccountSettings() {
|
||||
onClick={() => handleManageShared(acc)}
|
||||
disabled={!editable}
|
||||
className={cn(
|
||||
'flex items-center gap-3 w-full p-3 border border-border rounded-lg text-left transition-colors',
|
||||
'flex items-center gap-3 w-full p-3 border border-border rounded-lg text-start transition-colors',
|
||||
editable ? 'hover:bg-muted/50 cursor-pointer' : 'opacity-60 cursor-not-allowed',
|
||||
)}
|
||||
>
|
||||
@@ -359,7 +359,7 @@ function AccountRow({
|
||||
onClick={onSwitch}
|
||||
disabled={isActive}
|
||||
className={cn(
|
||||
'min-w-0 flex-1 text-left',
|
||||
'min-w-0 flex-1 text-start',
|
||||
!isActive && 'cursor-pointer'
|
||||
)}
|
||||
title={isActive ? labels.active : labels.switchTo}
|
||||
|
||||
@@ -141,7 +141,7 @@ export function AppearanceSettings() {
|
||||
onClick={() => { resetTourCompletion(); startTour(); }}
|
||||
className="text-xs h-7"
|
||||
>
|
||||
<PlayCircle className="w-3.5 h-3.5 mr-1" />
|
||||
<PlayCircle className="w-3.5 h-3.5 me-1" />
|
||||
{tTour('restart_button')}
|
||||
</Button>
|
||||
</SettingItem>
|
||||
|
||||
@@ -23,6 +23,7 @@ export function ComposingSettings() {
|
||||
const {
|
||||
autoSelectReplyIdentity,
|
||||
plainTextMode,
|
||||
rtlEditingSupport,
|
||||
attachmentReminderEnabled,
|
||||
attachmentReminderKeywords,
|
||||
sendDelaySeconds,
|
||||
@@ -52,6 +53,13 @@ export function ComposingSettings() {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('rtl_editing.label')} description={t('rtl_editing.description')}>
|
||||
<ToggleSwitch
|
||||
checked={rtlEditingSupport}
|
||||
onChange={(checked) => updateSetting('rtlEditingSupport', checked)}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('send_delay.label')} description={t('send_delay.description')}>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<Select
|
||||
@@ -65,7 +73,7 @@ export function ComposingSettings() {
|
||||
]}
|
||||
/>
|
||||
{sendDelaySeconds > 0 && !delayedSendSupported && (
|
||||
<p className="max-w-64 text-right text-xs text-amber-600 dark:text-amber-400">{t('send_delay.unsupported')}</p>
|
||||
<p className="max-w-64 text-end text-xs text-amber-600 dark:text-amber-400">{t('send_delay.unsupported')}</p>
|
||||
)}
|
||||
</div>
|
||||
</SettingItem>
|
||||
|
||||
@@ -73,7 +73,7 @@ export function ContactsSettings() {
|
||||
description={tSettings("import_description")}
|
||||
>
|
||||
<Button variant="outline" size="sm" onClick={() => setShowImport(true)}>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
<Upload className="w-4 h-4 me-2" />
|
||||
{t("import.title")}
|
||||
</Button>
|
||||
</SettingItem>
|
||||
@@ -88,7 +88,7 @@ export function ContactsSettings() {
|
||||
onClick={handleExport}
|
||||
disabled={individuals.length === 0}
|
||||
>
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
<Download className="w-4 h-4 me-2" />
|
||||
{t("export.title")}
|
||||
</Button>
|
||||
</SettingItem>
|
||||
|
||||
@@ -25,7 +25,7 @@ export function DebugSettings() {
|
||||
</SettingItem>
|
||||
|
||||
{debugMode && (
|
||||
<div className="ml-4 border-l-2 border-muted pl-4 space-y-1">
|
||||
<div className="ms-4 border-s-2 border-muted ps-4 space-y-1">
|
||||
<p className="text-xs text-muted-foreground mb-2">{t('debug_categories.description')}</p>
|
||||
{ALL_DEBUG_CATEGORIES.map((cat) => (
|
||||
<SettingItem
|
||||
|
||||
@@ -84,8 +84,8 @@ function FilesSettingsPreview({ settings }: { settings: FilesSettings }) {
|
||||
<div className="flex-1 min-w-0 overflow-hidden">
|
||||
<div className="flex items-center gap-3 px-2 py-1 text-[10px] font-medium text-muted-foreground border-b border-border bg-muted/50">
|
||||
<span className="flex-1 min-w-0">Name</span>
|
||||
<span className="w-14 text-right">Size</span>
|
||||
<span className="w-16 text-right">Modified</span>
|
||||
<span className="w-14 text-end">Size</span>
|
||||
<span className="w-16 text-end">Modified</span>
|
||||
</div>
|
||||
{sortedFiles.map((file) => (
|
||||
<div
|
||||
@@ -103,10 +103,10 @@ function FilesSettingsPreview({ settings }: { settings: FilesSettings }) {
|
||||
<span className={cn("flex-1 min-w-0 truncate text-[11px]", file.isFolder && "font-medium")}>
|
||||
{file.name}
|
||||
</span>
|
||||
<span className="w-14 text-right text-[10px] text-muted-foreground tabular-nums">
|
||||
<span className="w-14 text-end text-[10px] text-muted-foreground tabular-nums">
|
||||
{formatSize(file.size)}
|
||||
</span>
|
||||
<span className="w-16 text-right text-[10px] text-muted-foreground tabular-nums">
|
||||
<span className="w-16 text-end text-[10px] text-muted-foreground tabular-nums">
|
||||
{file.modified.slice(5)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -142,7 +142,7 @@ function FilesSettingsPreview({ settings }: { settings: FilesSettings }) {
|
||||
);
|
||||
|
||||
const sidebar = settings.folderLayout === "sidebar" && (
|
||||
<div className="w-24 border-r border-border bg-muted/30 py-1.5 flex-shrink-0">
|
||||
<div className="w-24 border-e border-border bg-muted/30 py-1.5 flex-shrink-0">
|
||||
<div className="flex items-center gap-1 px-2 py-0.5 text-[10px] font-medium text-foreground">
|
||||
<Home className="w-3 h-3 flex-shrink-0" />
|
||||
<span className="truncate">Files</span>
|
||||
|
||||
@@ -487,7 +487,7 @@ export function FilterSettings() {
|
||||
try { localStorage.setItem('settings-active-tab', 'vacation'); } catch { /* ignore */ }
|
||||
window.dispatchEvent(new CustomEvent('settings-tab-change', { detail: 'vacation' }));
|
||||
}}
|
||||
className="flex items-center gap-3 w-full p-3 rounded-md border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 hover:bg-green-100 dark:hover:bg-green-900/30 transition-colors text-left"
|
||||
className="flex items-center gap-3 w-full p-3 rounded-md border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 hover:bg-green-100 dark:hover:bg-green-900/30 transition-colors text-start"
|
||||
>
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-green-100 dark:bg-green-900/40">
|
||||
<PalmtreeIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
||||
@@ -661,7 +661,7 @@ export function FilterSettings() {
|
||||
setShowRuleModal(true);
|
||||
}}
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-1" />
|
||||
<Plus className="w-4 h-4 me-1" />
|
||||
{t("add_rule")}
|
||||
</Button>
|
||||
)}
|
||||
@@ -670,7 +670,7 @@ export function FilterSettings() {
|
||||
size="sm"
|
||||
onClick={() => setShowSieveEditor(true)}
|
||||
>
|
||||
<Code className="w-4 h-4 mr-1" />
|
||||
<Code className="w-4 h-4 me-1" />
|
||||
{t("raw_editor")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -57,7 +57,7 @@ export function LanguageSettings() {
|
||||
{ value: 'full', label: t('date_format.full') },
|
||||
]}
|
||||
/>
|
||||
<div className="text-xs text-muted-foreground text-right space-y-0.5 font-mono">
|
||||
<div className="text-xs text-muted-foreground text-end space-y-0.5 font-mono">
|
||||
<div>
|
||||
<span className="opacity-70">{t('date_format.preview_today')} </span>
|
||||
<span className="text-foreground/90">{preview.today}</span>
|
||||
|
||||
@@ -38,11 +38,11 @@ function MailLayoutPreview({
|
||||
|
||||
<div className="mt-3 overflow-hidden rounded-lg border border-border bg-muted/20">
|
||||
<div className="flex h-28">
|
||||
<div className="w-11 border-r border-border bg-muted/40" />
|
||||
<div className="w-11 border-e border-border bg-muted/40" />
|
||||
|
||||
{value === 'split' && (
|
||||
<>
|
||||
<div className="w-28 border-r border-border bg-background">
|
||||
<div className="w-28 border-e border-border bg-background">
|
||||
{MAIL_LAYOUT_PREVIEW_ROWS.map((row) => (
|
||||
<div
|
||||
key={row.subject}
|
||||
@@ -245,7 +245,7 @@ export function LayoutSettings() {
|
||||
)}
|
||||
|
||||
{enableUnifiedMailbox && hasGroupInboxes && !isSettingHidden('includeGroupInUnified') && (
|
||||
<div className="ml-4 border-l-2 border-border pl-4 -mt-2">
|
||||
<div className="ms-4 border-s-2 border-border ps-4 -mt-2">
|
||||
<SettingItem
|
||||
label={t('unified_mailbox.include_group.label')}
|
||||
description={t('unified_mailbox.include_group.description')}
|
||||
@@ -260,7 +260,7 @@ export function LayoutSettings() {
|
||||
)}
|
||||
|
||||
{enableUnifiedMailbox && crossViews.some(c => c.allowed) && (
|
||||
<div className="ml-4 border-l-2 border-border pl-4 -mt-2 space-y-2">
|
||||
<div className="ms-4 border-s-2 border-border ps-4 -mt-2 space-y-2">
|
||||
{crossViews.map(({ setting, value, allowed, labelKey, descKey }) => (
|
||||
allowed && !isSettingHidden(setting) && (
|
||||
<SettingItem
|
||||
@@ -293,7 +293,7 @@ export function LayoutSettings() {
|
||||
)}
|
||||
|
||||
{allMailViewAllowed && enableAllMailView && (
|
||||
<div className="ml-4 border-l-2 border-border pl-4 -mt-2 space-y-2">
|
||||
<div className="ms-4 border-s-2 border-border ps-4 -mt-2 space-y-2">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-foreground">{t('all_mail.folders_label')}</div>
|
||||
<div className="text-xs text-muted-foreground">{t('all_mail.folders_description')}</div>
|
||||
@@ -312,7 +312,7 @@ export function LayoutSettings() {
|
||||
key={mb.id}
|
||||
type="button"
|
||||
onClick={() => toggleAllMailFolder(mb.id)}
|
||||
className="w-full flex items-center gap-2.5 py-1.5 px-2 rounded-md hover:bg-muted/50 text-left"
|
||||
className="w-full flex items-center gap-2.5 py-1.5 px-2 rounded-md hover:bg-muted/50 text-start"
|
||||
role="checkbox"
|
||||
aria-checked={checked}
|
||||
>
|
||||
|
||||
@@ -35,7 +35,7 @@ export function SettingItem({ label, description, children, locked }: SettingIte
|
||||
data-search-label={label}
|
||||
className={cn("flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4 py-3 border-b border-border last:border-0", locked && "opacity-60")}
|
||||
>
|
||||
<div className="flex-1 min-w-0 sm:pr-4">
|
||||
<div className="flex-1 min-w-0 sm:pe-4">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<label className="text-sm font-medium text-foreground">{label}</label>
|
||||
{locked && <Lock className="w-3 h-3 text-muted-foreground" aria-label="Managed by administrator" />}
|
||||
@@ -72,7 +72,7 @@ export function ToggleSwitch({ checked, onChange, disabled }: ToggleSwitchProps)
|
||||
<span
|
||||
className={cn(
|
||||
'inline-block h-4 w-4 transform rounded-full bg-background transition-transform duration-150',
|
||||
checked ? 'translate-x-6' : 'translate-x-1'
|
||||
checked ? 'ltr:translate-x-6 rtl:-translate-x-6' : 'ltr:translate-x-1 rtl:-translate-x-1'
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -284,7 +284,7 @@ export function ShareCollectionDialog({
|
||||
value={preset}
|
||||
onChange={(e) => handleSetRights(principalId, e.target.value as RolePreset)}
|
||||
disabled={savingId === principalId}
|
||||
className="appearance-none rounded-md border border-input bg-background pl-3 pr-8 py-1.5 text-xs focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50"
|
||||
className="appearance-none rounded-md border border-input bg-background ps-3 pe-8 py-1.5 text-xs focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50"
|
||||
>
|
||||
{presetOptions.map((p) => (
|
||||
<option key={p} value={p}>{t(`preset.${p}`)}</option>
|
||||
@@ -318,7 +318,7 @@ export function ShareCollectionDialog({
|
||||
onClick={() => setShowAdd(true)}
|
||||
className="w-full"
|
||||
>
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
<UserPlus className="w-4 h-4 me-2" />
|
||||
{t("add_person")}
|
||||
</Button>
|
||||
)}
|
||||
@@ -336,7 +336,7 @@ export function ShareCollectionDialog({
|
||||
<div className="max-h-48 overflow-y-auto -mx-1">
|
||||
{loadingPrincipals && (
|
||||
<div className="flex items-center justify-center py-4 text-muted-foreground">
|
||||
<Loader2 className="w-4 h-4 animate-spin mr-2" />
|
||||
<Loader2 className="w-4 h-4 animate-spin me-2" />
|
||||
{t("loading_principals")}
|
||||
</div>
|
||||
)}
|
||||
@@ -350,7 +350,7 @@ export function ShareCollectionDialog({
|
||||
key={p.id}
|
||||
onClick={() => handleAdd(p)}
|
||||
disabled={savingId === p.id}
|
||||
className="w-full text-left px-3 py-2 rounded-md hover:bg-muted disabled:opacity-50 transition-colors"
|
||||
className="w-full text-start px-3 py-2 rounded-md hover:bg-muted disabled:opacity-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar
|
||||
|
||||
@@ -330,7 +330,7 @@ export function SidebarAppsSettings() {
|
||||
onClick={() => setShowAddForm(true)}
|
||||
className="w-full"
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
<Plus className="w-4 h-4 me-2" />
|
||||
{tApps("add_new")}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -304,7 +304,7 @@ export function SpamSiegeGame({ onClose }: { onClose: () => void }) {
|
||||
Close
|
||||
</Button>
|
||||
<Button size="sm" onClick={startGame}>
|
||||
<RotateCcw className="w-3.5 h-3.5 mr-1.5" />
|
||||
<RotateCcw className="w-3.5 h-3.5 me-1.5" />
|
||||
Again
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -104,7 +104,7 @@ export function TemplateSettings() {
|
||||
onClick={handleExport}
|
||||
disabled={templates.length === 0}
|
||||
>
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
<Download className="w-4 h-4 me-1" />
|
||||
{t('export')}
|
||||
</Button>
|
||||
<div>
|
||||
@@ -120,7 +120,7 @@ export function TemplateSettings() {
|
||||
size="sm"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<Upload className="w-4 h-4 mr-1" />
|
||||
<Upload className="w-4 h-4 me-1" />
|
||||
{t('import')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -139,7 +139,7 @@ function ThemeCard({ name, author, preview, css, isDark, isDefaultTheme, isActiv
|
||||
onClick={onActivate}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
'flex flex-col items-center p-3 rounded-xl border-2 transition-all text-left w-full disabled:cursor-not-allowed disabled:opacity-60',
|
||||
'flex flex-col items-center p-3 rounded-xl border-2 transition-all text-start w-full disabled:cursor-not-allowed disabled:opacity-60',
|
||||
isActive
|
||||
? 'border-primary bg-primary/5 ring-1 ring-primary/20'
|
||||
: 'border-border hover:border-primary/40 bg-card',
|
||||
|
||||
@@ -258,7 +258,7 @@ export function VacationSettings() {
|
||||
>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||
<Loader2 className="w-4 h-4 me-2 animate-spin" />
|
||||
{t('saving')}
|
||||
</>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user