Files
everyone-can-use-english/enjoy/src/renderer/components/notes/note-card.tsx
an-lee 0644c3bbd7 Feat: make notes on caption (#544)
* add segment model

* add note model

* db handle segment & note

* add notes & segments handler

* refactor media caption components

* segment & note create

* fix type

* update note column & may sync

* display selected words for note

* refactor selected words

* auto select words when editing note

* refactor

* refactor caption component

* display notes

* refactor notes components

* fix

* refactor segment & notes into context

* destroy note

* update locale

* fix caption switch issue

* fix layout

* refactor caption layout

* remove deprecated code

* may share note

* improve UI

* fix notes list auto update after created

* remove console.log

* add notes page

* refactor note parameters

* refactor components

* mark note on transcription

* handle no notes

* improve style

* improve style

* show context menu on selection text

* fix utils
2024-04-26 15:05:36 +08:00

166 lines
4.6 KiB
TypeScript

import { AppSettingsProviderContext } from "@renderer/context";
import { useContext, useState } from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogContent,
AlertDialogCancel,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
toast,
} from "@renderer/components/ui";
import { MoreHorizontalIcon } from "lucide-react";
import Markdown from "react-markdown";
import { t } from "i18next";
export const NoteCard = (props: {
note: NoteType;
onEdit?: (note: NoteType) => void;
}) => {
if (props.note.targetType === "Segment") {
return <SegmentNoteCard {...props} />;
}
};
export const SegmentNoteCard = (props: {
note: NoteType;
onEdit?: (note: NoteType) => void;
}) => {
const { note } = props;
return (
<div
id={`note-${note.id}`}
className="w-full rounded px-4 py-2 bg-muted/50"
>
<Markdown className="select-text prose prose-sm dark:prose-invert max-w-full mb-2">
{note.content}
</Markdown>
<div className="flex justify-between space-x-2">
{note.parameters?.quote ? (
<div className="flex">
<span className="text-muted-foreground text-sm px-1 border-b border-red-500 border-dashed">
{note.parameters.quote}
</span>
</div>
) : (
<div></div>
)}
<NoteActionsDropdownMenu {...props} />
</div>
</div>
);
};
const NoteActionsDropdownMenu = (props: {
note: NoteType;
onEdit?: (note: NoteType) => void;
}) => {
const { EnjoyApp, webApi } = useContext(AppSettingsProviderContext);
const { note, onEdit } = props;
const [deleting, setDeleting] = useState(false);
const [sharing, setSharing] = useState(false);
const handleDelete = () => {
EnjoyApp.notes.delete(note.id);
};
const handleShare = async () => {
try {
if (
note.segment &&
(!note.segment.syncedAt || !note.segment.uploadedAt)
) {
await EnjoyApp.segments.sync(note.segment.id);
}
if (!note.syncedAt) {
await EnjoyApp.notes.sync(note.id);
}
} catch (e) {
toast.error(t("shareFailed"), { description: e.message });
}
webApi
.createPost({
targetId: note.id,
targetType: "Note",
})
.then(() => {
toast.success(t("sharedSuccessfully"));
})
.catch((e) => {
toast.error(t("shareFailed"), { description: e.message });
});
};
return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="w-4 h-4 p-0">
<MoreHorizontalIcon className="w-4 h-4 text-muted-foreground" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{onEdit && (
<DropdownMenuItem onClick={() => onEdit(note)}>
{t("edit")}
</DropdownMenuItem>
)}
<DropdownMenuItem onClick={() => setSharing(true)}>
{t("share")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setDeleting(true)}>
{t("delete")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<AlertDialog open={sharing} onOpenChange={(value) => setSharing(value)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{t("shareNote")}</AlertDialogTitle>
<AlertDialogDescription>
{t("areYouSureToShareThisNoteToCommunity")}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
<AlertDialogAction asChild>
<Button onClick={handleShare}>{t("share")}</Button>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<AlertDialog open={deleting} onOpenChange={(value) => setDeleting(value)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{t("deleteNote")}</AlertDialogTitle>
<AlertDialogDescription>
{t("areYouSureToDeleteThisNote")}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
<AlertDialogAction asChild>
<Button onClick={handleDelete}>{t("delete")}</Button>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
};