@ -8,3 +8,5 @@ NEXT_PUBLIC_SENTRY_DSN=
|
||||
NEXT_PUBLIC_VIEWER_INTERNAL_URL=
|
||||
NEXT_PUBLIC_E2E_TEST=
|
||||
NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME=
|
||||
NEXT_PUBLIC_UNSPLASH_APP_NAME=
|
||||
NEXT_PUBLIC_UNSPLASH_ACCESS_KEY=
|
||||
|
@ -37,7 +37,9 @@
|
||||
"@trpc/next": "10.16.0",
|
||||
"@trpc/react-query": "10.16.0",
|
||||
"@trpc/server": "10.16.0",
|
||||
"@typebot.io/emails": "workspace:*",
|
||||
"@typebot.io/js": "workspace:*",
|
||||
"@typebot.io/next-international": "0.3.8",
|
||||
"@typebot.io/react": "workspace:*",
|
||||
"@udecode/plate-basic-marks": "20.4.0",
|
||||
"@udecode/plate-common": "^20.4.0",
|
||||
@ -57,7 +59,6 @@
|
||||
"codemirror": "6.0.1",
|
||||
"deep-object-diff": "1.1.9",
|
||||
"dequal": "2.0.3",
|
||||
"@typebot.io/emails": "workspace:*",
|
||||
"emojilib": "3.0.8",
|
||||
"focus-visible": "5.2.0",
|
||||
"framer-motion": "10.3.0",
|
||||
@ -73,7 +74,6 @@
|
||||
"minio": "7.0.32",
|
||||
"next": "13.2.4",
|
||||
"next-auth": "4.19.2",
|
||||
"@typebot.io/next-international": "0.3.8",
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"nodemailer": "6.9.1",
|
||||
"nprogress": "0.2.0",
|
||||
@ -93,12 +93,17 @@
|
||||
"swr": "2.1.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"trpc-openapi": "1.1.2",
|
||||
"unsplash-js": "^7.0.15",
|
||||
"use-debounce": "9.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.21.0",
|
||||
"@chakra-ui/styled-system": "2.6.1",
|
||||
"@playwright/test": "1.31.2",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/canvas-confetti": "1.6.0",
|
||||
"@types/google-spreadsheet": "3.3.1",
|
||||
"@types/jsonwebtoken": "9.0.1",
|
||||
@ -112,15 +117,11 @@
|
||||
"@types/qs": "6.9.7",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@typebot.io/prisma": "workspace:*",
|
||||
"dotenv": "16.0.3",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"superjson": "^1.12.2",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"typescript": "4.9.5",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"zod": "3.21.4"
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ export const EditableEmojiOrImageIcon = ({
|
||||
defaultUrl={icon ?? ''}
|
||||
onSubmit={onChangeIcon}
|
||||
isGiphyEnabled={false}
|
||||
isUnsplashEnabled={false}
|
||||
isEmojiEnabled={true}
|
||||
onClose={onClose}
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Flex, Stack, Text } from '@chakra-ui/react'
|
||||
import { GiphyFetch } from '@giphy/js-fetch-api'
|
||||
import { Grid } from '@giphy/react-components'
|
||||
import { GiphyLogo } from './GiphyLogo'
|
||||
import { GiphyLogo } from '../logos/GiphyLogo'
|
||||
import React, { useState } from 'react'
|
||||
import { env, isEmpty } from '@typebot.io/lib'
|
||||
import { TextInput } from '../inputs'
|
||||
@ -12,7 +12,7 @@ type GiphySearchFormProps = {
|
||||
|
||||
const giphyFetch = new GiphyFetch(env('GIPHY_API_KEY') as string)
|
||||
|
||||
export const GiphySearchForm = ({ onSubmit }: GiphySearchFormProps) => {
|
||||
export const GiphyPicker = ({ onSubmit }: GiphySearchFormProps) => {
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
|
||||
const fetchGifs = (offset: number) =>
|
||||
@ -24,7 +24,7 @@ export const GiphySearchForm = ({ onSubmit }: GiphySearchFormProps) => {
|
||||
return isEmpty(env('GIPHY_API_KEY')) ? (
|
||||
<Text>NEXT_PUBLIC_GIPHY_API_KEY is missing in environment</Text>
|
||||
) : (
|
||||
<Stack>
|
||||
<Stack spacing={4} pt="2">
|
||||
<Flex align="center">
|
||||
<TextInput
|
||||
autoFocus
|
@ -1,9 +1,12 @@
|
||||
import { useState } from 'react'
|
||||
import { Button, Flex, HStack, Stack } from '@chakra-ui/react'
|
||||
import { UploadButton } from './UploadButton'
|
||||
import { GiphySearchForm } from './GiphySearchForm'
|
||||
import { GiphyPicker } from './GiphyPicker'
|
||||
import { TextInput } from '../inputs/TextInput'
|
||||
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
||||
import { UnsplashPicker } from './UnsplashPicker'
|
||||
|
||||
type Tabs = 'link' | 'upload' | 'giphy' | 'emoji' | 'unsplash'
|
||||
|
||||
type Props = {
|
||||
filePath: string
|
||||
@ -11,6 +14,8 @@ type Props = {
|
||||
defaultUrl?: string
|
||||
isEmojiEnabled?: boolean
|
||||
isGiphyEnabled?: boolean
|
||||
isUnsplashEnabled?: boolean
|
||||
imageSize?: 'small' | 'regular' | 'thumb'
|
||||
onSubmit: (url: string) => void
|
||||
onClose?: () => void
|
||||
}
|
||||
@ -22,11 +27,13 @@ export const ImageUploadContent = ({
|
||||
onSubmit,
|
||||
isEmojiEnabled = false,
|
||||
isGiphyEnabled = true,
|
||||
isUnsplashEnabled = true,
|
||||
imageSize = 'regular',
|
||||
onClose,
|
||||
}: Props) => {
|
||||
const [currentTab, setCurrentTab] = useState<
|
||||
'link' | 'upload' | 'giphy' | 'emoji'
|
||||
>(isEmojiEnabled ? 'emoji' : 'link')
|
||||
const [currentTab, setCurrentTab] = useState<Tabs>(
|
||||
isEmojiEnabled ? 'emoji' : 'upload'
|
||||
)
|
||||
|
||||
const handleSubmit = (url: string) => {
|
||||
onSubmit(url)
|
||||
@ -68,12 +75,22 @@ export const ImageUploadContent = ({
|
||||
Giphy
|
||||
</Button>
|
||||
)}
|
||||
{isUnsplashEnabled && (
|
||||
<Button
|
||||
variant={currentTab === 'unsplash' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('unsplash')}
|
||||
size="sm"
|
||||
>
|
||||
Unsplash
|
||||
</Button>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<BodyContent
|
||||
filePath={filePath}
|
||||
includeFileName={includeFileName}
|
||||
tab={currentTab}
|
||||
imageSize={imageSize}
|
||||
onSubmit={handleSubmit}
|
||||
defaultUrl={defaultUrl}
|
||||
/>
|
||||
@ -86,12 +103,14 @@ const BodyContent = ({
|
||||
filePath,
|
||||
tab,
|
||||
defaultUrl,
|
||||
imageSize,
|
||||
onSubmit,
|
||||
}: {
|
||||
includeFileName?: boolean
|
||||
filePath: string
|
||||
tab: 'upload' | 'link' | 'giphy' | 'emoji'
|
||||
tab: Tabs
|
||||
defaultUrl?: string
|
||||
imageSize: 'small' | 'regular' | 'thumb'
|
||||
onSubmit: (url: string) => void
|
||||
}) => {
|
||||
switch (tab) {
|
||||
@ -109,6 +128,8 @@ const BodyContent = ({
|
||||
return <GiphyContent onNewUrl={onSubmit} />
|
||||
case 'emoji':
|
||||
return <EmojiSearchableList onEmojiSelected={onSubmit} />
|
||||
case 'unsplash':
|
||||
return <UnsplashPicker imageSize={imageSize} onImageSelect={onSubmit} />
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,5 +167,5 @@ const EmbedLinkContent = ({
|
||||
)
|
||||
|
||||
const GiphyContent = ({ onNewUrl }: ContentProps) => (
|
||||
<GiphySearchForm onSubmit={onNewUrl} />
|
||||
<GiphyPicker onSubmit={onNewUrl} />
|
||||
)
|
||||
|
@ -0,0 +1,219 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
Flex,
|
||||
Grid,
|
||||
GridItem,
|
||||
HStack,
|
||||
Image,
|
||||
Link,
|
||||
Spinner,
|
||||
Stack,
|
||||
Text,
|
||||
} from '@chakra-ui/react'
|
||||
import { env, isDefined, isEmpty } from '@typebot.io/lib'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { createApi } from 'unsplash-js'
|
||||
import { Basic as UnsplashImage } from 'unsplash-js/dist/methods/photos/types'
|
||||
import { TextInput } from '../inputs'
|
||||
import { UnsplashLogo } from '../logos/UnsplashLogo'
|
||||
import { TextLink } from '../TextLink'
|
||||
|
||||
const api = createApi({
|
||||
accessKey: env('UNSPLASH_ACCESS_KEY') ?? '',
|
||||
})
|
||||
|
||||
type Props = {
|
||||
imageSize: 'regular' | 'small' | 'thumb'
|
||||
onImageSelect: (imageUrl: string) => void
|
||||
}
|
||||
|
||||
export const UnsplashPicker = ({ imageSize, onImageSelect }: Props) => {
|
||||
const [isFetching, setIsFetching] = useState(false)
|
||||
const [images, setImages] = useState<UnsplashImage[]>([])
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const scrollContainer = useRef<HTMLDivElement>(null)
|
||||
const bottomAnchor = useRef<HTMLDivElement>(null)
|
||||
|
||||
const [nextPage, setNextPage] = useState(0)
|
||||
|
||||
const fetchNewImages = useCallback(async (query: string, page: number) => {
|
||||
console.log('Fetch images', query, page)
|
||||
if (query === '') return searchRandomImages()
|
||||
if (query.length <= 2) return
|
||||
setError(null)
|
||||
setIsFetching(true)
|
||||
try {
|
||||
const result = await api.search.getPhotos({
|
||||
query,
|
||||
perPage: 30,
|
||||
orientation: 'landscape',
|
||||
page,
|
||||
})
|
||||
if (result.errors) setError(result.errors[0])
|
||||
if (isDefined(result.response)) {
|
||||
if (page === 0) setImages(result.response.results)
|
||||
else
|
||||
setImages((images) => [
|
||||
...images,
|
||||
...(result.response?.results ?? []),
|
||||
])
|
||||
setNextPage((page) => page + 1)
|
||||
}
|
||||
} catch (err) {
|
||||
if (err && typeof err === 'object' && 'message' in err)
|
||||
setError(err.message as string)
|
||||
setError('Something went wrong')
|
||||
}
|
||||
setIsFetching(false)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!bottomAnchor.current) return
|
||||
const observer = new IntersectionObserver(
|
||||
(entities: IntersectionObserverEntry[]) => {
|
||||
console.log('Intersection observer', entities)
|
||||
const target = entities[0]
|
||||
if (target.isIntersecting) fetchNewImages(searchQuery, nextPage + 1)
|
||||
},
|
||||
{
|
||||
root: scrollContainer.current,
|
||||
}
|
||||
)
|
||||
if (bottomAnchor.current && nextPage > 0)
|
||||
observer.observe(bottomAnchor.current)
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [fetchNewImages, nextPage, searchQuery])
|
||||
|
||||
const searchRandomImages = async () => {
|
||||
setError(null)
|
||||
setIsFetching(true)
|
||||
try {
|
||||
const result = await api.photos.getRandom({
|
||||
count: 30,
|
||||
orientation: 'landscape',
|
||||
})
|
||||
|
||||
if (result.errors) setError(result.errors[0])
|
||||
if (isDefined(result.response))
|
||||
setImages(
|
||||
Array.isArray(result.response) ? result.response : [result.response]
|
||||
)
|
||||
} catch (err) {
|
||||
if (err && typeof err === 'object' && 'message' in err)
|
||||
setError(err.message as string)
|
||||
setError('Something went wrong')
|
||||
}
|
||||
setIsFetching(false)
|
||||
}
|
||||
|
||||
const selectImage = (image: UnsplashImage) => {
|
||||
const url = image.urls[imageSize]
|
||||
api.photos.trackDownload({
|
||||
downloadLocation: image.links.download_location,
|
||||
})
|
||||
if (isDefined(url)) onImageSelect(url)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
searchRandomImages()
|
||||
}, [])
|
||||
|
||||
if (isEmpty(env('UNSPLASH_ACCESS_KEY')))
|
||||
return (
|
||||
<Text>NEXT_PUBLIC_UNSPLASH_ACCESS_KEY is missing in environment</Text>
|
||||
)
|
||||
|
||||
return (
|
||||
<Stack spacing={4} pt="2">
|
||||
<HStack align="center">
|
||||
<TextInput
|
||||
autoFocus
|
||||
placeholder="Search..."
|
||||
onChange={(query) => {
|
||||
setSearchQuery(query)
|
||||
fetchNewImages(query, 0)
|
||||
}}
|
||||
withVariableButton={false}
|
||||
/>
|
||||
<Link
|
||||
isExternal
|
||||
href={`https://unsplash.com/?utm_source=${env(
|
||||
'UNSPLASH_APP_NAME'
|
||||
)}&utm_medium=referral`}
|
||||
>
|
||||
<UnsplashLogo width="80px" />
|
||||
</Link>
|
||||
</HStack>
|
||||
{isDefined(error) && (
|
||||
<Alert status="error">
|
||||
<AlertIcon />
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
<Stack overflowY="scroll" maxH="400px" ref={scrollContainer}>
|
||||
{images.length > 0 && (
|
||||
<Grid templateColumns="repeat(4, 1fr)" columnGap={2} rowGap={3}>
|
||||
{images.map((image, index) => (
|
||||
<GridItem
|
||||
as={Stack}
|
||||
key={image.id}
|
||||
boxSize="100%"
|
||||
spacing="0"
|
||||
ref={index === images.length - 1 ? bottomAnchor : undefined}
|
||||
>
|
||||
<UnsplashImage
|
||||
image={image}
|
||||
onClick={() => selectImage(image)}
|
||||
/>
|
||||
</GridItem>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
{isFetching && (
|
||||
<Flex justifyContent="center" py="4">
|
||||
<Spinner />
|
||||
</Flex>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
type UnsplashImageProps = {
|
||||
image: UnsplashImage
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const UnsplashImage = ({ image, onClick }: UnsplashImageProps) => {
|
||||
const { user, urls, alt_description } = image
|
||||
|
||||
return (
|
||||
<>
|
||||
<Image
|
||||
objectFit="cover"
|
||||
src={urls.thumb}
|
||||
alt={alt_description ?? 'Unsplash image'}
|
||||
onClick={onClick}
|
||||
rounded="md"
|
||||
h="100%"
|
||||
cursor="pointer"
|
||||
/>
|
||||
<TextLink
|
||||
fontSize="xs"
|
||||
isExternal
|
||||
href={`https://unsplash.com/@${user.username}?utm_source=${env(
|
||||
'UNSPLASH_APP_NAME'
|
||||
)}&utm_medium=referral`}
|
||||
noOfLines={1}
|
||||
color="gray.500"
|
||||
>
|
||||
{user.name}
|
||||
</TextLink>
|
||||
</>
|
||||
)
|
||||
}
|
@ -13,6 +13,7 @@ export const TextLink = ({
|
||||
scroll,
|
||||
prefetch,
|
||||
isExternal,
|
||||
noOfLines,
|
||||
...textProps
|
||||
}: TextLinkProps) => (
|
||||
<Link
|
||||
@ -26,7 +27,9 @@ export const TextLink = ({
|
||||
<chakra.span textDecor="underline" display="inline-block" {...textProps}>
|
||||
{isExternal ? (
|
||||
<HStack spacing={1}>
|
||||
<chakra.span>{children}</chakra.span>
|
||||
<chakra.span noOfLines={noOfLines} maxW="100%">
|
||||
{children}
|
||||
</chakra.span>
|
||||
<ExternalLinkIcon />
|
||||
</HStack>
|
||||
) : (
|
||||
|
7
apps/builder/src/components/logos/UnsplashLogo.tsx
Normal file
7
apps/builder/src/components/logos/UnsplashLogo.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import { IconProps, Icon } from '@chakra-ui/react'
|
||||
|
||||
export const UnsplashLogo = (props: IconProps) => (
|
||||
<Icon viewBox="0 0 457.19 104.19" {...props}>
|
||||
<path d="M59.88 38.66h27.53v48.75H0V38.66h27.53v24.37h32.35zm93 25c0 8.25-5.45 13.13-12.9 13.13-7.28 0-12.81-4.88-12.81-13.13V24.41h-12.22v39.13c0 15.45 11 25.21 25.06 25.21s25.15-9.76 25.15-25.21V24.41h-12.25zm43.7-21.13c-4.7 0-9.94 2-12.6 6.57v-5.41h-11.45v43.64h11.81v-25.1c0-5 3-9 8.16-9 5.68 0 8.08 3.82 8.08 8.7v25.4h11.8V59.82c.03-9.59-4.94-17.31-15.77-17.31zm43.31 18.37l-6.48-1.33c-2.47-.5-4-1.77-4-3.9 0-2.49 2.23-4.35 5.33-4.35 4.36 0 6.09 2.25 6.51 4.88h10.18c-.08-6-4.83-13.84-16.51-13.84-9.41 0-16.33 6.47-16.33 14.28 0 6.13 3.81 11.19 12.24 13l6.05 1.33c3.37.71 4.7 2.31 4.7 4.26 0 2.31-2.14 4.35-6 4.35-4.71 0-7.27-2.68-7.87-5.79h-10.5c.59 6.53 5.32 14.84 18.46 14.84 11.45 0 17.22-7.28 17.22-14.38-.01-6.36-4.36-11.59-12.97-13.37zm63.19 4.53c0 13.22-8.26 23-20.59 23-6 0-10.48-2.4-12.61-5.33v21.13h-11.8V43.67h11.45v5.41c2-3.37 6.83-6.39 13.4-6.39 12.81 0 20.18 9.76 20.18 22.72zm-11.63.09c0-7.72-4.79-12.25-10.83-12.25s-10.91 4.53-10.91 12.25 4.88 12.33 10.91 12.33 10.91-4.54 10.91-12.35zm68-21.83h11.45v43.64h-11.8v-5.31c-2 3.5-6.57 6.38-12.61 6.38-12.33 0-20.59-9.77-20.59-23 0-13 7.37-22.72 20.15-22.72 6.57 0 11.32 3.05 13.4 6.39zm-.18 21.83c0-7.72-4.88-12.25-10.91-12.25s-10.83 4.51-10.83 12.23 4.79 12.33 10.83 12.33 10.92-4.6 10.92-12.33zm-50.66 21.81h11.8V24.41h-11.8zm132.35-44.81c-4.17 0-9 1.41-11.81 4.78V24.41h-11.8v62.91h11.8V61.68c.27-4.8 3.2-8.52 8.17-8.52 5.68 0 8.08 3.83 8.07 8.71v25.47h11.81V59.82c-.01-9.59-5.15-17.3-16.24-17.3zm-42 18.36l-6.43-1.33c-2.47-.5-4-1.77-4-3.9 0-2.49 2.22-4.35 5.33-4.35 4.35 0 6.08 2.25 6.5 4.88h10.17c-.08-6-4.83-13.84-16.51-13.84-9.41 0-16.33 6.47-16.33 14.28 0 6.13 3.82 11.19 12.25 13l6 1.33c3.37.71 4.7 2.31 4.7 4.26 0 2.31-2.14 4.35-6 4.35-4.71 0-7.27-2.68-7.87-5.79h-10.49c.58 6.53 5.31 14.84 18.45 14.84 11.45 0 17.22-7.28 17.22-14.38 0-6.34-4.35-11.57-12.95-13.35zM59.88 0H27.53v24.37h32.35z" />
|
||||
</Icon>
|
||||
)
|
@ -65,6 +65,7 @@ export const MetadataForm = ({
|
||||
defaultUrl={metadata.favIconUrl ?? ''}
|
||||
onSubmit={handleFavIconSubmit}
|
||||
isGiphyEnabled={false}
|
||||
imageSize="thumb"
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
@ -91,6 +91,7 @@ export const AvatarForm = ({
|
||||
<ImageUploadContent
|
||||
filePath={uploadFilePath}
|
||||
defaultUrl={avatarProps?.url}
|
||||
imageSize="thumb"
|
||||
onSubmit={handleImageUrl}
|
||||
/>
|
||||
</PopoverContent>
|
||||
|
@ -180,6 +180,15 @@ Used to search for GIF. You can create a Giphy app [here](https://developers.gip
|
||||
| ------------------------- | ------- | ------------- |
|
||||
| NEXT_PUBLIC_GIPHY_API_KEY | | Giphy API key |
|
||||
|
||||
## Unsplash (image picker)
|
||||
|
||||
Used to search for images. You can create a Giphy app [here](https://unsplash.com/developers)
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| ------------------------------- | ------- | ----------------- |
|
||||
| NEXT_PUBLIC_UNSPLASH_APP_NAME | | Unsplash App name |
|
||||
| NEXT_PUBLIC_UNSPLASH_ACCESS_KEY | | Unsplash API key |
|
||||
|
||||
## Others
|
||||
|
||||
<details><summary><h3>Show</h3></summary>
|
||||
|
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@ -121,6 +121,7 @@ importers:
|
||||
tinycolor2: 1.6.0
|
||||
trpc-openapi: 1.1.2
|
||||
typescript: 4.9.5
|
||||
unsplash-js: ^7.0.15
|
||||
use-debounce: 9.0.3
|
||||
zod: 3.21.4
|
||||
dependencies:
|
||||
@ -204,6 +205,7 @@ importers:
|
||||
swr: 2.1.0_react@18.2.0
|
||||
tinycolor2: 1.6.0
|
||||
trpc-openapi: 1.1.2_k6tpxpkoeqrvdlcqns422rglmm
|
||||
unsplash-js: 7.0.15
|
||||
use-debounce: 9.0.3_react@18.2.0
|
||||
devDependencies:
|
||||
'@babel/core': 7.21.0
|
||||
@ -6829,6 +6831,10 @@ packages:
|
||||
'@types/node': 18.15.3
|
||||
dev: false
|
||||
|
||||
/@types/content-type/1.1.5:
|
||||
resolution: {integrity: sha512-dgMN+syt1xb7Hk8LU6AODOfPlvz5z1CbXpPuJE5ZrX9STfBOIXF09pEB8N7a97WT9dbngt3ksDCm6GW6yMrxfQ==}
|
||||
dev: false
|
||||
|
||||
/@types/cors/2.8.13:
|
||||
resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==}
|
||||
dependencies:
|
||||
@ -19688,6 +19694,14 @@ packages:
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/unsplash-js/7.0.15:
|
||||
resolution: {integrity: sha512-WGqKp9wl2m2tAUPyw2eMZs/KICR+A52tCaRapzVXWxkA4pjHqsaGwiJXTEW7hBy4Pu0QmP6KxTt2jST3tluawA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
'@types/content-type': 1.1.5
|
||||
content-type: 1.0.5
|
||||
dev: false
|
||||
|
||||
/untildify/4.0.0:
|
||||
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
|
||||
engines: {node: '>=8'}
|
||||
|
Reference in New Issue
Block a user