feat: enhance backup and download functionalities

- Updated `BackupCenterPage` to support download progress tracking during remote backup downloads.
- Modified `ImportPage` to simplify export functionality by removing unnecessary payload handling.
- Improved `JwtWarningPage` to utilize a new clipboard utility for copying text with feedback.
- Enhanced `PublicSendPage` to show download progress for files being downloaded.
- Updated `RecoverTwoFactorPage` to include autocomplete attributes for better user experience.
- Refactored `SendsPage` to use the new clipboard utility for copying access URLs.
- Enhanced `SettingsPage` to utilize the clipboard utility for copying sensitive information.
- Improved `TotpCodesPage` to use the clipboard utility for copying TOTP codes.
- Updated `VaultPage` and related components to support download progress for attachments.
- Introduced a new `app-notify` module for consistent notification handling across the application.
- Created a `clipboard` utility for improved clipboard interactions with user feedback.
- Added progress tracking for file downloads in the API layer, enhancing user experience during downloads.
This commit is contained in:
shuaiplus
2026-03-15 23:12:45 +08:00
parent 9820c2ed44
commit 4b8cad6d00
33 changed files with 387 additions and 121 deletions
+11
View File
@@ -39,6 +39,7 @@ function PasswordField(props: {
value: string;
onInput: (v: string) => void;
autoFocus?: boolean;
autoComplete?: string;
}) {
const [show, setShow] = useState(false);
return (
@@ -51,6 +52,7 @@ function PasswordField(props: {
value={props.value}
onInput={(e) => props.onInput((e.currentTarget as HTMLInputElement).value)}
autoFocus={props.autoFocus}
autoComplete={props.autoComplete}
/>
<button type="button" className="eye-btn" onClick={() => setShow((v) => !v)}>
{show ? <EyeOff size={16} /> : <Eye size={16} />}
@@ -76,10 +78,12 @@ export default function AuthViews(props: AuthViewsProps) {
}}
>
<p className="muted standalone-muted">{props.emailForLock}</p>
<input type="text" value={props.emailForLock} autoComplete="username" readOnly hidden tabIndex={-1} aria-hidden="true" />
<PasswordField
label={t('txt_master_password')}
value={props.unlockPassword}
autoFocus
autoComplete="current-password"
onInput={props.onChangeUnlock}
/>
<button type="submit" className="btn btn-primary full" disabled={unlockBusy}>
@@ -112,6 +116,7 @@ export default function AuthViews(props: AuthViewsProps) {
<input
className="input"
value={props.registerValues.name}
autoComplete="name"
onInput={(e) =>
props.onChangeRegister({ ...props.registerValues, name: (e.currentTarget as HTMLInputElement).value })
}
@@ -123,6 +128,7 @@ export default function AuthViews(props: AuthViewsProps) {
className="input"
type="email"
value={props.registerValues.email}
autoComplete="email"
onInput={(e) =>
props.onChangeRegister({ ...props.registerValues, email: (e.currentTarget as HTMLInputElement).value })
}
@@ -131,11 +137,13 @@ export default function AuthViews(props: AuthViewsProps) {
<PasswordField
label={t('txt_master_password')}
value={props.registerValues.password}
autoComplete="new-password"
onInput={(v) => props.onChangeRegister({ ...props.registerValues, password: v })}
/>
<PasswordField
label={t('txt_confirm_master_password')}
value={props.registerValues.password2}
autoComplete="new-password"
onInput={(v) => props.onChangeRegister({ ...props.registerValues, password2: v })}
/>
<label className="field">
@@ -143,6 +151,7 @@ export default function AuthViews(props: AuthViewsProps) {
<input
className="input"
value={props.registerValues.inviteCode}
autoComplete="off"
onInput={(e) =>
props.onChangeRegister({ ...props.registerValues, inviteCode: (e.currentTarget as HTMLInputElement).value })
}
@@ -178,12 +187,14 @@ export default function AuthViews(props: AuthViewsProps) {
className="input"
type="email"
value={props.loginValues.email}
autoComplete="username"
onInput={(e) => props.onChangeLogin({ ...props.loginValues, email: (e.currentTarget as HTMLInputElement).value })}
/>
</label>
<PasswordField
label={t('txt_master_password')}
value={props.loginValues.password}
autoComplete="current-password"
onInput={(v) => props.onChangeLogin({ ...props.loginValues, password: v })}
autoFocus
/>