refactor(signature): apply strategy pattern and make it easier to expand with new tools
This commit is contained in:
parent
f72ad37ec0
commit
be146fa0fa
@ -7,7 +7,7 @@ import {
|
|||||||
isCurrentValueLast
|
isCurrentValueLast
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { MARK_TYPE_CONFIG } from '../getMarkComponents.tsx'
|
import { MarkInput } from '../MarkTypeStrategy/MarkInput.tsx'
|
||||||
|
|
||||||
interface MarkFormFieldProps {
|
interface MarkFormFieldProps {
|
||||||
currentUserMarks: CurrentUserMark[]
|
currentUserMarks: CurrentUserMark[]
|
||||||
@ -52,8 +52,7 @@ const MarkFormField = ({
|
|||||||
}
|
}
|
||||||
const toggleActions = () => setDisplayActions(!displayActions)
|
const toggleActions = () => setDisplayActions(!displayActions)
|
||||||
const markLabel = getToolboxLabelByMarkType(selectedMark.mark.type)
|
const markLabel = getToolboxLabelByMarkType(selectedMark.mark.type)
|
||||||
const { input: MarkInputComponent } =
|
|
||||||
MARK_TYPE_CONFIG[selectedMark.mark.type] || {}
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.trigger}>
|
<div className={styles.trigger}>
|
||||||
@ -84,15 +83,14 @@ const MarkFormField = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.inputWrapper}>
|
<div className={styles.inputWrapper}>
|
||||||
<form onSubmit={(e) => handleFormSubmit(e)}>
|
<form onSubmit={(e) => handleFormSubmit(e)}>
|
||||||
{typeof MarkInputComponent !== 'undefined' && (
|
<MarkInput
|
||||||
<MarkInputComponent
|
markType={selectedMark.mark.type}
|
||||||
key={selectedMark.id}
|
key={selectedMark.id}
|
||||||
value={selectedMarkValue}
|
value={selectedMarkValue}
|
||||||
placeholder={markLabel}
|
placeholder={markLabel}
|
||||||
handler={handleSelectedMarkValueChange}
|
handler={handleSelectedMarkValueChange}
|
||||||
userMark={selectedMark}
|
userMark={selectedMark}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
<div className={styles.actionsBottom}>
|
<div className={styles.actionsBottom}>
|
||||||
<button type="submit" className={styles.submitButton}>
|
<button type="submit" className={styles.submitButton}>
|
||||||
NEXT
|
NEXT
|
||||||
|
16
src/components/MarkTypeStrategy/MarkInput.tsx
Normal file
16
src/components/MarkTypeStrategy/MarkInput.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { MarkType } from '../../types/drawing'
|
||||||
|
import { MARK_TYPE_CONFIG, MarkInputProps } from './MarkStrategy'
|
||||||
|
|
||||||
|
interface MarkInputComponentProps extends MarkInputProps {
|
||||||
|
markType: MarkType
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MarkInput = ({ markType, ...rest }: MarkInputComponentProps) => {
|
||||||
|
const { input: InputComponent } = MARK_TYPE_CONFIG[markType] || {}
|
||||||
|
|
||||||
|
if (typeof InputComponent !== 'undefined') {
|
||||||
|
return <InputComponent {...rest} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
20
src/components/MarkTypeStrategy/MarkRender.tsx
Normal file
20
src/components/MarkTypeStrategy/MarkRender.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { MarkType } from '../../types/drawing'
|
||||||
|
import { MARK_TYPE_CONFIG, MarkRenderProps } from './MarkStrategy'
|
||||||
|
|
||||||
|
interface MarkRenderComponentProps extends MarkRenderProps {
|
||||||
|
markType: MarkType
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MarkRender = ({ markType, ...rest }: MarkRenderComponentProps) => {
|
||||||
|
const { render: RenderComponent } = MARK_TYPE_CONFIG[markType] || {}
|
||||||
|
|
||||||
|
if (typeof RenderComponent !== 'undefined') {
|
||||||
|
return <RenderComponent {...rest} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <DefaultRenderComponent {...rest} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultRenderComponent = ({ value }: MarkRenderProps) => (
|
||||||
|
<span>{value}</span>
|
||||||
|
)
|
32
src/components/MarkTypeStrategy/MarkStrategy.tsx
Normal file
32
src/components/MarkTypeStrategy/MarkStrategy.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { MarkType } from '../../types/drawing'
|
||||||
|
import { CurrentUserMark, Mark } from '../../types/mark'
|
||||||
|
import { TextStrategy } from './Text'
|
||||||
|
import { SignatureStrategy } from './Signature'
|
||||||
|
|
||||||
|
export interface MarkInputProps {
|
||||||
|
value: string
|
||||||
|
handler: (value: string) => void
|
||||||
|
placeholder?: string
|
||||||
|
userMark?: CurrentUserMark
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarkRenderProps {
|
||||||
|
value?: string
|
||||||
|
mark: Mark
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarkStrategy {
|
||||||
|
input: React.FC<MarkInputProps>
|
||||||
|
render: React.FC<MarkRenderProps>
|
||||||
|
encryptAndUpload?: (value: string, key?: string) => Promise<string>
|
||||||
|
fetchAndDecrypt?: (value: string, key?: string) => Promise<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MarkStrategies = {
|
||||||
|
[key in MarkType]?: MarkStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MARK_TYPE_CONFIG: MarkStrategies = {
|
||||||
|
[MarkType.TEXT]: TextStrategy,
|
||||||
|
[MarkType.SIGNATURE]: SignatureStrategy
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
@import '../../styles/colors.scss';
|
@import '../../../styles/colors.scss';
|
||||||
|
|
||||||
$padding: 5px;
|
$padding: 5px;
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
import { useCallback, useEffect, useRef } from 'react'
|
import { useCallback, useEffect, useRef } from 'react'
|
||||||
import { MarkInputProps } from '../../types/mark'
|
|
||||||
import { faEraser } from '@fortawesome/free-solid-svg-icons'
|
import { faEraser } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import styles from './Signature.module.scss'
|
import { MarkRenderSignature } from './Render'
|
||||||
import { MarkRenderSignature } from '../MarkRender/Signature'
|
|
||||||
import SignaturePad from 'signature_pad'
|
import SignaturePad from 'signature_pad'
|
||||||
import { SIGNATURE_PAD_OPTIONS, SIGNATURE_PAD_SIZE } from '../../utils/const'
|
import { SIGNATURE_PAD_OPTIONS, SIGNATURE_PAD_SIZE } from '../../../utils/const'
|
||||||
import { BasicPoint } from 'signature_pad/dist/types/point'
|
import { BasicPoint } from 'signature_pad/dist/types/point'
|
||||||
|
import { MarkInputProps } from '../MarkStrategy'
|
||||||
|
import styles from './Input.module.scss'
|
||||||
|
|
||||||
export const MarkInputSignature = ({
|
export const MarkInputSignature = ({
|
||||||
value,
|
value,
|
@ -1,9 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import SignaturePad from 'signature_pad'
|
import SignaturePad from 'signature_pad'
|
||||||
import { MarkRenderProps } from '../../types/mark'
|
import { SIGNATURE_PAD_OPTIONS, SIGNATURE_PAD_SIZE } from '../../../utils'
|
||||||
import { SIGNATURE_PAD_OPTIONS, SIGNATURE_PAD_SIZE } from '../../utils'
|
|
||||||
import { BasicPoint } from 'signature_pad/dist/types/point'
|
import { BasicPoint } from 'signature_pad/dist/types/point'
|
||||||
import styles from './Signature.module.scss'
|
import { MarkRenderProps } from '../MarkStrategy'
|
||||||
|
import styles from './Render.module.scss'
|
||||||
|
|
||||||
export const MarkRenderSignature = ({ value }: MarkRenderProps) => {
|
export const MarkRenderSignature = ({ value }: MarkRenderProps) => {
|
||||||
const [dataUrl, setDataUrl] = useState<string | undefined>()
|
const [dataUrl, setDataUrl] = useState<string | undefined>()
|
86
src/components/MarkTypeStrategy/Signature/index.tsx
Normal file
86
src/components/MarkTypeStrategy/Signature/index.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import {
|
||||||
|
decryptArrayBuffer,
|
||||||
|
encryptArrayBuffer,
|
||||||
|
getHash,
|
||||||
|
isOnline,
|
||||||
|
uploadToFileStorage
|
||||||
|
} from '../../../utils'
|
||||||
|
import { MarkStrategy } from '../MarkStrategy'
|
||||||
|
import { MarkInputSignature } from './Input'
|
||||||
|
import { MarkRenderSignature } from './Render'
|
||||||
|
|
||||||
|
export const SignatureStrategy: MarkStrategy = {
|
||||||
|
input: MarkInputSignature,
|
||||||
|
render: MarkRenderSignature,
|
||||||
|
encryptAndUpload: async (value, encryptionKey) => {
|
||||||
|
// Value is the stringified signature object
|
||||||
|
// Encode it as text to the arrayBuffer
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const uint8Array = encoder.encode(value)
|
||||||
|
const hash = await getHash(uint8Array)
|
||||||
|
|
||||||
|
if (!hash) {
|
||||||
|
throw new Error("Can't get file hash.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encryptionKey) {
|
||||||
|
throw new Error('Signature requires an encryption key')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the file contents with the same encryption key from the create signature
|
||||||
|
const encryptedArrayBuffer = await encryptArrayBuffer(
|
||||||
|
uint8Array,
|
||||||
|
encryptionKey
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create the encrypted json file from array buffer and hash
|
||||||
|
const file = new File([encryptedArrayBuffer], `${hash}.json`)
|
||||||
|
|
||||||
|
if (await isOnline()) {
|
||||||
|
try {
|
||||||
|
const url = await uploadToFileStorage(file)
|
||||||
|
console.info(`${file.name} uploaded to file storage`)
|
||||||
|
return url
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error(
|
||||||
|
`Error occurred in uploading file ${file.name}`,
|
||||||
|
error.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle offline?
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
fetchAndDecrypt: async (value, encryptionKey) => {
|
||||||
|
if (!encryptionKey) {
|
||||||
|
throw new Error('Signature requires an encryption key')
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedArrayBuffer = await axios.get(value, {
|
||||||
|
responseType: 'arraybuffer'
|
||||||
|
})
|
||||||
|
|
||||||
|
const arrayBuffer = await decryptArrayBuffer(
|
||||||
|
encryptedArrayBuffer.data,
|
||||||
|
encryptionKey
|
||||||
|
).catch((err) => {
|
||||||
|
console.log('err in decryption:>> ', err)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
if (arrayBuffer) {
|
||||||
|
// decode json
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
const value = decoder.decode(arrayBuffer)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle offline?
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { MarkInputProps } from '../../types/mark'
|
import { MarkInputProps } from '../MarkStrategy'
|
||||||
import styles from '../MarkFormField/style.module.scss'
|
import styles from '../../MarkFormField/style.module.scss'
|
||||||
|
|
||||||
export const MarkInputText = ({
|
export const MarkInputText = ({
|
||||||
value,
|
value,
|
7
src/components/MarkTypeStrategy/Text/index.tsx
Normal file
7
src/components/MarkTypeStrategy/Text/index.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { MarkStrategy } from '../MarkStrategy'
|
||||||
|
import { MarkInputText } from './Input'
|
||||||
|
|
||||||
|
export const TextStrategy: MarkStrategy = {
|
||||||
|
input: MarkInputText,
|
||||||
|
render: ({ value }) => <>{value}</>
|
||||||
|
}
|
@ -4,7 +4,7 @@ import { FONT_SIZE, FONT_TYPE, inPx } from '../../utils/pdf.ts'
|
|||||||
import { useScale } from '../../hooks/useScale.tsx'
|
import { useScale } from '../../hooks/useScale.tsx'
|
||||||
import { forwardRef } from 'react'
|
import { forwardRef } from 'react'
|
||||||
import { npubToHex } from '../../utils/nostr.ts'
|
import { npubToHex } from '../../utils/nostr.ts'
|
||||||
import { MARK_TYPE_CONFIG } from '../getMarkComponents.tsx'
|
import { MarkRender } from '../MarkTypeStrategy/MarkRender.tsx'
|
||||||
|
|
||||||
interface PdfMarkItemProps {
|
interface PdfMarkItemProps {
|
||||||
userMark: CurrentUserMark
|
userMark: CurrentUserMark
|
||||||
@ -28,8 +28,6 @@ const PdfMarkItem = forwardRef<HTMLDivElement, PdfMarkItemProps>(
|
|||||||
const getMarkValue = () =>
|
const getMarkValue = () =>
|
||||||
isEdited() ? selectedMarkValue : userMark.currentValue
|
isEdited() ? selectedMarkValue : userMark.currentValue
|
||||||
const { from } = useScale()
|
const { from } = useScale()
|
||||||
const { render: MarkRenderComponent } =
|
|
||||||
MARK_TYPE_CONFIG[userMark.mark.type] || {}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -50,13 +48,12 @@ const PdfMarkItem = forwardRef<HTMLDivElement, PdfMarkItemProps>(
|
|||||||
fontSize: inPx(from(pageWidth, FONT_SIZE))
|
fontSize: inPx(from(pageWidth, FONT_SIZE))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof MarkRenderComponent !== 'undefined' && (
|
<MarkRender
|
||||||
<MarkRenderComponent
|
|
||||||
key={getMarkValue()}
|
key={getMarkValue()}
|
||||||
|
markType={userMark.mark.type}
|
||||||
value={getMarkValue()}
|
value={getMarkValue()}
|
||||||
mark={userMark.mark}
|
mark={userMark.mark}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { useEffect, useRef } from 'react'
|
|||||||
import pdfViewStyles from './style.module.scss'
|
import pdfViewStyles from './style.module.scss'
|
||||||
import { FONT_SIZE, FONT_TYPE, inPx } from '../../utils/pdf.ts'
|
import { FONT_SIZE, FONT_TYPE, inPx } from '../../utils/pdf.ts'
|
||||||
import { useScale } from '../../hooks/useScale.tsx'
|
import { useScale } from '../../hooks/useScale.tsx'
|
||||||
import { MARK_TYPE_CONFIG } from '../getMarkComponents.tsx'
|
import { MarkRender } from '../MarkTypeStrategy/MarkRender.tsx'
|
||||||
interface PdfPageProps {
|
interface PdfPageProps {
|
||||||
fileName: string
|
fileName: string
|
||||||
pageIndex: number
|
pageIndex: number
|
||||||
@ -61,7 +61,6 @@ const PdfPageItem = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{otherUserMarks.map((m, i) => {
|
{otherUserMarks.map((m, i) => {
|
||||||
const { render: MarkRenderComponent } = MARK_TYPE_CONFIG[m.type] || {}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
@ -75,9 +74,7 @@ const PdfPageItem = ({
|
|||||||
fontSize: inPx(from(page.width, FONT_SIZE))
|
fontSize: inPx(from(page.width, FONT_SIZE))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof MarkRenderComponent !== 'undefined' && (
|
<MarkRender value={m.value} mark={m} markType={m.type} />
|
||||||
<MarkRenderComponent value={m.value} mark={m} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
import { toast } from 'react-toastify'
|
|
||||||
import { MarkType } from '../types/drawing'
|
|
||||||
import { MarkConfigs } from '../types/mark'
|
|
||||||
import {
|
|
||||||
decryptArrayBuffer,
|
|
||||||
encryptArrayBuffer,
|
|
||||||
getHash,
|
|
||||||
isOnline,
|
|
||||||
uploadToFileStorage
|
|
||||||
} from '../utils'
|
|
||||||
import { MarkInputSignature } from './MarkInputs/Signature'
|
|
||||||
import { MarkInputText } from './MarkInputs/Text'
|
|
||||||
import { MarkRenderSignature } from './MarkRender/Signature'
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
export const MARK_TYPE_CONFIG: MarkConfigs = {
|
|
||||||
[MarkType.TEXT]: {
|
|
||||||
input: MarkInputText,
|
|
||||||
render: ({ value }) => <>{value}</>
|
|
||||||
},
|
|
||||||
[MarkType.SIGNATURE]: {
|
|
||||||
input: MarkInputSignature,
|
|
||||||
render: MarkRenderSignature,
|
|
||||||
encryptAndUpload: async (value, encryptionKey) => {
|
|
||||||
// Value is the stringified signature object
|
|
||||||
// Encode it as text to the arrayBuffer
|
|
||||||
const encoder = new TextEncoder()
|
|
||||||
const uint8Array = encoder.encode(value)
|
|
||||||
const hash = await getHash(uint8Array)
|
|
||||||
|
|
||||||
if (!hash) {
|
|
||||||
throw new Error("Can't get file hash.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!encryptionKey) {
|
|
||||||
throw new Error('Signature requires an encryption key')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt the file contents with the same encryption key from the create signature
|
|
||||||
const encryptedArrayBuffer = await encryptArrayBuffer(
|
|
||||||
uint8Array,
|
|
||||||
encryptionKey
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create the encrypted json file from array buffer and hash
|
|
||||||
const file = new File([encryptedArrayBuffer], `${hash}.json`)
|
|
||||||
|
|
||||||
if (await isOnline()) {
|
|
||||||
try {
|
|
||||||
const url = await uploadToFileStorage(file)
|
|
||||||
toast.success('files.zip uploaded to file storage')
|
|
||||||
return url
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
toast.error(error.message || 'Error occurred in uploading file')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Handle offline?
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
},
|
|
||||||
fetchAndDecrypt: async (value, encryptionKey) => {
|
|
||||||
if (!encryptionKey) {
|
|
||||||
throw new Error('Signature requires an encryption key')
|
|
||||||
}
|
|
||||||
|
|
||||||
const encryptedArrayBuffer = await axios.get(value, {
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
})
|
|
||||||
|
|
||||||
const arrayBuffer = await decryptArrayBuffer(
|
|
||||||
encryptedArrayBuffer.data,
|
|
||||||
encryptionKey
|
|
||||||
).catch((err) => {
|
|
||||||
console.log('err in decryption:>> ', err)
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
|
|
||||||
if (arrayBuffer) {
|
|
||||||
// decode json
|
|
||||||
const decoder = new TextDecoder()
|
|
||||||
const value = decoder.decode(arrayBuffer)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle offline?
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ import { Event } from 'nostr-tools'
|
|||||||
import store from '../store/store'
|
import store from '../store/store'
|
||||||
import { NostrController } from '../controllers'
|
import { NostrController } from '../controllers'
|
||||||
import { MetaParseError } from '../types/errors/MetaParseError'
|
import { MetaParseError } from '../types/errors/MetaParseError'
|
||||||
import { MARK_TYPE_CONFIG } from '../components/getMarkComponents'
|
import { MARK_TYPE_CONFIG } from '../components/MarkTypeStrategy/MarkStrategy'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flattened interface that combines properties `Meta`, `CreateSignatureEventContent`,
|
* Flattened interface that combines properties `Meta`, `CreateSignatureEventContent`,
|
||||||
|
@ -55,7 +55,7 @@ import {
|
|||||||
} from '../../utils/file.ts'
|
} from '../../utils/file.ts'
|
||||||
import { ARRAY_BUFFER, DEFLATE } from '../../utils/const.ts'
|
import { ARRAY_BUFFER, DEFLATE } from '../../utils/const.ts'
|
||||||
import { generateTimestamp } from '../../utils/opentimestamps.ts'
|
import { generateTimestamp } from '../../utils/opentimestamps.ts'
|
||||||
import { MARK_TYPE_CONFIG } from '../../components/getMarkComponents.tsx'
|
import { MARK_TYPE_CONFIG } from '../../components/MarkTypeStrategy/MarkStrategy.tsx'
|
||||||
|
|
||||||
enum SignedStatus {
|
enum SignedStatus {
|
||||||
Fully_Signed,
|
Fully_Signed,
|
||||||
|
@ -55,7 +55,7 @@ import {
|
|||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { upgradeAndVerifyTimestamp } from '../../utils/opentimestamps.ts'
|
import { upgradeAndVerifyTimestamp } from '../../utils/opentimestamps.ts'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { MARK_TYPE_CONFIG } from '../../components/getMarkComponents.tsx'
|
import { MarkRender } from '../../components/MarkTypeStrategy/MarkRender.tsx'
|
||||||
|
|
||||||
interface PdfViewProps {
|
interface PdfViewProps {
|
||||||
files: CurrentUserFile[]
|
files: CurrentUserFile[]
|
||||||
@ -115,8 +115,6 @@ const SlimPdfView = ({
|
|||||||
alt={`page ${i} of ${file.name}`}
|
alt={`page ${i} of ${file.name}`}
|
||||||
/>
|
/>
|
||||||
{marks.map((m) => {
|
{marks.map((m) => {
|
||||||
const { render: MarkRenderComponent } =
|
|
||||||
MARK_TYPE_CONFIG[m.type] || {}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`file-mark ${styles.mark}`}
|
className={`file-mark ${styles.mark}`}
|
||||||
@ -132,9 +130,11 @@ const SlimPdfView = ({
|
|||||||
fontSize: inPx(from(page.width, FONT_SIZE))
|
fontSize: inPx(from(page.width, FONT_SIZE))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof MarkRenderComponent !== 'undefined' && (
|
<MarkRender
|
||||||
<MarkRenderComponent value={m.value} mark={m} />
|
markType={m.type}
|
||||||
)}
|
value={m.value}
|
||||||
|
mark={m}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -28,26 +28,3 @@ export interface MarkRect {
|
|||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MarkInputProps {
|
|
||||||
value: string
|
|
||||||
handler: (value: string) => void
|
|
||||||
placeholder?: string
|
|
||||||
userMark?: CurrentUserMark
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MarkRenderProps {
|
|
||||||
value?: string
|
|
||||||
mark: Mark
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MarkConfig {
|
|
||||||
input: React.FC<MarkInputProps>
|
|
||||||
render: React.FC<MarkRenderProps>
|
|
||||||
encryptAndUpload?: (value: string, key?: string) => Promise<string>
|
|
||||||
fetchAndDecrypt?: (value: string, key?: string) => Promise<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MarkConfigs = {
|
|
||||||
[key in MarkType]?: MarkConfig
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { MARK_TYPE_CONFIG } from '../components/getMarkComponents.tsx'
|
import { MARK_TYPE_CONFIG } from '../components/MarkTypeStrategy/MarkStrategy.tsx'
|
||||||
import { NostrController } from '../controllers/NostrController.ts'
|
import { NostrController } from '../controllers/NostrController.ts'
|
||||||
import store from '../store/store.ts'
|
import store from '../store/store.ts'
|
||||||
import { Meta } from '../types'
|
import { Meta } from '../types'
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
faStamp,
|
faStamp,
|
||||||
faTableCellsLarge
|
faTableCellsLarge
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { MARK_TYPE_CONFIG } from '../components/getMarkComponents.tsx'
|
import { MARK_TYPE_CONFIG } from '../components/MarkTypeStrategy/MarkStrategy.tsx'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes in an array of Marks already filtered by User.
|
* Takes in an array of Marks already filtered by User.
|
||||||
|
Loading…
Reference in New Issue
Block a user