Update domain page UI
This commit is contained in:
@@ -290,8 +290,7 @@ const DomainSettings: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
<p className="font-semibold text-xl mt-2 text-destructive">Danger</p>
|
||||
|
||||
<p className="text-destructive text-sm font-semibold">
|
||||
Deleting a domain will remove all of its DNS records and stop sending
|
||||
emails.
|
||||
Deleting a domain will stop sending emails with this domain.
|
||||
</p>
|
||||
<DeleteDomain domain={domain} />
|
||||
</div>
|
||||
|
@@ -1,8 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@unsend/ui/src/button";
|
||||
import { Input } from "@unsend/ui/src/input";
|
||||
import { Label } from "@unsend/ui/src/label";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -18,27 +16,120 @@ import { Domain } from "@prisma/client";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "@unsend/ui/src/toaster";
|
||||
import { Send, SendHorizonal } from "lucide-react";
|
||||
import { Code } from "@unsend/ui/src/code";
|
||||
|
||||
const jsCode = `const requestOptions = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer us_ad9a79256e366399c747cbf0b38eca3c472e8a2e"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"to": "koushikmohan1996@gmail.com",
|
||||
"from": "hello@test.splitpro.app",
|
||||
"subject": "Test mail",
|
||||
"html": "<p>Hello this is a test mail</p>"
|
||||
}),
|
||||
redirect: "follow"
|
||||
};
|
||||
|
||||
fetch("http://localhost:3000/api/v1/emails", requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => console.log(result))
|
||||
.catch(error => console.error(error));
|
||||
`;
|
||||
|
||||
const pythonCode = `import requests
|
||||
import json
|
||||
|
||||
url = "http://localhost:3000/api/v1/emails"
|
||||
|
||||
payload = json.dumps({
|
||||
"to": "koushikmohan1996@gmail.com",
|
||||
"from": "hello@test.splitpro.app",
|
||||
"subject": "Test mail",
|
||||
"html": "<p>Hello this is a test mail</p>"
|
||||
})
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer us_ad9a79256e366399c747cbf0b38eca3c472e8a2e'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)`;
|
||||
|
||||
const rubyCode = `require 'uri'
|
||||
require 'net/http'
|
||||
require 'json'
|
||||
|
||||
url = URI("http://localhost:3000/api/v1/emails")
|
||||
|
||||
http = Net::HTTP.new(url.host, url.port)
|
||||
request = Net::HTTP::Post.new(url)
|
||||
request["Accept"] = 'application/json'
|
||||
request["Content-Type"] = 'application/json'
|
||||
request["Authorization"] = 'Bearer us_ad9a79256e366399c747cbf0b38eca3c472e8a2e'
|
||||
request.body = JSON.dump({
|
||||
"to" => "koushikmohan1996@gmail.com",
|
||||
"from" => "hello@test.splitpro.app",
|
||||
"subject" => "Test mail",
|
||||
"html" => "<p>Hello this is a test mail</p>"
|
||||
})
|
||||
|
||||
response = http.request(request)
|
||||
puts response.read_body`;
|
||||
|
||||
const phpCode = `$url = "http://localhost:3000/api/v1/emails";
|
||||
|
||||
$payload = json_encode(array(
|
||||
"to" => "koushikmohan1996@gmail.com",
|
||||
"from" => "hello@test.splitpro.app",
|
||||
"subject" => "Test mail",
|
||||
"html" => "<p>Hello this is a test mail</p>"
|
||||
));
|
||||
|
||||
$headers = array(
|
||||
"Accept: application/json",
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer us_ad9a79256e366399c747cbf0b38eca3c472e8a2e"
|
||||
);
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
echo 'Error:' . curl_error($ch);
|
||||
} else {
|
||||
echo $response;
|
||||
}`;
|
||||
|
||||
export const SendTestMail: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [domainName, setDomainName] = useState("");
|
||||
const deleteDomainMutation = api.domain.deleteDomain.useMutation();
|
||||
const sendTestEmailFromDomainMutation =
|
||||
api.domain.sendTestEmailFromDomain.useMutation();
|
||||
|
||||
const utils = api.useUtils();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
function handleSave() {
|
||||
deleteDomainMutation.mutate(
|
||||
function handleSendTestEmail() {
|
||||
sendTestEmailFromDomainMutation.mutate(
|
||||
{
|
||||
id: domain.id,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
utils.domain.domains.invalidate();
|
||||
toast.success(`Test email sent`);
|
||||
setOpen(false);
|
||||
toast.success(`Domain ${domain.name} deleted`);
|
||||
router.replace("/domains");
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -55,10 +146,28 @@ export const SendTestMail: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
Send test email
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogContent className=" max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Send test email</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Code
|
||||
codeBlocks={[
|
||||
{ language: "js", code: jsCode },
|
||||
{ language: "ruby", code: rubyCode },
|
||||
{ language: "php", code: phpCode },
|
||||
{ language: "python", code: pythonCode },
|
||||
]}
|
||||
/>
|
||||
<div className="flex justify-end w-full">
|
||||
<Button
|
||||
onClick={handleSendTestEmail}
|
||||
disabled={sendTestEmailFromDomainMutation.isPending}
|
||||
>
|
||||
{sendTestEmailFromDomainMutation.isPending
|
||||
? "Sending email..."
|
||||
: "Send test email"}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
getDomain,
|
||||
updateDomain,
|
||||
} from "~/server/service/domain-service";
|
||||
import { sendEmail } from "~/server/service/email-service";
|
||||
|
||||
export const domainRouter = createTRPCRouter({
|
||||
createDomain: teamProcedure
|
||||
@@ -61,4 +62,37 @@ export const domainRouter = createTRPCRouter({
|
||||
await deleteDomain(input.id);
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
sendTestEmailFromDomain: teamProcedure
|
||||
.input(z.object({ id: z.number() }))
|
||||
.mutation(
|
||||
async ({
|
||||
ctx: {
|
||||
session: { user },
|
||||
team,
|
||||
},
|
||||
input,
|
||||
}) => {
|
||||
const domain = await db.domain.findFirst({
|
||||
where: { id: input.id, teamId: team.id },
|
||||
});
|
||||
|
||||
if (!domain) {
|
||||
throw new Error("Domain not found");
|
||||
}
|
||||
|
||||
if (!user.email) {
|
||||
throw new Error("User email not found");
|
||||
}
|
||||
|
||||
return sendEmail({
|
||||
teamId: team.id,
|
||||
to: user.email,
|
||||
from: `hello@${domain.name}`,
|
||||
subject: "Test mail",
|
||||
text: "Hello this is a test mail",
|
||||
html: "<p>Hello this is a test mail</p>",
|
||||
});
|
||||
}
|
||||
),
|
||||
});
|
||||
|
@@ -8,16 +8,16 @@ export async function sendEmail(
|
||||
) {
|
||||
const { to, from, subject, text, html, teamId } = emailContent;
|
||||
|
||||
const domains = await db.domain.findMany({ where: { teamId } });
|
||||
|
||||
const fromDomain = from.split("@")[1];
|
||||
if (!fromDomain) {
|
||||
throw new Error("From email is not valid");
|
||||
}
|
||||
|
||||
const domain = domains.find((domain) => domain.name === fromDomain);
|
||||
const domain = await db.domain.findFirst({
|
||||
where: { teamId, name: fromDomain },
|
||||
});
|
||||
|
||||
if (!domain) {
|
||||
throw new Error("Domain not found. Add domain to unsend first");
|
||||
throw new Error(
|
||||
"Domain of from email is wrong. Use the email verified by unsend"
|
||||
);
|
||||
}
|
||||
|
||||
if (domain.status !== "SUCCESS") {
|
||||
|
148
packages/ui/code-theme.ts
Normal file
148
packages/ui/code-theme.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
const codeTheme: {
|
||||
[key: string]: React.CSSProperties;
|
||||
} = {
|
||||
hljs: {
|
||||
display: "block",
|
||||
overflowX: "auto",
|
||||
padding: "0.5em",
|
||||
background: "#070808",
|
||||
color: "#d6deeb",
|
||||
},
|
||||
"hljs-keyword": {
|
||||
color: "#c792ea",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-built_in": {
|
||||
color: "#addb67",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-type": {
|
||||
color: "#82aaff",
|
||||
},
|
||||
"hljs-literal": {
|
||||
color: "#ff5874",
|
||||
},
|
||||
"hljs-number": {
|
||||
color: "#F78C6C",
|
||||
},
|
||||
"hljs-regexp": {
|
||||
color: "#5ca7e4",
|
||||
},
|
||||
"hljs-string": {
|
||||
color: "#ecc48d",
|
||||
},
|
||||
"hljs-subst": {
|
||||
color: "#d3423e",
|
||||
},
|
||||
"hljs-symbol": {
|
||||
color: "#82aaff",
|
||||
},
|
||||
"hljs-class": {
|
||||
color: "#ffcb8b",
|
||||
},
|
||||
"hljs-function": {
|
||||
color: "#82AAFF",
|
||||
},
|
||||
"hljs-title": {
|
||||
color: "#DCDCAA",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-params": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-comment": {
|
||||
color: "#637777",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-doctag": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-meta": {
|
||||
color: "#82aaff",
|
||||
},
|
||||
"hljs-meta-keyword": {
|
||||
color: "#82aaff",
|
||||
},
|
||||
"hljs-meta-string": {
|
||||
color: "#ecc48d",
|
||||
},
|
||||
"hljs-section": {
|
||||
color: "#82b1ff",
|
||||
},
|
||||
"hljs-tag": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-name": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-builtin-name": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-attr": {
|
||||
color: "#7fdbca",
|
||||
},
|
||||
"hljs-attribute": {
|
||||
color: "#80cbc4",
|
||||
},
|
||||
"hljs-variable": {
|
||||
color: "#addb67",
|
||||
},
|
||||
"hljs-bullet": {
|
||||
color: "#d9f5dd",
|
||||
},
|
||||
"hljs-code": {
|
||||
color: "#80CBC4",
|
||||
},
|
||||
"hljs-emphasis": {
|
||||
color: "#c792ea",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-strong": {
|
||||
color: "#addb67",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
"hljs-formula": {
|
||||
color: "#c792ea",
|
||||
},
|
||||
"hljs-link": {
|
||||
color: "#ff869a",
|
||||
},
|
||||
"hljs-quote": {
|
||||
color: "#697098",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-selector-tag": {
|
||||
color: "#ff6363",
|
||||
},
|
||||
"hljs-selector-id": {
|
||||
color: "#fad430",
|
||||
},
|
||||
"hljs-selector-class": {
|
||||
color: "#addb67",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-selector-attr": {
|
||||
color: "#c792ea",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-selector-pseudo": {
|
||||
color: "#c792ea",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-template-tag": {
|
||||
color: "#c792ea",
|
||||
},
|
||||
"hljs-template-variable": {
|
||||
color: "#addb67",
|
||||
},
|
||||
"hljs-addition": {
|
||||
color: "#addb67ff",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"hljs-deletion": {
|
||||
color: "#EF535090",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
};
|
||||
|
||||
export default codeTheme;
|
@@ -15,6 +15,7 @@
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/react": "^18.2.61",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@types/react-syntax-highlighter": "^15.5.11",
|
||||
"@unsend/eslint-config": "workspace:*",
|
||||
"@unsend/tailwind-config": "workspace:*",
|
||||
"@unsend/typescript-config": "workspace:*",
|
||||
@@ -32,12 +33,14 @@
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"add": "^2.0.6",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"lucide-react": "^0.359.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"pnpm": "^8.15.5",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"sonner": "^1.4.41",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
|
97
packages/ui/src/code.tsx
Normal file
97
packages/ui/src/code.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import js from "react-syntax-highlighter/dist/esm/languages/hljs/javascript";
|
||||
import ruby from "react-syntax-highlighter/dist/esm/languages/hljs/ruby";
|
||||
import php from "react-syntax-highlighter/dist/esm/languages/hljs/php";
|
||||
import python from "react-syntax-highlighter/dist/esm/languages/hljs/python";
|
||||
// import { nightOwl } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
||||
import codeTheme from "../code-theme";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs";
|
||||
import { Button } from "./button";
|
||||
import { ClipboardCopy, Check } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
type Language = "js" | "ruby" | "php" | "python";
|
||||
|
||||
type CodeProps = {
|
||||
codeBlocks: {
|
||||
language: Language;
|
||||
code: string;
|
||||
display?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
SyntaxHighlighter.registerLanguage("js", js);
|
||||
SyntaxHighlighter.registerLanguage("ruby", ruby);
|
||||
SyntaxHighlighter.registerLanguage("php", php);
|
||||
SyntaxHighlighter.registerLanguage("python", python);
|
||||
|
||||
export const Code: React.FC<CodeProps> = ({ codeBlocks }) => {
|
||||
const [selectedTab, setSelectedTab] = useState(
|
||||
codeBlocks[0]?.language ?? "js"
|
||||
);
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const copyToClipboard = async (code: string) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(code);
|
||||
setIsCopied(true);
|
||||
setTimeout(() => setIsCopied(false), 2000); // Reset the icon back to clipboard after 2 seconds
|
||||
} catch (err) {
|
||||
alert("Failed to copy code");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-md bg-background border">
|
||||
<Tabs
|
||||
defaultValue={codeBlocks[0]?.language}
|
||||
onValueChange={(val) => setSelectedTab(val as Language)}
|
||||
>
|
||||
<div className="flex justify-between items-center border-b py-1 px-2">
|
||||
<TabsList className="w-full rounded-none justify-start bg-transparent h-12">
|
||||
<div className="">
|
||||
{codeBlocks.map((block) => (
|
||||
<TabsTrigger
|
||||
key={block.language}
|
||||
value={block.language}
|
||||
className="data-[state=active]:bg-accent py-0.5 px-4"
|
||||
>
|
||||
{block.language}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</div>
|
||||
</TabsList>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="icon"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
codeBlocks.find((block) => block.language === selectedTab)
|
||||
?.code || ""
|
||||
)
|
||||
}
|
||||
>
|
||||
{isCopied ? (
|
||||
<Check className="h-4 w-4" />
|
||||
) : (
|
||||
<ClipboardCopy className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
{codeBlocks.map((block) => (
|
||||
<TabsContent
|
||||
key={block.language}
|
||||
value={block.language}
|
||||
className="py-2"
|
||||
>
|
||||
<div className="overflow-auto max-w-[38rem] h-[20rem]">
|
||||
<SyntaxHighlighter language={block.language} style={codeTheme}>
|
||||
{block.code}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
55
packages/ui/src/tabs.tsx
Normal file
55
packages/ui/src/tabs.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||
|
||||
import { cn } from "../lib/utils";
|
||||
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
181
pnpm-lock.yaml
generated
181
pnpm-lock.yaml
generated
@@ -278,6 +278,9 @@ importers:
|
||||
'@radix-ui/react-switch':
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-tabs':
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
|
||||
add:
|
||||
specifier: ^2.0.6
|
||||
version: 2.0.6
|
||||
@@ -296,6 +299,9 @@ importers:
|
||||
pnpm:
|
||||
specifier: ^8.15.5
|
||||
version: 8.15.5
|
||||
react-syntax-highlighter:
|
||||
specifier: ^15.5.0
|
||||
version: 15.5.0(react@18.2.0)
|
||||
sonner:
|
||||
specifier: ^1.4.41
|
||||
version: 1.4.41(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -318,6 +324,9 @@ importers:
|
||||
'@types/react-dom':
|
||||
specifier: ^18.2.19
|
||||
version: 18.2.22
|
||||
'@types/react-syntax-highlighter':
|
||||
specifier: ^15.5.11
|
||||
version: 15.5.11
|
||||
'@unsend/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:../eslint-config
|
||||
@@ -2297,6 +2306,34 @@ packages:
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.66)(react@18.2.0)
|
||||
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.66)(react@18.2.0)
|
||||
'@radix-ui/react-id': 1.0.1(@types/react@18.2.66)(react@18.2.0)
|
||||
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.66)(react@18.2.0)
|
||||
'@types/react': 18.2.66
|
||||
'@types/react-dom': 18.2.22
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.66)(react@18.2.0):
|
||||
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
||||
peerDependencies:
|
||||
@@ -2896,6 +2933,12 @@ packages:
|
||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||
dev: true
|
||||
|
||||
/@types/hast@2.3.10:
|
||||
resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
|
||||
dependencies:
|
||||
'@types/unist': 2.0.10
|
||||
dev: false
|
||||
|
||||
/@types/json-schema@7.0.15:
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
dev: true
|
||||
@@ -2922,6 +2965,12 @@ packages:
|
||||
dependencies:
|
||||
'@types/react': 18.2.66
|
||||
|
||||
/@types/react-syntax-highlighter@15.5.11:
|
||||
resolution: {integrity: sha512-ZqIJl+Pg8kD+47kxUjvrlElrraSUrYa4h0dauY/U/FTUuprSCqvUj+9PNQNQzVc6AJgIWUUxn87/gqsMHNbRjw==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.66
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.66:
|
||||
resolution: {integrity: sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==}
|
||||
dependencies:
|
||||
@@ -2936,6 +2985,10 @@ packages:
|
||||
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
|
||||
dev: true
|
||||
|
||||
/@types/unist@2.0.10:
|
||||
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2):
|
||||
resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
@@ -3657,6 +3710,18 @@ packages:
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
|
||||
/character-entities-legacy@1.1.4:
|
||||
resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==}
|
||||
dev: false
|
||||
|
||||
/character-entities@1.2.4:
|
||||
resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==}
|
||||
dev: false
|
||||
|
||||
/character-reference-invalid@1.1.4:
|
||||
resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
|
||||
dev: false
|
||||
|
||||
/chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
@@ -3722,6 +3787,10 @@ packages:
|
||||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
/comma-separated-tokens@1.0.8:
|
||||
resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
|
||||
dev: false
|
||||
|
||||
/commander@4.1.1:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -4668,6 +4737,12 @@ packages:
|
||||
dependencies:
|
||||
reusify: 1.0.4
|
||||
|
||||
/fault@1.0.4:
|
||||
resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==}
|
||||
dependencies:
|
||||
format: 0.2.2
|
||||
dev: false
|
||||
|
||||
/file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@@ -4723,6 +4798,11 @@ packages:
|
||||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
|
||||
/format@0.2.2:
|
||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
dev: false
|
||||
|
||||
/fraction.js@4.3.7:
|
||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||
dev: true
|
||||
@@ -4951,6 +5031,24 @@ packages:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
/hast-util-parse-selector@2.2.5:
|
||||
resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
|
||||
dev: false
|
||||
|
||||
/hastscript@6.0.0:
|
||||
resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
|
||||
dependencies:
|
||||
'@types/hast': 2.3.10
|
||||
comma-separated-tokens: 1.0.8
|
||||
hast-util-parse-selector: 2.2.5
|
||||
property-information: 5.6.0
|
||||
space-separated-tokens: 1.1.5
|
||||
dev: false
|
||||
|
||||
/highlight.js@10.7.3:
|
||||
resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
|
||||
dev: false
|
||||
|
||||
/hono@4.2.2:
|
||||
resolution: {integrity: sha512-mDmjBHF6uBNN3TASdAbDCFsN9FLbrlgXyFZkhLEkU7hUgk0+T9hcsUrL/nho4qV+Xk0RDHx7gop4Q1gelZZVRw==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
@@ -5014,6 +5112,17 @@ packages:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/is-alphabetical@1.0.4:
|
||||
resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==}
|
||||
dev: false
|
||||
|
||||
/is-alphanumerical@1.0.4:
|
||||
resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==}
|
||||
dependencies:
|
||||
is-alphabetical: 1.0.4
|
||||
is-decimal: 1.0.4
|
||||
dev: false
|
||||
|
||||
/is-array-buffer@3.0.4:
|
||||
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5077,6 +5186,10 @@ packages:
|
||||
has-tostringtag: 1.0.2
|
||||
dev: true
|
||||
|
||||
/is-decimal@1.0.4:
|
||||
resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
|
||||
dev: false
|
||||
|
||||
/is-extglob@2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -5104,6 +5217,10 @@ packages:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
/is-hexadecimal@1.0.4:
|
||||
resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
|
||||
dev: false
|
||||
|
||||
/is-map@2.0.3:
|
||||
resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5371,6 +5488,13 @@ packages:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
|
||||
/lowlight@1.20.0:
|
||||
resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==}
|
||||
dependencies:
|
||||
fault: 1.0.4
|
||||
highlight.js: 10.7.3
|
||||
dev: false
|
||||
|
||||
/lru-cache@10.2.0:
|
||||
resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
|
||||
engines: {node: 14 || >=16.14}
|
||||
@@ -5752,6 +5876,17 @@ packages:
|
||||
callsites: 3.1.0
|
||||
dev: true
|
||||
|
||||
/parse-entities@2.0.0:
|
||||
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
|
||||
dependencies:
|
||||
character-entities: 1.2.4
|
||||
character-entities-legacy: 1.1.4
|
||||
character-reference-invalid: 1.1.4
|
||||
is-alphanumerical: 1.0.4
|
||||
is-decimal: 1.0.4
|
||||
is-hexadecimal: 1.0.4
|
||||
dev: false
|
||||
|
||||
/parse-json@5.2.0:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -6021,6 +6156,16 @@ packages:
|
||||
'@prisma/engines': 5.11.0
|
||||
dev: false
|
||||
|
||||
/prismjs@1.27.0:
|
||||
resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/prismjs@1.29.0:
|
||||
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
dependencies:
|
||||
@@ -6029,6 +6174,12 @@ packages:
|
||||
react-is: 16.13.1
|
||||
dev: true
|
||||
|
||||
/property-information@5.6.0:
|
||||
resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==}
|
||||
dependencies:
|
||||
xtend: 4.0.2
|
||||
dev: false
|
||||
|
||||
/punycode@2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -6103,6 +6254,19 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/react-syntax-highlighter@15.5.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==}
|
||||
peerDependencies:
|
||||
react: '>= 0.14.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.0
|
||||
highlight.js: 10.7.3
|
||||
lowlight: 1.20.0
|
||||
prismjs: 1.29.0
|
||||
react: 18.2.0
|
||||
refractor: 3.6.0
|
||||
dev: false
|
||||
|
||||
/react@18.2.0:
|
||||
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -6152,6 +6316,14 @@ packages:
|
||||
which-builtin-type: 1.1.3
|
||||
dev: true
|
||||
|
||||
/refractor@3.6.0:
|
||||
resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==}
|
||||
dependencies:
|
||||
hastscript: 6.0.0
|
||||
parse-entities: 2.0.0
|
||||
prismjs: 1.27.0
|
||||
dev: false
|
||||
|
||||
/regenerator-runtime@0.14.1:
|
||||
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||
|
||||
@@ -6365,6 +6537,10 @@ packages:
|
||||
resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/space-separated-tokens@1.1.5:
|
||||
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
|
||||
dev: false
|
||||
|
||||
/spdx-correct@3.2.0:
|
||||
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
|
||||
dependencies:
|
||||
@@ -6949,6 +7125,11 @@ packages:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
dev: true
|
||||
|
||||
/xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
dev: false
|
||||
|
||||
/yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
dev: true
|
||||
|
Reference in New Issue
Block a user