Merge pull request #210 from useplunk/email-view
Add ability to view transactional email in contacts page
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plunk",
|
"name": "plunk",
|
||||||
"version": "1.2.1",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "agpl-3.0",
|
"license": "agpl-3.0",
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"@uiball/loaders": "^1.3.1",
|
"@uiball/loaders": "^1.3.1",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"dayjs": "^1.11.12",
|
"dayjs": "^1.11.12",
|
||||||
|
"dompurify": "^3.2.6",
|
||||||
"framer-motion": "^11.3.7",
|
"framer-motion": "^11.3.7",
|
||||||
"jotai": "2.9.0",
|
"jotai": "2.9.0",
|
||||||
"lucide-react": "^0.408.0",
|
"lucide-react": "^0.408.0",
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ import React, { useEffect, useState } from "react";
|
|||||||
import {useFieldArray, useForm} from "react-hook-form";
|
import {useFieldArray, useForm} from "react-hook-form";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
import { Card, Empty, FullscreenLoader, Input, Modal, Toggle } from "../../components";
|
import {Badge, Card, Empty, FullscreenLoader, Input, Modal, Toggle} from "../../components";
|
||||||
import {Dashboard} from "../../layouts";
|
import {Dashboard} from "../../layouts";
|
||||||
import {useContact} from "../../lib/hooks/contacts";
|
import {useContact} from "../../lib/hooks/contacts";
|
||||||
import {useActiveProject} from "../../lib/hooks/projects";
|
import {useActiveProject} from "../../lib/hooks/projects";
|
||||||
import {network} from "../../lib/network";
|
import {network} from "../../lib/network";
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
|
|
||||||
interface ContactValues {
|
interface ContactValues {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -33,7 +34,7 @@ interface EventValues {
|
|||||||
*/
|
*/
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [selectedEmail, setSelectedEmail] = useState(null);
|
||||||
if (!router.isReady) {
|
if (!router.isReady) {
|
||||||
return <FullscreenLoader/>;
|
return <FullscreenLoader/>;
|
||||||
}
|
}
|
||||||
@@ -183,7 +184,8 @@ export default function Index() {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Input register={eventRegister("event")} label={"Event"} placeholder={"signup"} error={eventErrors.event} />
|
<Input register={eventRegister("event")} label={"Event"} placeholder={"signup"}
|
||||||
|
error={eventErrors.event}/>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Dashboard>
|
<Dashboard>
|
||||||
<Card
|
<Card
|
||||||
@@ -239,17 +241,21 @@ export default function Index() {
|
|||||||
strokeWidth="1.5"
|
strokeWidth="1.5"
|
||||||
d="M9.75 7.5V6.75C9.75 5.64543 10.6454 4.75 11.75 4.75H12.25C13.3546 4.75 14.25 5.64543 14.25 6.75V7.5"
|
d="M9.75 7.5V6.75C9.75 5.64543 10.6454 4.75 11.75 4.75H12.25C13.3546 4.75 14.25 5.64543 14.25 6.75V7.5"
|
||||||
/>
|
/>
|
||||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M5 7.75H19" />
|
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"
|
||||||
|
strokeWidth="1.5" d="M5 7.75H19"/>
|
||||||
</svg>
|
</svg>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<form onSubmit={handleSubmit(update)} className="space-y-6 sm:grid sm:gap-x-5 sm:space-y-9 sm:grid-cols-2">
|
<form onSubmit={handleSubmit(update)}
|
||||||
|
className="space-y-6 sm:grid sm:gap-x-5 sm:space-y-9 sm:grid-cols-2">
|
||||||
<div className={"col-span-2 flex items-center gap-6"}>
|
<div className={"col-span-2 flex items-center gap-6"}>
|
||||||
<span className="inline-flex h-20 w-20 items-center justify-center rounded-full bg-neutral-100">
|
<span
|
||||||
<span className="text-xl font-semibold leading-none text-neutral-800">{contact.email[0].toUpperCase()}</span>
|
className="inline-flex h-20 w-20 items-center justify-center rounded-full bg-neutral-100">
|
||||||
|
<span
|
||||||
|
className="text-xl font-semibold leading-none text-neutral-800">{contact.email[0].toUpperCase()}</span>
|
||||||
</span>
|
</span>
|
||||||
<h1 className={"text-2xl font-semibold text-neutral-800"}>
|
<h1 className={"text-2xl font-semibold text-neutral-800"}>
|
||||||
{contact.email[0].toUpperCase()}
|
{contact.email[0].toUpperCase()}
|
||||||
@@ -259,7 +265,8 @@ export default function Index() {
|
|||||||
|
|
||||||
<div className={"grid sm:col-span-2"}>
|
<div className={"grid sm:col-span-2"}>
|
||||||
<div className={"grid items-center gap-3 sm:grid-cols-9"}>
|
<div className={"grid items-center gap-3 sm:grid-cols-9"}>
|
||||||
<label htmlFor={"data"} className="block text-sm font-medium text-neutral-700 sm:col-span-8">
|
<label htmlFor={"data"}
|
||||||
|
className="block text-sm font-medium text-neutral-700 sm:col-span-8">
|
||||||
Metadata
|
Metadata
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button
|
||||||
@@ -398,34 +405,30 @@ export default function Index() {
|
|||||||
</Card>
|
</Card>
|
||||||
<Card title={"Journey"}>
|
<Card title={"Journey"}>
|
||||||
{contact.triggers.length > 0 || contact.emails.length > 0 ? (
|
{contact.triggers.length > 0 || contact.emails.length > 0 ? (
|
||||||
<div className="scrollbar-thin scrollbar-thumb-neutral-300 scrollbar-track-neutral-100 scrollbar-thumb-rounded-full scrollbar-track-rounded-full flow-root h-96 max-h-96 overflow-y-auto pr-6">
|
<div
|
||||||
|
className="scrollbar-thin scrollbar-thumb-neutral-300 scrollbar-track-neutral-100 scrollbar-thumb-rounded-full scrollbar-track-rounded-full flow-root h-96 max-h-96 overflow-y-auto pr-6">
|
||||||
<ul className="-mb-8">
|
<ul className="-mb-8">
|
||||||
{[...contact.triggers, ...contact.emails]
|
{[...contact.triggers, ...contact.emails]
|
||||||
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
||||||
.map((t, index) => {
|
.map((t, index) => {
|
||||||
if (t.messageId) {
|
if (t.messageId) {
|
||||||
const email = t as Email;
|
const email = t as Email;
|
||||||
|
const expanded = selectedEmail?.id === email.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li key={email.id} className="mb-8">
|
||||||
<div className="relative pb-8">
|
|
||||||
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
||||||
<span className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200" aria-hidden="true" />
|
<span
|
||||||
|
className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200"
|
||||||
|
aria-hidden="true"/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="relative flex space-x-3">
|
<div className="relative flex space-x-3">
|
||||||
<div>
|
<div>
|
||||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
<span
|
||||||
<svg
|
className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
||||||
className={"h-5 w-5"}
|
<svg className={"h-5 w-5"} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
strokeWidth="1.5" stroke="currentColor" fill="none" strokeLinecap="round"
|
||||||
viewBox="0 0 24 24"
|
strokeLinejoin="round">
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<>
|
<>
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||||
<rect x="3" y="5" width="18" height="14" rx="2"/>
|
<rect x="3" y="5" width="18" height="14" rx="2"/>
|
||||||
@@ -434,31 +437,69 @@ export default function Index() {
|
|||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
<div
|
||||||
|
className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
||||||
|
<div className="relative">
|
||||||
|
<p
|
||||||
|
className="text-sm text-neutral-500 cursor-pointer"
|
||||||
|
onClick={() => setSelectedEmail(expanded ? null : email)}
|
||||||
|
>
|
||||||
|
Transactional email {email.subject} delivered
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="whitespace-nowrap text-right text-sm text-neutral-500">
|
||||||
|
<time
|
||||||
|
dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Expanded panel for all screen sizes */}
|
||||||
|
{expanded && (
|
||||||
|
<div
|
||||||
|
className="mt-4 mb-2 ml-10 rounded border border-neutral-200 bg-neutral-50 p-4 text-sm">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
className="font-semibold text-neutral-700 w-20">Status</span>
|
||||||
|
<Badge type={'info'}><span
|
||||||
|
className={'capitalize'}>{email.status.toLowerCase()}</span></Badge>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
className="font-semibold text-neutral-700 w-20">Sent</span>
|
||||||
|
<span
|
||||||
|
className="text-neutral-800">{dayjs(email.createdAt).format("YYYY-MM-DD HH:mm")}</span>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-neutral-500">Transactional email {email.subject} delivered</p>
|
<span
|
||||||
</div>
|
className="font-semibold text-neutral-700 block mb-1">Body</span>
|
||||||
<div className="whitespace-nowrap text-right text-sm text-neutral-500">
|
<div
|
||||||
<time dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(email.body)}}
|
||||||
</div>
|
className="rounded bg-white p-3 text-neutral-800 whitespace-pre-line max-h-64 overflow-y-auto"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.action) {
|
if (t.action) {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li className="mb-8">
|
||||||
<div className="relative pb-8">
|
<div className="relative pb-8">
|
||||||
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
||||||
<span className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200" aria-hidden="true" />
|
<span
|
||||||
|
className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200"
|
||||||
|
aria-hidden="true"/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="relative flex space-x-3">
|
<div className="relative flex space-x-3">
|
||||||
<div>
|
<div>
|
||||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
<span
|
||||||
|
className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
||||||
<svg
|
<svg
|
||||||
className={"h-5 w-5"}
|
className={"h-5 w-5"}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -469,20 +510,27 @@ export default function Index() {
|
|||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
>
|
>
|
||||||
<path d="M16 21h3c.81 0 1.48 -.67 1.48 -1.48l.02 -.02c0 -.82 -.69 -1.5 -1.5 -1.5h-3v3z" />
|
<path
|
||||||
<path d="M16 15h2.5c.84 -.01 1.5 .66 1.5 1.5s-.66 1.5 -1.5 1.5h-2.5v-3z" />
|
d="M16 21h3c.81 0 1.48 -.67 1.48 -1.48l.02 -.02c0 -.82 -.69 -1.5 -1.5 -1.5h-3v3z"/>
|
||||||
<path d="M4 9v-4c0 -1.036 .895 -2 2 -2s2 .964 2 2v4" />
|
<path
|
||||||
<path d="M2.99 11.98a9 9 0 0 0 9 9m9 -9a9 9 0 0 0 -9 -9" />
|
d="M16 15h2.5c.84 -.01 1.5 .66 1.5 1.5s-.66 1.5 -1.5 1.5h-2.5v-3z"/>
|
||||||
|
<path
|
||||||
|
d="M4 9v-4c0 -1.036 .895 -2 2 -2s2 .964 2 2v4"/>
|
||||||
|
<path
|
||||||
|
d="M2.99 11.98a9 9 0 0 0 9 9m9 -9a9 9 0 0 0 -9 -9"/>
|
||||||
<path d="M8 7h-4"/>
|
<path d="M8 7h-4"/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
<div
|
||||||
|
className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-neutral-500">{t.action.name} triggered</p>
|
<p className="text-sm text-neutral-500">{t.action.name} triggered</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="whitespace-nowrap text-right text-sm text-neutral-500">
|
<div
|
||||||
<time dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
className="whitespace-nowrap text-right text-sm text-neutral-500">
|
||||||
|
<time
|
||||||
|
dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -493,14 +541,17 @@ export default function Index() {
|
|||||||
|
|
||||||
if (t.event) {
|
if (t.event) {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li className="mb-8">
|
||||||
<div className="relative pb-8">
|
<div className="relative pb-8">
|
||||||
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
{contact.triggers.length + contact.emails.length - 1 !== index && (
|
||||||
<span className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200" aria-hidden="true" />
|
<span
|
||||||
|
className="absolute left-4 top-4 -ml-px h-full w-0.5 bg-neutral-200"
|
||||||
|
aria-hidden="true"/>
|
||||||
)}
|
)}
|
||||||
<div className="relative flex space-x-3">
|
<div className="relative flex space-x-3">
|
||||||
<div>
|
<div>
|
||||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
<span
|
||||||
|
className="flex h-8 w-8 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 ring-8 ring-white">
|
||||||
{t.event.templateId ? (
|
{t.event.templateId ? (
|
||||||
<svg
|
<svg
|
||||||
className={"h-5 w-5"}
|
className={"h-5 w-5"}
|
||||||
@@ -514,17 +565,26 @@ export default function Index() {
|
|||||||
>
|
>
|
||||||
{t.event.name.includes("delivered") ? (
|
{t.event.name.includes("delivered") ? (
|
||||||
<>
|
<>
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none"
|
||||||
<rect x="3" y="5" width="18" height="14" rx="2" />
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
<rect x="3" y="5" width="18"
|
||||||
|
height="14" rx="2"/>
|
||||||
<polyline points="3 7 12 13 21 7"/>
|
<polyline points="3 7 12 13 21 7"/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none"
|
||||||
<polyline points="3 9 12 15 21 9 12 3 3 9" />
|
d="M0 0h24v24H0z"
|
||||||
<path d="M21 9v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10" />
|
fill="none"/>
|
||||||
<line x1="3" y1="19" x2="9" y2="13" />
|
<polyline
|
||||||
<line x1="15" y1="13" x2="21" y2="19" />
|
points="3 9 12 15 21 9 12 3 3 9"/>
|
||||||
|
<path
|
||||||
|
d="M21 9v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10"/>
|
||||||
|
<line x1="3" y1="19" x2="9"
|
||||||
|
y2="13"/>
|
||||||
|
<line x1="15" y1="13" x2="21"
|
||||||
|
y2="19"/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</svg>
|
</svg>
|
||||||
@@ -543,8 +603,10 @@ export default function Index() {
|
|||||||
<path d="M13 9h5"/>
|
<path d="M13 9h5"/>
|
||||||
<path d="M13 15h8"/>
|
<path d="M13 15h8"/>
|
||||||
<path d="M13 19h5"/>
|
<path d="M13 19h5"/>
|
||||||
<rect x="3" y="4" width="6" height="6" rx="1" />
|
<rect x="3" y="4" width="6" height="6"
|
||||||
<rect x="3" y="14" width="6" height="6" rx="1" />
|
rx="1"/>
|
||||||
|
<rect x="3" y="14" width="6" height="6"
|
||||||
|
rx="1"/>
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
<svg
|
<svg
|
||||||
@@ -559,12 +621,14 @@ export default function Index() {
|
|||||||
>
|
>
|
||||||
<path d="M8 9l3 3l-3 3"/>
|
<path d="M8 9l3 3l-3 3"/>
|
||||||
<line x1="13" y1="15" x2="16" y2="15"/>
|
<line x1="13" y1="15" x2="16" y2="15"/>
|
||||||
<rect x="3" y="4" width="18" height="16" rx="2" />
|
<rect x="3" y="4" width="18" height="16"
|
||||||
|
rx="2"/>
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
<div
|
||||||
|
className="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-neutral-500">
|
<p className="text-sm text-neutral-500">
|
||||||
{t.event.templateId || t.event.campaignId
|
{t.event.templateId || t.event.campaignId
|
||||||
@@ -584,8 +648,10 @@ export default function Index() {
|
|||||||
: "triggered"}
|
: "triggered"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="whitespace-nowrap text-right text-sm text-neutral-500">
|
<div
|
||||||
<time dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
className="whitespace-nowrap text-right text-sm text-neutral-500">
|
||||||
|
<time
|
||||||
|
dateTime={dayjs(t.createdAt).format("YYYY-MM-DD")}>{dayjs().to(t.createdAt)}</time>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -597,7 +663,8 @@ export default function Index() {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Empty title={"No triggers"} description={"This contact has not yet triggered any events or actions"} />
|
<Empty title={"No triggers"}
|
||||||
|
description={"This contact has not yet triggered any events or actions"}/>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</Dashboard>
|
</Dashboard>
|
||||||
|
|||||||
@@ -3041,6 +3041,7 @@ __metadata:
|
|||||||
autoprefixer: "npm:^10.4.19"
|
autoprefixer: "npm:^10.4.19"
|
||||||
classnames: "npm:^2.5.1"
|
classnames: "npm:^2.5.1"
|
||||||
dayjs: "npm:^1.11.12"
|
dayjs: "npm:^1.11.12"
|
||||||
|
dompurify: "npm:^3.2.6"
|
||||||
framer-motion: "npm:^11.3.7"
|
framer-motion: "npm:^11.3.7"
|
||||||
jotai: "npm:2.9.0"
|
jotai: "npm:2.9.0"
|
||||||
lucide-react: "npm:^0.408.0"
|
lucide-react: "npm:^0.408.0"
|
||||||
@@ -4777,6 +4778,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/trusted-types@npm:^2.0.7":
|
||||||
|
version: 2.0.7
|
||||||
|
resolution: "@types/trusted-types@npm:2.0.7"
|
||||||
|
checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/unist@npm:^2":
|
"@types/unist@npm:^2":
|
||||||
version: 2.0.11
|
version: 2.0.11
|
||||||
resolution: "@types/unist@npm:2.0.11"
|
resolution: "@types/unist@npm:2.0.11"
|
||||||
@@ -6565,6 +6573,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"dompurify@npm:^3.2.6":
|
||||||
|
version: 3.2.6
|
||||||
|
resolution: "dompurify@npm:3.2.6"
|
||||||
|
dependencies:
|
||||||
|
"@types/trusted-types": "npm:^2.0.7"
|
||||||
|
dependenciesMeta:
|
||||||
|
"@types/trusted-types":
|
||||||
|
optional: true
|
||||||
|
checksum: 10c0/c8f8e5b0879a0d93c84a2e5e78649a47d0c057ed0f7850ca3d573d2cca64b84fb1ff85bd4b20980ade69c4e5b80ae73011340f1c2ff375c7ef98bb8268e1d13a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"domutils@npm:^2.4.2":
|
"domutils@npm:^2.4.2":
|
||||||
version: 2.8.0
|
version: 2.8.0
|
||||||
resolution: "domutils@npm:2.8.0"
|
resolution: "domutils@npm:2.8.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user