From 77624aae8c8179956e78ad0173096622b007013c Mon Sep 17 00:00:00 2001 From: Triston Armstrong Date: Wed, 9 Oct 2024 12:55:58 -0400 Subject: [PATCH] feat(notes): add support for exporting individual notes This adds an export icon to the notes cards so a user can export an individual note for sharing or saaving for later --- src/components/Divider.tsx | 7 ++++++ src/components/NoteCard.tsx | 22 +++++++++++++++-- src/components/cardSelector/CardSelector.tsx | 11 +-------- src/components/cardSelector/ExportButton.tsx | 13 +++------- src/components/icons/ExportIcon.tsx | 26 ++++++++++++++++++++ src/utils/createFileAndExport.ts | 23 +++++++++++++++++ src/utils/createFileCompliantDateString.ts | 3 +++ src/utils/createFileFromData.ts | 9 +++++++ 8 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 src/components/Divider.tsx create mode 100644 src/components/icons/ExportIcon.tsx create mode 100644 src/utils/createFileAndExport.ts create mode 100644 src/utils/createFileCompliantDateString.ts create mode 100644 src/utils/createFileFromData.ts diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx new file mode 100644 index 0000000..09e3595 --- /dev/null +++ b/src/components/Divider.tsx @@ -0,0 +1,7 @@ +export function Divider() { + return ( +
+ ) +} + + diff --git a/src/components/NoteCard.tsx b/src/components/NoteCard.tsx index bd22e71..e370823 100644 --- a/src/components/NoteCard.tsx +++ b/src/components/NoteCard.tsx @@ -1,4 +1,3 @@ - import { signal, useRef } from "kaioken" import { NotesSigal, focusedItem } from "../signals" import { useDebounce } from "../utils/useDebounce" @@ -7,6 +6,9 @@ import { LayerEnum } from "../utils/enums" import { useThemeDetector } from "../utils/useThemeDetector" import { MarkDownEditor } from "./MarkDownEditor/MarkDownEditor" import { ChangeEvent } from "tiny-markdown-editor" +import { Divider } from "./Divider" +import { ExportIcon } from "./icons/ExportIcon" +import { createFileAndExport } from "../utils/createFileAndExport" namespace NoteCard { export interface NoteCardProps { @@ -107,6 +109,10 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) { focusedItem.value = itemKey } + function _handleExportClick(e) { + createFileAndExport("Note", item.contents, "text/markdown") + } + const cardPositionStyle = { zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`, width: `${item.dimensions.w}px`, @@ -128,7 +134,19 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
- + +
+
+ +
+ + + +

diff --git a/src/components/cardSelector/CardSelector.tsx b/src/components/cardSelector/CardSelector.tsx index 8b0002b..0d0131e 100644 --- a/src/components/cardSelector/CardSelector.tsx +++ b/src/components/cardSelector/CardSelector.tsx @@ -4,6 +4,7 @@ import { ImageCardButton } from "./ImageCardButton" import { ExportButton } from "./ExportButton" import { TextButton } from "./TextButton" import { ImportButton } from "./ImportButton" +import { Divider } from "../Divider" export function CardSelector() { const containerRef = useRef(null) @@ -27,16 +28,6 @@ export function CardSelector() { ) } -function Divider() { - return ( -
- ) -} - diff --git a/src/components/cardSelector/ExportButton.tsx b/src/components/cardSelector/ExportButton.tsx index f2aa17c..4601214 100644 --- a/src/components/cardSelector/ExportButton.tsx +++ b/src/components/cardSelector/ExportButton.tsx @@ -1,4 +1,5 @@ import { ImagesSignal, NotesSigal } from "../../signals" +import { createFileAndExport } from "../../utils/createFileAndExport" import { Tooltip } from "./Tooltip" import { defaultClassName } from "./utils" @@ -12,17 +13,9 @@ export function ExportButton() { ...notes.value, ...images.value } - const date = new Date().toDateString().split(' ').join('_') - const name = `Kslab_export_${date}.json` + const name = `Kslab_export` const jsonData = JSON.stringify(mergeState) - const file = new File([jsonData], name, { - type: 'text/json' - }) - const url = URL.createObjectURL(file) - const a = document.createElement('a') - a.download = name - a.href = url - a.click() + createFileAndExport(name, jsonData, "text/json") } return ( diff --git a/src/components/icons/ExportIcon.tsx b/src/components/icons/ExportIcon.tsx new file mode 100644 index 0000000..6766f5e --- /dev/null +++ b/src/components/icons/ExportIcon.tsx @@ -0,0 +1,26 @@ +namespace ExportIcon { + export interface Props { + className?: string + } +} +export function ExportIcon({ className }: ExportIcon.Props) { + + return ( + + + + + + ) +} diff --git a/src/utils/createFileAndExport.ts b/src/utils/createFileAndExport.ts new file mode 100644 index 0000000..61e6d9b --- /dev/null +++ b/src/utils/createFileAndExport.ts @@ -0,0 +1,23 @@ +import { createFileCompliantDateString } from "./createFileCompliantDateString" +import { createFileFromData } from "./createFileFromData" + +export type acceptableFileTypes = "text/json" | "text/markdown" +export function createFileAndExport( + name: string, + data: string, + type: acceptableFileTypes +) { + const date = createFileCompliantDateString() + const fileName = `${name}_${date}.${_getFileType(type)}` + const file = createFileFromData(data, fileName, "text/json") + const url = URL.createObjectURL(file) + const a = document.createElement("a") + a.download = fileName + a.href = url + a.click() +} + +function _getFileType(type: acceptableFileTypes): "json" | "md" { + if (type === "text/markdown") return "md" + return "json" +} diff --git a/src/utils/createFileCompliantDateString.ts b/src/utils/createFileCompliantDateString.ts new file mode 100644 index 0000000..30707cf --- /dev/null +++ b/src/utils/createFileCompliantDateString.ts @@ -0,0 +1,3 @@ +export function createFileCompliantDateString() { + return new Date().toDateString().split(" ").join("_") +} diff --git a/src/utils/createFileFromData.ts b/src/utils/createFileFromData.ts new file mode 100644 index 0000000..e50033d --- /dev/null +++ b/src/utils/createFileFromData.ts @@ -0,0 +1,9 @@ +export function createFileFromData( + data: string, + name: string, + type: BlobPropertyBag["type"] +) { + return new File(Array.from(data), name, { + type: type, + }) +}