Compare commits
No commits in common. "cc059f6cb401069b26391f18d4938ad9ef9bbf6d" and "aae11589a4cb94b3973a6571173889af0c893fb8" have entirely different histories.
cc059f6cb4
...
aae11589a4
1633
package-lock.json
generated
1633
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -57,7 +57,6 @@
|
|||||||
"react-singleton-hook": "^4.0.1",
|
"react-singleton-hook": "^4.0.1",
|
||||||
"react-toastify": "10.0.4",
|
"react-toastify": "10.0.4",
|
||||||
"redux": "5.0.1",
|
"redux": "5.0.1",
|
||||||
"svgo": "^3.3.2",
|
|
||||||
"tseep": "1.2.1"
|
"tseep": "1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -67,7 +66,6 @@
|
|||||||
"@types/pdfjs-dist": "^2.10.378",
|
"@types/pdfjs-dist": "^2.10.378",
|
||||||
"@types/react": "^18.2.56",
|
"@types/react": "^18.2.56",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.19",
|
||||||
"@types/svgo": "^3.0.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||||
"@typescript-eslint/parser": "^7.0.2",
|
"@typescript-eslint/parser": "^7.0.2",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
@ -80,7 +78,6 @@
|
|||||||
"ts-css-modules-vite-plugin": "1.0.20",
|
"ts-css-modules-vite-plugin": "1.0.20",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.1.4",
|
"vite": "^5.1.4",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
|
||||||
"vite-tsconfig-paths": "4.3.2"
|
"vite-tsconfig-paths": "4.3.2"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
@ -7,12 +7,13 @@ import {
|
|||||||
isCurrentValueLast
|
isCurrentValueLast
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { MARK_TYPE_CONFIG } from '../getMarkComponents.tsx'
|
|
||||||
|
|
||||||
interface MarkFormFieldProps {
|
interface MarkFormFieldProps {
|
||||||
currentUserMarks: CurrentUserMark[]
|
currentUserMarks: CurrentUserMark[]
|
||||||
handleCurrentUserMarkChange: (mark: CurrentUserMark) => void
|
handleCurrentUserMarkChange: (mark: CurrentUserMark) => void
|
||||||
handleSelectedMarkValueChange: (value: string) => void
|
handleSelectedMarkValueChange: (
|
||||||
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
|
) => void
|
||||||
handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void
|
||||||
selectedMark: CurrentUserMark
|
selectedMark: CurrentUserMark
|
||||||
selectedMarkValue: string
|
selectedMarkValue: string
|
||||||
@ -52,8 +53,6 @@ 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,14 +83,12 @@ 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' && (
|
<input
|
||||||
<MarkInputComponent
|
className={styles.input}
|
||||||
value={selectedMarkValue}
|
|
||||||
placeholder={markLabel}
|
placeholder={markLabel}
|
||||||
handler={handleSelectedMarkValueChange}
|
onChange={handleSelectedMarkValueChange}
|
||||||
userMark={selectedMark}
|
value={selectedMarkValue}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
<div className={styles.actionsBottom}>
|
<div className={styles.actionsBottom}>
|
||||||
<button type="submit" className={styles.submitButton}>
|
<button type="submit" className={styles.submitButton}>
|
||||||
NEXT
|
NEXT
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
@import '../../styles/colors.scss';
|
|
||||||
|
|
||||||
$padding: 5px;
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: $padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relative {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.canvas {
|
|
||||||
outline: 1px solid black;
|
|
||||||
background-color: $body-background-color;
|
|
||||||
cursor: crosshair;
|
|
||||||
|
|
||||||
// Disable panning/zooming when touching canvas element
|
|
||||||
-ms-touch-action: none;
|
|
||||||
touch-action: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.absolute {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reset {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: $padding;
|
|
||||||
color: $primary-main;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $primary-dark;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
import { useRef, useState } from 'react'
|
|
||||||
import { MarkInputProps } from '../../types/mark'
|
|
||||||
import { getOptimizedPaths, optimizeSVG } from '../../utils'
|
|
||||||
import { faEraser } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import styles from './Signature.module.scss'
|
|
||||||
import { MarkRenderSignature } from '../MarkRender/Signature'
|
|
||||||
|
|
||||||
export const MarkInputSignature = ({
|
|
||||||
value,
|
|
||||||
handler,
|
|
||||||
userMark
|
|
||||||
}: MarkInputProps) => {
|
|
||||||
const location = userMark?.mark.location
|
|
||||||
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
||||||
const [drawing, setDrawing] = useState(false)
|
|
||||||
const [paths, setPaths] = useState<string[]>(value ? JSON.parse(value) : [])
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
if (location && paths) {
|
|
||||||
if (paths.length) {
|
|
||||||
const optimizedSvg = optimizeSVG(location, paths)
|
|
||||||
const extractedPaths = getOptimizedPaths(optimizedSvg)
|
|
||||||
handler(JSON.stringify(extractedPaths))
|
|
||||||
} else {
|
|
||||||
handler('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePointerDown = (event: React.PointerEvent) => {
|
|
||||||
const rect = event.currentTarget.getBoundingClientRect()
|
|
||||||
const x = event.clientX - rect.left
|
|
||||||
const y = event.clientY - rect.top
|
|
||||||
|
|
||||||
const ctx = canvasRef.current?.getContext('2d')
|
|
||||||
ctx?.beginPath()
|
|
||||||
ctx?.moveTo(x, y)
|
|
||||||
setPaths([...paths, `M ${x} ${y}`])
|
|
||||||
setDrawing(true)
|
|
||||||
}
|
|
||||||
const handlePointerUp = () => {
|
|
||||||
setDrawing(false)
|
|
||||||
update()
|
|
||||||
const ctx = canvasRef.current?.getContext('2d')
|
|
||||||
ctx?.clearRect(0, 0, canvasRef.current!.width, canvasRef.current!.height)
|
|
||||||
}
|
|
||||||
const handlePointerMove = (event: React.PointerEvent) => {
|
|
||||||
if (!drawing) return
|
|
||||||
const ctx = canvasRef.current?.getContext('2d')
|
|
||||||
const rect = canvasRef.current?.getBoundingClientRect()
|
|
||||||
const x = event.clientX - rect!.left
|
|
||||||
const y = event.clientY - rect!.top
|
|
||||||
|
|
||||||
ctx?.lineTo(x, y)
|
|
||||||
ctx?.stroke()
|
|
||||||
|
|
||||||
// Collect the path data
|
|
||||||
setPaths((prevPaths) => {
|
|
||||||
const newPaths = [...prevPaths]
|
|
||||||
newPaths[newPaths.length - 1] += ` L ${x} ${y}`
|
|
||||||
return newPaths
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleReset = () => {
|
|
||||||
setPaths([])
|
|
||||||
setDrawing(false)
|
|
||||||
update()
|
|
||||||
const ctx = canvasRef.current?.getContext('2d')
|
|
||||||
ctx?.clearRect(0, 0, canvasRef.current!.width, canvasRef.current!.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.wrapper}>
|
|
||||||
<div className={styles.relative}>
|
|
||||||
<canvas
|
|
||||||
height={location?.height}
|
|
||||||
width={location?.width}
|
|
||||||
ref={canvasRef}
|
|
||||||
className={styles.canvas}
|
|
||||||
onPointerDown={handlePointerDown}
|
|
||||||
onPointerUp={handlePointerUp}
|
|
||||||
onPointerMove={handlePointerMove}
|
|
||||||
onPointerOut={handlePointerUp}
|
|
||||||
></canvas>
|
|
||||||
{typeof userMark?.mark !== 'undefined' && (
|
|
||||||
<div className={styles.absolute}>
|
|
||||||
<MarkRenderSignature value={value} mark={userMark.mark} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className={styles.reset}>
|
|
||||||
<FontAwesomeIcon size="sm" icon={faEraser} onClick={handleReset} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import { MarkInputProps } from '../../types/mark'
|
|
||||||
import styles from '../MarkFormField/style.module.scss'
|
|
||||||
|
|
||||||
export const MarkInputText = ({
|
|
||||||
value,
|
|
||||||
handler,
|
|
||||||
placeholder
|
|
||||||
}: MarkInputProps) => {
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
className={styles.input}
|
|
||||||
placeholder={placeholder}
|
|
||||||
onChange={(e) => {
|
|
||||||
handler(e.currentTarget.value)
|
|
||||||
}}
|
|
||||||
value={value}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { MarkRenderProps } from '../../types/mark'
|
|
||||||
|
|
||||||
export const MarkRenderSignature = ({ value, mark }: MarkRenderProps) => {
|
|
||||||
const paths = value ? JSON.parse(value) : []
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg viewBox={`0 0 ${mark.location.width} ${mark.location.height}`}>
|
|
||||||
{paths.map((path: string) => (
|
|
||||||
<path d={path} stroke="black" fill="none" />
|
|
||||||
))}
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ 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'
|
|
||||||
|
|
||||||
interface PdfMarkItemProps {
|
interface PdfMarkItemProps {
|
||||||
userMark: CurrentUserMark
|
userMark: CurrentUserMark
|
||||||
@ -28,8 +27,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,9 +47,7 @@ const PdfMarkItem = forwardRef<HTMLDivElement, PdfMarkItemProps>(
|
|||||||
fontSize: inPx(from(pageWidth, FONT_SIZE))
|
fontSize: inPx(from(pageWidth, FONT_SIZE))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof MarkRenderComponent !== 'undefined' && (
|
{getMarkValue()}
|
||||||
<MarkRenderComponent value={getMarkValue()} mark={userMark.mark} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,8 @@ const PdfMarking = (props: PdfMarkingProps) => {
|
|||||||
// setCurrentUserMarks(updatedCurrentUserMarks)
|
// setCurrentUserMarks(updatedCurrentUserMarks)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const handleChange = (value: string) => setSelectedMarkValue(value)
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setSelectedMarkValue(event.target.value)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { MarkType } from '../types/drawing'
|
|
||||||
import { MarkConfigs } from '../types/mark'
|
|
||||||
import { MarkInputSignature } from './MarkInputs/Signature'
|
|
||||||
import { MarkInputText } from './MarkInputs/Text'
|
|
||||||
import { MarkRenderSignature } from './MarkRender/Signature'
|
|
||||||
|
|
||||||
export const MARK_TYPE_CONFIG: MarkConfigs = {
|
|
||||||
[MarkType.TEXT]: {
|
|
||||||
input: MarkInputText,
|
|
||||||
render: ({ value }) => <>{value}</>
|
|
||||||
},
|
|
||||||
[MarkType.SIGNATURE]: {
|
|
||||||
input: MarkInputSignature,
|
|
||||||
render: MarkRenderSignature
|
|
||||||
}
|
|
||||||
}
|
|
@ -55,7 +55,6 @@ 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'
|
|
||||||
|
|
||||||
interface PdfViewProps {
|
interface PdfViewProps {
|
||||||
files: CurrentUserFile[]
|
files: CurrentUserFile[]
|
||||||
@ -115,8 +114,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 +129,7 @@ const SlimPdfView = ({
|
|||||||
fontSize: inPx(from(page.width, FONT_SIZE))
|
fontSize: inPx(from(page.width, FONT_SIZE))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof MarkRenderComponent !== 'undefined' && (
|
{m.value}
|
||||||
<MarkRenderComponent value={m.value} mark={m} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -28,24 +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>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MarkConfigs = {
|
|
||||||
[key in MarkType]?: MarkConfig
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CurrentUserMark, Mark, MarkLocation } from '../types/mark.ts'
|
import { CurrentUserMark, Mark } from '../types/mark.ts'
|
||||||
import { hexToNpub } from './nostr.ts'
|
import { hexToNpub } from './nostr.ts'
|
||||||
import { Meta, SignedEventContent } from '../types'
|
import { Meta, SignedEventContent } from '../types'
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
@ -24,7 +24,6 @@ import {
|
|||||||
faStamp,
|
faStamp,
|
||||||
faTableCellsLarge
|
faTableCellsLarge
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { Config, optimize } from 'svgo'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes in an array of Marks already filtered by User.
|
* Takes in an array of Marks already filtered by User.
|
||||||
@ -159,11 +158,6 @@ export const DEFAULT_TOOLBOX: DrawTool[] = [
|
|||||||
icon: faT,
|
icon: faT,
|
||||||
label: 'Text'
|
label: 'Text'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
identifier: MarkType.SIGNATURE,
|
|
||||||
icon: faSignature,
|
|
||||||
label: 'Signature'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
identifier: MarkType.FULLNAME,
|
identifier: MarkType.FULLNAME,
|
||||||
icon: faIdCard,
|
icon: faIdCard,
|
||||||
@ -176,6 +170,12 @@ export const DEFAULT_TOOLBOX: DrawTool[] = [
|
|||||||
label: 'Job Title',
|
label: 'Job Title',
|
||||||
isComingSoon: true
|
isComingSoon: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.SIGNATURE,
|
||||||
|
icon: faSignature,
|
||||||
|
label: 'Signature',
|
||||||
|
isComingSoon: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.DATETIME,
|
identifier: MarkType.DATETIME,
|
||||||
icon: faClock,
|
icon: faClock,
|
||||||
@ -266,24 +266,6 @@ export const getToolboxLabelByMarkType = (markType: MarkType) => {
|
|||||||
return DEFAULT_TOOLBOX.find((t) => t.identifier === markType)?.label
|
return DEFAULT_TOOLBOX.find((t) => t.identifier === markType)?.label
|
||||||
}
|
}
|
||||||
|
|
||||||
export const optimizeSVG = (location: MarkLocation, paths: string[]) => {
|
|
||||||
const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" width="${location.width}" height="${location.height}">${paths.map((path) => `<path d="${path}" stroke="black" fill="none" />`).join('')}</svg>`
|
|
||||||
const optimizedSVG = optimize(svgContent, {
|
|
||||||
multipass: true, // Optimize multiple times if needed
|
|
||||||
floatPrecision: 2 // Adjust precision
|
|
||||||
} as Config)
|
|
||||||
|
|
||||||
return optimizedSVG.data
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getOptimizedPaths = (svgString: string) => {
|
|
||||||
const regex = / d="([^"]*)"/g
|
|
||||||
const matches = [...svgString.matchAll(regex)]
|
|
||||||
const pathValues = matches.map((match) => match[1])
|
|
||||||
|
|
||||||
return pathValues
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getCurrentUserMarks,
|
getCurrentUserMarks,
|
||||||
filterMarksByPubkey,
|
filterMarksByPubkey,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { MarkType, PdfPage } from '../types/drawing.ts'
|
import { PdfPage } from '../types/drawing.ts'
|
||||||
import { PDFDocument, PDFFont, PDFPage, rgb } from 'pdf-lib'
|
import { PDFDocument, PDFFont, PDFPage, rgb } from 'pdf-lib'
|
||||||
import { Mark } from '../types/mark.ts'
|
import { Mark } from '../types/mark.ts'
|
||||||
import * as PDFJS from 'pdfjs-dist'
|
import * as PDFJS from 'pdfjs-dist'
|
||||||
@ -132,17 +132,9 @@ export const addMarks = async (
|
|||||||
|
|
||||||
for (let i = 0; i < pages.length; i++) {
|
for (let i = 0; i < pages.length; i++) {
|
||||||
if (marksPerPage && Object.hasOwn(marksPerPage, i)) {
|
if (marksPerPage && Object.hasOwn(marksPerPage, i)) {
|
||||||
marksPerPage[i]?.forEach((mark) => {
|
marksPerPage[i]?.forEach((mark) =>
|
||||||
switch (mark.type) {
|
|
||||||
case MarkType.SIGNATURE:
|
|
||||||
drawSignatureText(mark, pages[i])
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
drawMarkText(mark, pages[i], robotoFont)
|
drawMarkText(mark, pages[i], robotoFont)
|
||||||
break
|
)
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,19 +245,3 @@ async function embedFont(pdf: PDFDocument) {
|
|||||||
const embeddedFont = await pdf.embedFont(fontBytes)
|
const embeddedFont = await pdf.embedFont(fontBytes)
|
||||||
return embeddedFont
|
return embeddedFont
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawSignatureText = (mark: Mark, page: PDFPage) => {
|
|
||||||
const { location } = mark
|
|
||||||
const { height } = page.getSize()
|
|
||||||
|
|
||||||
// Convert the mark location origin (top, left) to PDF origin (bottom, left)
|
|
||||||
const x = location.left
|
|
||||||
const y = height - location.top
|
|
||||||
|
|
||||||
if (hasValue(mark)) {
|
|
||||||
const paths = JSON.parse(mark.value!)
|
|
||||||
paths.forEach((d: string) => {
|
|
||||||
page.drawSvgPath(d, { x, y })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [react(), tsconfigPaths()],
|
||||||
react(),
|
|
||||||
tsconfigPaths(),
|
|
||||||
nodePolyfills({
|
|
||||||
include: ['os']
|
|
||||||
})
|
|
||||||
],
|
|
||||||
build: {
|
build: {
|
||||||
target: 'ES2022'
|
target: 'ES2022'
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user