Release to main #216
@ -108,7 +108,6 @@ export const CreatePage = () => {
|
|||||||
const [drawnFiles, setDrawnFiles] = useState<SigitFile[]>([])
|
const [drawnFiles, setDrawnFiles] = useState<SigitFile[]>([])
|
||||||
|
|
||||||
const [selectedTool, setSelectedTool] = useState<DrawTool>()
|
const [selectedTool, setSelectedTool] = useState<DrawTool>()
|
||||||
const [toolbox] = useState<DrawTool[]>(DEFAULT_TOOLBOX)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the drawing tool
|
* Changes the drawing tool
|
||||||
@ -833,28 +832,36 @@ export const CreatePage = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`${styles.paperGroup} ${styles.toolbox}`}>
|
<div className={`${styles.paperGroup} ${styles.toolbox}`}>
|
||||||
{toolbox.map((drawTool: DrawTool, index: number) => {
|
{DEFAULT_TOOLBOX.filter((drawTool) => !drawTool.isHidden).map(
|
||||||
return (
|
(drawTool: DrawTool, index: number) => {
|
||||||
<div
|
return (
|
||||||
key={index}
|
<div
|
||||||
{...(drawTool.active && {
|
key={index}
|
||||||
onClick: () => handleToolSelect(drawTool)
|
{...(!drawTool.isComingSoon && {
|
||||||
})}
|
onClick: () => handleToolSelect(drawTool)
|
||||||
className={`${styles.toolItem} ${selectedTool?.identifier === drawTool.identifier ? styles.selected : ''} ${!drawTool.active ? styles.comingSoon : ''}
|
})}
|
||||||
|
className={`${styles.toolItem} ${selectedTool?.identifier === drawTool.identifier ? styles.selected : ''} ${drawTool.isComingSoon ? styles.comingSoon : ''}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon fontSize={'15px'} icon={drawTool.icon} />
|
<FontAwesomeIcon
|
||||||
{drawTool.label}
|
fontSize={'15px'}
|
||||||
{drawTool.active ? (
|
icon={drawTool.icon}
|
||||||
<FontAwesomeIcon fontSize={'15px'} icon={faEllipsis} />
|
/>
|
||||||
) : (
|
{drawTool.label}
|
||||||
<span className={styles.comingSoonPlaceholder}>
|
{!drawTool.isComingSoon ? (
|
||||||
Coming soon
|
<FontAwesomeIcon
|
||||||
</span>
|
fontSize={'15px'}
|
||||||
)}
|
icon={faEllipsis}
|
||||||
</div>
|
/>
|
||||||
)
|
) : (
|
||||||
})}
|
<span className={styles.comingSoonPlaceholder}>
|
||||||
|
Coming soon
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button onClick={handleCreate} variant="contained">
|
<Button onClick={handleCreate} variant="contained">
|
||||||
|
@ -31,7 +31,10 @@ export interface DrawTool {
|
|||||||
icon: IconDefinition
|
icon: IconDefinition
|
||||||
defaultValue?: string
|
defaultValue?: string
|
||||||
selected?: boolean
|
selected?: boolean
|
||||||
active?: boolean
|
/** show or hide the toolbox item */
|
||||||
|
isHidden?: boolean
|
||||||
|
/** show or hide "coming soon" message on the toolbox item */
|
||||||
|
isComingSoon?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MarkType {
|
export enum MarkType {
|
||||||
|
@ -21,6 +21,8 @@ export const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000
|
|||||||
|
|
||||||
export const SIGIT_RELAY = 'wss://relay.sigit.io'
|
export const SIGIT_RELAY = 'wss://relay.sigit.io'
|
||||||
|
|
||||||
|
export const SIGIT_BLOSSOM = 'https://blossom.sigit.io'
|
||||||
|
|
||||||
export const DEFAULT_LOOK_UP_RELAY_LIST = [
|
export const DEFAULT_LOOK_UP_RELAY_LIST = [
|
||||||
SIGIT_RELAY,
|
SIGIT_RELAY,
|
||||||
'wss://user.kindpag.es',
|
'wss://user.kindpag.es',
|
||||||
|
@ -3,14 +3,26 @@ 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'
|
||||||
import { EMPTY } from './const.ts'
|
import { EMPTY } from './const.ts'
|
||||||
import { MarkType } from '../types/drawing.ts'
|
import { DrawTool, MarkType } from '../types/drawing.ts'
|
||||||
import {
|
import {
|
||||||
faT,
|
faT,
|
||||||
faSignature,
|
faSignature,
|
||||||
faBriefcase,
|
faBriefcase,
|
||||||
faIdCard,
|
faIdCard,
|
||||||
faClock,
|
faClock,
|
||||||
fa1
|
fa1,
|
||||||
|
faCalendarDays,
|
||||||
|
faCheckDouble,
|
||||||
|
faCircleDot,
|
||||||
|
faCreditCard,
|
||||||
|
faHeading,
|
||||||
|
faImage,
|
||||||
|
faPaperclip,
|
||||||
|
faPhone,
|
||||||
|
faSquareCaretDown,
|
||||||
|
faSquareCheck,
|
||||||
|
faStamp,
|
||||||
|
faTableCellsLarge
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -140,115 +152,114 @@ const findOtherUserMarks = (marks: Mark[], pubkey: string): Mark[] => {
|
|||||||
return marks.filter((mark) => mark.npub !== hexToNpub(pubkey))
|
return marks.filter((mark) => mark.npub !== hexToNpub(pubkey))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_TOOLBOX = [
|
export const DEFAULT_TOOLBOX: DrawTool[] = [
|
||||||
{
|
{
|
||||||
identifier: MarkType.FULLNAME,
|
identifier: MarkType.FULLNAME,
|
||||||
icon: faIdCard,
|
icon: faIdCard,
|
||||||
label: 'Full Name',
|
label: 'Full Name',
|
||||||
active: false
|
isComingSoon: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.JOBTITLE,
|
identifier: MarkType.JOBTITLE,
|
||||||
icon: faBriefcase,
|
icon: faBriefcase,
|
||||||
label: 'Job Title',
|
label: 'Job Title',
|
||||||
active: false
|
isComingSoon: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.SIGNATURE,
|
identifier: MarkType.SIGNATURE,
|
||||||
icon: faSignature,
|
icon: faSignature,
|
||||||
label: 'Signature',
|
label: 'Signature',
|
||||||
active: false
|
isComingSoon: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.DATETIME,
|
identifier: MarkType.DATETIME,
|
||||||
icon: faClock,
|
icon: faClock,
|
||||||
label: 'Date Time',
|
label: 'Date Time',
|
||||||
active: false
|
isComingSoon: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.TEXT,
|
identifier: MarkType.TEXT,
|
||||||
icon: faT,
|
icon: faT,
|
||||||
label: 'Text',
|
label: 'Text'
|
||||||
active: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
identifier: MarkType.NUMBER,
|
identifier: MarkType.NUMBER,
|
||||||
icon: fa1,
|
icon: fa1,
|
||||||
label: 'Number',
|
label: 'Number',
|
||||||
active: false
|
isComingSoon: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.INITIALS,
|
||||||
|
icon: faHeading,
|
||||||
|
label: 'Initials',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.DATE,
|
||||||
|
icon: faCalendarDays,
|
||||||
|
label: 'Date',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.IMAGES,
|
||||||
|
icon: faImage,
|
||||||
|
label: 'Images',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.CHECKBOX,
|
||||||
|
icon: faSquareCheck,
|
||||||
|
label: 'Checkbox',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.MULTIPLE,
|
||||||
|
icon: faCheckDouble,
|
||||||
|
label: 'Multiple',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.FILE,
|
||||||
|
icon: faPaperclip,
|
||||||
|
label: 'File',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.RADIO,
|
||||||
|
icon: faCircleDot,
|
||||||
|
label: 'Radio',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.SELECT,
|
||||||
|
icon: faSquareCaretDown,
|
||||||
|
label: 'Select',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.CELLS,
|
||||||
|
icon: faTableCellsLarge,
|
||||||
|
label: 'Cells',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.STAMP,
|
||||||
|
icon: faStamp,
|
||||||
|
label: 'Stamp',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.PAYMENT,
|
||||||
|
icon: faCreditCard,
|
||||||
|
label: 'Payment',
|
||||||
|
isHidden: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
identifier: MarkType.PHONE,
|
||||||
|
icon: faPhone,
|
||||||
|
label: 'Phone',
|
||||||
|
isHidden: true
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// identifier: MarkType.INITIALS,
|
|
||||||
// icon: faHeading,
|
|
||||||
// label: 'Initials',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.DATE,
|
|
||||||
// icon: faCalendarDays,
|
|
||||||
// label: 'Date',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.IMAGES,
|
|
||||||
// icon: faImage,
|
|
||||||
// label: 'Images',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.CHECKBOX,
|
|
||||||
// icon: faSquareCheck,
|
|
||||||
// label: 'Checkbox',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.MULTIPLE,
|
|
||||||
// icon: faCheckDouble,
|
|
||||||
// label: 'Multiple',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.FILE,
|
|
||||||
// icon: faPaperclip,
|
|
||||||
// label: 'File',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.RADIO,
|
|
||||||
// icon: faCircleDot,
|
|
||||||
// label: 'Radio',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.SELECT,
|
|
||||||
// icon: faSquareCaretDown,
|
|
||||||
// label: 'Select',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.CELLS,
|
|
||||||
// icon: faTableCellsLarge,
|
|
||||||
// label: 'Cells',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.STAMP,
|
|
||||||
// icon: faStamp,
|
|
||||||
// label: 'Stamp',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.PAYMENT,
|
|
||||||
// icon: faCreditCard,
|
|
||||||
// label: 'Payment',
|
|
||||||
// active: false
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// identifier: MarkType.PHONE,
|
|
||||||
// icon: faPhone,
|
|
||||||
// label: 'Phone',
|
|
||||||
// active: false
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
export const getToolboxLabelByMarkType = (markType: MarkType) => {
|
export const getToolboxLabelByMarkType = (markType: MarkType) => {
|
||||||
|
@ -16,6 +16,8 @@ import { CreateSignatureEventContent, Meta } from '../types'
|
|||||||
import { hexToNpub, unixNow } from './nostr'
|
import { hexToNpub, unixNow } from './nostr'
|
||||||
import { parseJson } from './string'
|
import { parseJson } from './string'
|
||||||
import { hexToBytes } from '@noble/hashes/utils'
|
import { hexToBytes } from '@noble/hashes/utils'
|
||||||
|
import { getHash } from './hash.ts'
|
||||||
|
import { SIGIT_BLOSSOM } from './const.ts'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uploads a file to a file storage service.
|
* Uploads a file to a file storage service.
|
||||||
@ -25,12 +27,18 @@ import { hexToBytes } from '@noble/hashes/utils'
|
|||||||
*/
|
*/
|
||||||
export const uploadToFileStorage = async (file: File) => {
|
export const uploadToFileStorage = async (file: File) => {
|
||||||
// Define event metadata for authorization
|
// Define event metadata for authorization
|
||||||
|
const hash = await getHash(await file.arrayBuffer())
|
||||||
|
if (!hash) {
|
||||||
|
throw new Error("Can't get file hash.")
|
||||||
|
}
|
||||||
|
|
||||||
const event: EventTemplate = {
|
const event: EventTemplate = {
|
||||||
kind: 24242,
|
kind: 24242,
|
||||||
content: 'Authorize Upload',
|
content: 'Authorize Upload',
|
||||||
created_at: unixNow(),
|
created_at: unixNow(),
|
||||||
tags: [
|
tags: [
|
||||||
['t', 'upload'],
|
['t', 'upload'],
|
||||||
|
['x', hash],
|
||||||
['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
|
['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
|
||||||
['name', file.name],
|
['name', file.name],
|
||||||
['size', String(file.size)]
|
['size', String(file.size)]
|
||||||
@ -47,11 +55,8 @@ export const uploadToFileStorage = async (file: File) => {
|
|||||||
// Sign the authorization event using the dedicated key stored in user app data
|
// Sign the authorization event using the dedicated key stored in user app data
|
||||||
const authEvent = finalizeEvent(event, hexToBytes(key))
|
const authEvent = finalizeEvent(event, hexToBytes(key))
|
||||||
|
|
||||||
// URL of the file storage service
|
|
||||||
const FILE_STORAGE_URL = 'https://blossom.sigit.io' // REFACTOR: should be an env
|
|
||||||
|
|
||||||
// Upload the file to the file storage service using Axios
|
// Upload the file to the file storage service using Axios
|
||||||
const response = await axios.put(`${FILE_STORAGE_URL}/upload`, file, {
|
const response = await axios.put(`${SIGIT_BLOSSOM}/upload`, file, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Nostr ' + btoa(JSON.stringify(authEvent)), // Set authorization header
|
Authorization: 'Nostr ' + btoa(JSON.stringify(authEvent)), // Set authorization header
|
||||||
'Content-Type': 'application/sigit' // Set content type header
|
'Content-Type': 'application/sigit' // Set content type header
|
||||||
|
@ -35,6 +35,7 @@ import { getDefaultRelayMap } from './relays'
|
|||||||
import { parseJson, removeLeadingSlash } from './string'
|
import { parseJson, removeLeadingSlash } from './string'
|
||||||
import { timeout } from './utils'
|
import { timeout } from './utils'
|
||||||
import { getHash } from './hash'
|
import { getHash } from './hash'
|
||||||
|
import { SIGIT_BLOSSOM } from './const.ts'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a `d` tag for userAppData
|
* Generates a `d` tag for userAppData
|
||||||
@ -723,6 +724,11 @@ const uploadUserAppDataToBlossom = async (
|
|||||||
type: 'application/octet-stream'
|
type: 'application/octet-stream'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const hash = await getHash(await file.arrayBuffer())
|
||||||
|
if (!hash) {
|
||||||
|
throw new Error("Can't get file hash.")
|
||||||
|
}
|
||||||
|
|
||||||
// Define event metadata for authorization
|
// Define event metadata for authorization
|
||||||
const event: EventTemplate = {
|
const event: EventTemplate = {
|
||||||
kind: 24242,
|
kind: 24242,
|
||||||
@ -730,6 +736,7 @@ const uploadUserAppDataToBlossom = async (
|
|||||||
created_at: unixNow(),
|
created_at: unixNow(),
|
||||||
tags: [
|
tags: [
|
||||||
['t', 'upload'],
|
['t', 'upload'],
|
||||||
|
['x', hash],
|
||||||
['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
|
['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
|
||||||
['name', file.name],
|
['name', file.name],
|
||||||
['size', String(file.size)]
|
['size', String(file.size)]
|
||||||
@ -739,11 +746,8 @@ const uploadUserAppDataToBlossom = async (
|
|||||||
// Finalize the event with the private key
|
// Finalize the event with the private key
|
||||||
const authEvent = finalizeEvent(event, hexToBytes(privateKey))
|
const authEvent = finalizeEvent(event, hexToBytes(privateKey))
|
||||||
|
|
||||||
// URL of the file storage service
|
|
||||||
const FILE_STORAGE_URL = 'https://blossom.sigit.io'
|
|
||||||
|
|
||||||
// Upload the file to the file storage service using Axios
|
// Upload the file to the file storage service using Axios
|
||||||
const response = await axios.put(`${FILE_STORAGE_URL}/upload`, file, {
|
const response = await axios.put(`${SIGIT_BLOSSOM}/upload`, file, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Nostr ' + btoa(JSON.stringify(authEvent)) // Set authorization header
|
Authorization: 'Nostr ' + btoa(JSON.stringify(authEvent)) // Set authorization header
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user