mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-04 22:40:11 +00:00
feat: add offline mode notice and related styles to enhance user experience during offline access
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useState } from 'preact/hooks';
|
||||
import { ArrowLeft, Eye, EyeOff, KeyRound, LogIn, LogOut, Unlock, UserPlus } from 'lucide-preact';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import { AlertTriangle, ArrowLeft, Eye, EyeOff, KeyRound, LogIn, LogOut, Unlock, UserPlus } from 'lucide-preact';
|
||||
import NetworkStatusBadge from '@/components/NetworkStatusBadge';
|
||||
import StandalonePageFrame from '@/components/StandalonePageFrame';
|
||||
import { t } from '@/lib/i18n';
|
||||
import { getCurrentNetworkStatus, subscribeNetworkStatus, type NetworkStatus } from '@/lib/network-status';
|
||||
|
||||
interface LoginValues {
|
||||
email: string;
|
||||
@@ -81,6 +82,36 @@ function PasswordField(props: {
|
||||
);
|
||||
}
|
||||
|
||||
function OfflineModeNotice() {
|
||||
const [status, setStatus] = useState<NetworkStatus>(getCurrentNetworkStatus);
|
||||
|
||||
useEffect(() => subscribeNetworkStatus(setStatus), []);
|
||||
|
||||
if (status !== 'offline') return null;
|
||||
|
||||
return (
|
||||
<div className="offline-mode-notice" role="alert" aria-live="assertive">
|
||||
<div>
|
||||
<strong>{t('txt_offline_mode_notice_title')}</strong>
|
||||
<div className="offline-shortcut-list">
|
||||
<div className="offline-shortcut-row">
|
||||
<span className="offline-shortcut-label">{t('txt_offline_mode_notice_windows')}</span>
|
||||
<span className="offline-shortcut-value">
|
||||
<span className="offline-shortcut-chord"><kbd>Ctrl</kbd><span>+</span><kbd>F5</kbd></span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="offline-shortcut-row">
|
||||
<span className="offline-shortcut-label">{t('txt_offline_mode_notice_macos')}</span>
|
||||
<span className="offline-shortcut-value">
|
||||
<span className="offline-shortcut-chord"><kbd>Command</kbd><span>+</span><kbd>Shift</kbd><span>+</span><kbd>R</kbd></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AuthViews(props: AuthViewsProps) {
|
||||
const loginBusy = props.pendingAction === 'login';
|
||||
const passkeyBusy = props.pendingAction === 'passkey';
|
||||
@@ -99,6 +130,7 @@ export default function AuthViews(props: AuthViewsProps) {
|
||||
props.onSubmitUnlock();
|
||||
}}
|
||||
>
|
||||
<OfflineModeNotice />
|
||||
<p className="muted standalone-muted">{props.emailForLock}</p>
|
||||
<input type="text" value={props.emailForLock} autoComplete="username" readOnly hidden tabIndex={-1} aria-hidden="true" />
|
||||
<PasswordField
|
||||
@@ -245,6 +277,7 @@ export default function AuthViews(props: AuthViewsProps) {
|
||||
props.onSubmitLogin();
|
||||
}}
|
||||
>
|
||||
<OfflineModeNotice />
|
||||
{passkeyPasswordPending ? (
|
||||
<>
|
||||
<p className="muted standalone-muted">{props.pendingPasskeyPasswordEmail}</p>
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const en: Record<string, string> = {
|
||||
"txt_online": "Online",
|
||||
"txt_offline": "Offline",
|
||||
"txt_offline_vault_readonly": "Offline mode is read-only. Connect to NodeWarden before changing your vault.",
|
||||
"txt_offline_mode_notice_title": "You are in offline mode. If this looks wrong, force refresh.",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "Submit",
|
||||
"txt_sync": "Sync",
|
||||
"txt_sync_vault": "Sync Vault",
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const es: Record<string, string> = {
|
||||
"txt_online": "En línea",
|
||||
"txt_offline": "Sin conexión",
|
||||
"txt_offline_vault_readonly": "El modo sin conexión es de solo lectura. Conecta con NodeWarden antes de cambiar la bóveda.",
|
||||
"txt_offline_mode_notice_title": "Estás en modo sin conexión. Si parece un error, fuerza la recarga.",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "Enviar",
|
||||
"txt_sync": "Sincronizar",
|
||||
"txt_sync_vault": "Sincronizar bóveda",
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const fi: Record<string, string> = {
|
||||
"txt_online": "Verkossa",
|
||||
"txt_offline": "Offline",
|
||||
"txt_offline_vault_readonly": "Offline-tila on vain luku -muodossa. Yhdistä NodeWardeniin ennen kuin muutat holviasi.",
|
||||
"txt_offline_mode_notice_title": "Olet offline-tilassa. Jos tämä vaikuttaa virheeltä, tee pakotettu päivitys.",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "Lähetä",
|
||||
"txt_sync": "Synkronoi",
|
||||
"txt_sync_vault": "Synkronoi holvi",
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const ru: Record<string, string> = {
|
||||
"txt_online": "Онлайн",
|
||||
"txt_offline": "Офлайн",
|
||||
"txt_offline_vault_readonly": "Автономный режим доступен только для чтения. Подключитесь к NodeWarden, чтобы изменить хранилище.",
|
||||
"txt_offline_mode_notice_title": "Вы в автономном режиме. Если это ошибка, выполните принудительное обновление.",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "Отправить",
|
||||
"txt_sync": "Синхронизировать",
|
||||
"txt_sync_vault": "Синхронизировать хранилище",
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const zhCN: Record<string, string> = {
|
||||
"txt_online": "在线",
|
||||
"txt_offline": "离线",
|
||||
"txt_offline_vault_readonly": "当前为离线模式,只能查看密码库。连接到 NodeWarden 后才能修改。",
|
||||
"txt_offline_mode_notice_title": "你正处于离线模式,若误判请强制刷新",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "提交",
|
||||
"txt_sync": "同步",
|
||||
"txt_sync_vault": "同步",
|
||||
|
||||
@@ -1012,6 +1012,9 @@ const zhTW: Record<string, string> = {
|
||||
"txt_online": "在線",
|
||||
"txt_offline": "離線",
|
||||
"txt_offline_vault_readonly": "目前為離線模式,只能查看密碼庫。連線到 NodeWarden 後才能修改。",
|
||||
"txt_offline_mode_notice_title": "你正處於離線模式,若誤判請強制重新整理",
|
||||
"txt_offline_mode_notice_windows": "Windows:",
|
||||
"txt_offline_mode_notice_macos": "macOS:",
|
||||
"txt_submit": "提交",
|
||||
"txt_sync": "同步",
|
||||
"txt_sync_vault": "同步",
|
||||
|
||||
@@ -492,6 +492,58 @@
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.offline-mode-notice {
|
||||
@apply mb-4 flex items-start gap-3 rounded-xl border px-3.5 py-3 text-left text-sm leading-relaxed;
|
||||
background: color-mix(in srgb, var(--warning) 10%, var(--panel));
|
||||
border-color: color-mix(in srgb, var(--warning) 42%, var(--line));
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.offline-mode-notice svg {
|
||||
@apply mt-0.5 shrink-0;
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.offline-mode-notice strong {
|
||||
@apply block text-center text-[13px] font-extrabold;
|
||||
color: color-mix(in srgb, var(--warning) 82%, var(--text));
|
||||
}
|
||||
|
||||
.offline-mode-notice > div {
|
||||
@apply min-w-0 flex-1;
|
||||
}
|
||||
|
||||
.offline-shortcut-list {
|
||||
@apply mt-2 grid gap-1.5;
|
||||
grid-template-columns: max-content minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.offline-shortcut-row {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.offline-shortcut-label {
|
||||
@apply text-xs font-extrabold;
|
||||
color: color-mix(in srgb, var(--warning) 76%, var(--text));
|
||||
}
|
||||
|
||||
.offline-shortcut-value {
|
||||
@apply flex min-w-0 flex-wrap items-center gap-1.5;
|
||||
color: var(--muted-strong);
|
||||
}
|
||||
|
||||
.offline-shortcut-chord {
|
||||
@apply inline-flex items-center gap-1 whitespace-nowrap;
|
||||
}
|
||||
|
||||
.offline-shortcut-chord kbd {
|
||||
@apply inline-flex min-h-6 items-center rounded-md border px-1.5 font-mono text-[12px] font-bold leading-none;
|
||||
background: color-mix(in srgb, var(--panel) 88%, var(--warning));
|
||||
border-color: color-mix(in srgb, var(--warning) 35%, var(--line));
|
||||
box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--warning) 26%, transparent);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.standalone-muted {
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user