mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-07-05 04:21:50 +02:00
b1f1363502
Show a one-time toast asking how a feature is working after its third successful use, with an optional comment sent anonymously to the Yaak API (feature key, text, app version, and OS only — nothing identifying, and nothing is sent unless the user clicks Send). - New cmd_send_feedback Tauri command posts fire-and-forget via the shared API client (localhost in dev) - Feature keys registry (cookie-editor, response-history, sse-summary, git-sync) with per-feature use counting in the key-value store - "Never ask for feedback" setting to disable prompts entirely - Toast gains dynamicHeight and hideDismiss props for richer content - Fix missing vertical padding on xs/2xs multiline inputs - Fix unused-import and dead-code warnings in yaak-system-appearance on non-Linux builds Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import { atom } from "jotai";
|
|
import type { ToastInstance } from "../components/Toasts";
|
|
import { generateId } from "./generateId";
|
|
import { jotaiStore } from "./jotai";
|
|
|
|
export const toastsAtom = atom<ToastInstance[]>([]);
|
|
|
|
export function showToast({
|
|
id,
|
|
timeout = 5000,
|
|
...props
|
|
}: Omit<ToastInstance, "id" | "timeout" | "uniqueKey"> & {
|
|
id?: ToastInstance["id"];
|
|
timeout?: ToastInstance["timeout"];
|
|
}) {
|
|
id = id ?? generateId();
|
|
const uniqueKey = generateId();
|
|
|
|
const toasts = jotaiStore.get(toastsAtom);
|
|
const toastWithSameId = toasts.find((t) => t.id === id);
|
|
|
|
let delay = 0;
|
|
if (toastWithSameId) {
|
|
hideToast(toastWithSameId);
|
|
// Allow enough time for old toast to animate out
|
|
delay = 200;
|
|
}
|
|
|
|
setTimeout(() => {
|
|
const newToast: ToastInstance = { id, uniqueKey, timeout, ...props };
|
|
if (timeout != null) {
|
|
setTimeout(() => hideToast(newToast), timeout);
|
|
}
|
|
jotaiStore.set(toastsAtom, (prev) => [...prev, newToast]);
|
|
}, delay);
|
|
|
|
return id;
|
|
}
|
|
|
|
export function hideToastById(id: string) {
|
|
const toast = jotaiStore.get(toastsAtom).find((t) => t.id === id);
|
|
if (toast) hideToast(toast);
|
|
}
|
|
|
|
export function hideToast(toHide: ToastInstance) {
|
|
jotaiStore.set(toastsAtom, (all) => {
|
|
const t = all.find((t) => t.uniqueKey === toHide.uniqueKey);
|
|
t?.onClose?.();
|
|
return all.filter((t) => t.uniqueKey !== toHide.uniqueKey);
|
|
});
|
|
}
|
|
|
|
export function showErrorToast<T>({
|
|
id,
|
|
title,
|
|
message,
|
|
}: {
|
|
id: string;
|
|
title: string;
|
|
message: T;
|
|
}) {
|
|
return showToast({
|
|
id,
|
|
color: "danger",
|
|
timeout: null,
|
|
message: (
|
|
<div className="w-full">
|
|
<h2 className="text-lg font-bold mb-2">{title}</h2>
|
|
<div className="whitespace-pre-wrap wrap-break-word">{String(message)}</div>
|
|
</div>
|
|
),
|
|
});
|
|
}
|