fix(files): an upload is said once in any order, copy buttons speak, a link list that failed says so
- The queue holds an upload it sees land done while this tab's upload still waits for its answer, so the dialog's notice is the only one whichever comes first; another device's upload follows after. - One `useCopyFeedback` for every Copy beside a value (token, share link, set-password link): Copied for a moment, a notice a screen reader hears, a warning when the clipboard refuses; the token dialog's two Copy buttons are named by what they copy. - The share dialog's link list shows loading, and a load error with Retry, never "no links" — and no New link beside a list it has not seen. - The settings texts say that signing out elsewhere or a password change revokes the API tokens. - DESIGN.md logs the folder-link decisions; the design lab keeps only the chosen renderings of the Links, Tokens and Files rounds.
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { copyText } from "../lib/clipboard";
|
||||
import { notify } from "../lib/notifications";
|
||||
|
||||
// How long a Copy button reads "Copied" after it worked.
|
||||
const COPIED_MS = 2000;
|
||||
|
||||
/** The feedback of a Copy button that sits beside the value it copies (a token, a share link, a
|
||||
* set-password link), the same at every such button: it reads "Copied" for a moment, and a notice
|
||||
* says it too — the notices are a live region, so a screen reader hears what a swapped label would
|
||||
* not tell it. A copy that failed is a warning, not an error: the value is on screen and
|
||||
* selectable, so it is a convenience that failed, not the action.
|
||||
*
|
||||
* A feature file, not `ui/`: it speaks the app's notifications (as `copyItems` does). */
|
||||
export function useCopyFeedback(): { copied: boolean; copy: (value: string) => Promise<void> } {
|
||||
const { t } = useTranslation();
|
||||
const [copied, setCopied] = useState(false);
|
||||
const copy = async (value: string) => {
|
||||
if (await copyText(value)) {
|
||||
setCopied(true);
|
||||
notify({ level: "success", message: t("common.copy.done") });
|
||||
window.setTimeout(() => setCopied(false), COPIED_MS);
|
||||
return;
|
||||
}
|
||||
notify({ level: "warning", message: t("common.copy.failed") });
|
||||
};
|
||||
return { copied, copy };
|
||||
}
|
||||
Reference in New Issue
Block a user