Show number of added cards

This commit is contained in:
Abdo 2025-09-03 00:01:04 +03:00
parent 355e5f2125
commit 5fe532d5d2
5 changed files with 42 additions and 22 deletions

View file

@ -586,12 +586,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
if (!(await noteCanBeAdded())) { if (!(await noteCanBeAdded())) {
return; return;
} }
const noteId = ( const response = await addEditorNote({
await addEditorNote({ note: note!,
note: note!, deckId,
deckId, });
}) showToast(
).noteId; tr.importingCardsAdded({ count: response.changes!.count }),
"success",
500,
);
const noteId = response.noteId;
note.id = noteId; note.id = noteId;
addNoteToHistory(note!); addNoteToHistory(note!);
lastAddedNote = note; lastAddedNote = note;
@ -767,6 +771,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type NotetypeChooser from "$lib/components/NotetypeChooser.svelte"; import type NotetypeChooser from "$lib/components/NotetypeChooser.svelte";
import type DeckChooser from "$lib/components/DeckChooser.svelte"; import type DeckChooser from "$lib/components/DeckChooser.svelte";
import { ConfigKey_Bool } from "@generated/anki/config_pb"; import { ConfigKey_Bool } from "@generated/anki/config_pb";
import {
destroyToast,
initToast,
showToast,
} from "../image-occlusion/toast-utils.svelte";
$: isIOImageLoaded = false; $: isIOImageLoaded = false;
$: ioImageLoadedStore.set(isIOImageLoaded); $: ioImageLoadedStore.set(isIOImageLoaded);
@ -1231,6 +1240,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
deregisterSticky = registerShortcut(toggleStickyAll, "Shift+F9"); deregisterSticky = registerShortcut(toggleStickyAll, "Shift+F9");
} }
initToast();
function wrap(before: string, after: string): void { function wrap(before: string, after: string): void {
if (!$focusedInput || !editingInputIsRichText($focusedInput)) { if (!$focusedInput || !editingInputIsRichText($focusedInput)) {
return; return;
@ -1293,6 +1304,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
onDestroy(() => { onDestroy(() => {
deregisterSticky(); deregisterSticky();
destroyToast();
}); });
let apiPartial: Partial<NoteEditorAPI> = {}; let apiPartial: Partial<NoteEditorAPI> = {};

View file

@ -17,15 +17,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { MaskEditorAPI } from "./tools/api"; import { MaskEditorAPI } from "./tools/api";
import { onResize } from "./tools/tool-zoom"; import { onResize } from "./tools/tool-zoom";
import { saveNeededStore } from "./store"; import { saveNeededStore } from "./store";
import { destroyToast, initToast } from "./toast-utils.svelte";
import type Toast from "./Toast.svelte";
export let mode: IOMode; export let mode: IOMode;
const iconSize = 80; const iconSize = 80;
let innerWidth = 0; let innerWidth = 0;
const startingTool = mode.kind === "add" ? "draw-rectangle" : "cursor"; const startingTool = mode.kind === "add" ? "draw-rectangle" : "cursor";
let canvas: fabric.Canvas | null = null; let canvas: fabric.Canvas | null = null;
let toast: Toast | null = null;
$: { $: {
globalThis.maskEditor = canvas ? new MaskEditorAPI(canvas) : null; globalThis.maskEditor = canvas ? new MaskEditorAPI(canvas) : null;
@ -70,13 +67,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
onMount(() => { onMount(() => {
window.addEventListener("resize", resizeEvent); window.addEventListener("resize", resizeEvent);
toast = initToast();
}); });
onDestroy(() => { onDestroy(() => {
window.removeEventListener("resize", resizeEvent); window.removeEventListener("resize", resizeEvent);
unsubscribe(); unsubscribe();
destroyToast(toast!);
}); });
const resizeEvent = () => { const resizeEvent = () => {

View file

@ -8,17 +8,23 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { mdiClose } from "$lib/components/icons"; import { mdiClose } from "$lib/components/icons";
import type { ToastProps } from "./types"; import type { ToastProps } from "./types";
const props: ToastProps = $props(); let { showToast, type, message, timeout }: ToastProps = $props();
const closeToast = () => { const closeToast = () => {
props.showToast = false; showToast = false;
}; };
$effect(() => {
if (timeout) {
setTimeout(closeToast, timeout);
}
});
</script> </script>
{#if props.showToast} {#if showToast}
<div class="toast-container desktop-only"> <div class="toast-container">
<div class="toast {props.type === 'success' ? 'success' : 'error'}"> <div class="toast {type === 'success' ? 'success' : 'error'}">
{props.message} {message}
<IconButton iconSize={96} on:click={closeToast} class="toast-icon"> <IconButton iconSize={96} on:click={closeToast} class="toast-icon">
<Icon icon={mdiClose} /> <Icon icon={mdiClose} />
</IconButton> </IconButton>

View file

@ -11,21 +11,27 @@ const toastProps: ToastProps = $state({
message: "", message: "",
}); });
export function initToast(): Toast { let toast: Toast | null = null;
return mount(Toast, {
export function initToast() {
toast = mount(Toast, {
target: document.body, target: document.body,
props: toastProps, props: toastProps,
}); });
} }
export function destroyToast(toast: Toast) { export function destroyToast() {
unmount(toast); if (toast) {
unmount(toast);
toast = null;
}
} }
export function showToast(message: string, type: "success" | "error") { export function showToast(message: string, type: "success" | "error", timeout?: number) {
toastProps.message = message; toastProps.message = message;
toastProps.type = type; toastProps.type = type;
toastProps.showToast = true; toastProps.showToast = true;
toastProps.timeout = timeout;
} }
export function hideToast() { export function hideToast() {

View file

@ -14,4 +14,5 @@ export interface ToastProps {
message: string; message: string;
type: "success" | "error"; type: "success" | "error";
showToast: boolean; showToast: boolean;
timeout?: number;
} }