generated from Klectr/KTemplate
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
This commit is contained in:
parent
f659a38026
commit
77624aae8c
7
src/components/Divider.tsx
Normal file
7
src/components/Divider.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export function Divider() {
|
||||
return (
|
||||
<div className="border-l-[1px] border-l-[#9c9c9c]"></div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
<div className="overflow-hidden flex-1 flex flex-col gap-1">
|
||||
<div className="px-2 flex justify-between items-center cursor-move" onmousedown={_handleMouseDown}>
|
||||
<div style={saveIndicatorStyle} className="rounded-full w-1 h-1 dark:bg-white bg-green-500"></div>
|
||||
<button className="text-md dark:text-[#777] text-black" onclick={_handleClose}>x</button>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<div
|
||||
onclick={_handleExportClick}
|
||||
className="flex items-center">
|
||||
<ExportIcon
|
||||
className="cursor-pointer w-4 h-4 text-[#9c9c9c] hover:text-blue-500 transition-color duration-300"
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<button className="text-md dark:text-[#777] text-black" onclick={_handleClose}>x</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="border dark:border-[#1c1c1c] border-[#ddd]" />
|
||||
|
@ -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<HTMLDivElement>(null)
|
||||
@ -27,16 +28,6 @@ export function CardSelector() {
|
||||
)
|
||||
}
|
||||
|
||||
function Divider() {
|
||||
return (
|
||||
<div style={{
|
||||
margin: '2px 2px',
|
||||
border: "1px solid #9c9c9c",
|
||||
borderRight: 'none',
|
||||
}}></div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 (
|
||||
|
26
src/components/icons/ExportIcon.tsx
Normal file
26
src/components/icons/ExportIcon.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
namespace ExportIcon {
|
||||
export interface Props {
|
||||
className?: string
|
||||
}
|
||||
}
|
||||
export function ExportIcon({ className }: ExportIcon.Props) {
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
className={className ?? ""}
|
||||
>
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
||||
<polyline points="17 8 12 3 7 8" />
|
||||
<line x1="12" x2="12" y1="3" y2="15" />
|
||||
</svg>
|
||||
)
|
||||
}
|
23
src/utils/createFileAndExport.ts
Normal file
23
src/utils/createFileAndExport.ts
Normal file
@ -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"
|
||||
}
|
3
src/utils/createFileCompliantDateString.ts
Normal file
3
src/utils/createFileCompliantDateString.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function createFileCompliantDateString() {
|
||||
return new Date().toDateString().split(" ").join("_")
|
||||
}
|
9
src/utils/createFileFromData.ts
Normal file
9
src/utils/createFileFromData.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export function createFileFromData(
|
||||
data: string,
|
||||
name: string,
|
||||
type: BlobPropertyBag["type"]
|
||||
) {
|
||||
return new File(Array.from(data), name, {
|
||||
type: type,
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user