diff --git a/.github/workflows/code-check.yml b/.github/workflows/code-check.yml index 5024553399..d40e83057b 100644 --- a/.github/workflows/code-check.yml +++ b/.github/workflows/code-check.yml @@ -16,7 +16,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - uses: pnpm/action-setup@v2.2.4 name: Install pnpm @@ -52,7 +52,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - uses: pnpm/action-setup@v2.2.4 name: Install pnpm @@ -90,7 +90,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - uses: pnpm/action-setup@v2.2.4 name: Install pnpm diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0534967748..c350ce1b04 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - uses: pnpm/action-setup@v2.2.4 name: Install pnpm diff --git a/.nvmrc b/.nvmrc index 50e4b92aeb..7950a44576 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.18.0 +v18.17.0 diff --git a/apps/www/.prettierignore b/apps/www/.prettierignore index ccf2b0bb07..fb41136e08 100644 --- a/apps/www/.prettierignore +++ b/apps/www/.prettierignore @@ -3,4 +3,5 @@ node_modules .next build .contentlayer -__registry__/index.tsx \ No newline at end of file +__registry__/index.tsx +app/examples/mail/components/mail.tsx diff --git a/apps/www/__registry__/index.tsx b/apps/www/__registry__/index.tsx index af4376f853..810df6ae10 100644 --- a/apps/www/__registry__/index.tsx +++ b/apps/www/__registry__/index.tsx @@ -68,6 +68,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/ui/card")), files: ["registry/default/ui/card.tsx"], }, + "carousel": { + name: "carousel", + type: "components:ui", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/ui/carousel")), + files: ["registry/default/ui/carousel.tsx"], + }, "checkbox": { name: "checkbox", type: "components:ui", @@ -103,6 +110,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/ui/dialog")), files: ["registry/default/ui/dialog.tsx"], }, + "drawer": { + name: "drawer", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/drawer")), + files: ["registry/default/ui/drawer.tsx"], + }, "dropdown-menu": { name: "dropdown-menu", type: "components:ui", @@ -152,6 +166,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/ui/navigation-menu")), files: ["registry/default/ui/navigation-menu.tsx"], }, + "pagination": { + name: "pagination", + type: "components:ui", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/ui/pagination")), + files: ["registry/default/ui/pagination.tsx"], + }, "popover": { name: "popover", type: "components:ui", @@ -173,6 +194,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/ui/radio-group")), files: ["registry/default/ui/radio-group.tsx"], }, + "resizable": { + name: "resizable", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/resizable")), + files: ["registry/default/ui/resizable.tsx"], + }, "scroll-area": { name: "scroll-area", type: "components:ui", @@ -215,6 +243,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/ui/slider")), files: ["registry/default/ui/slider.tsx"], }, + "sonner": { + name: "sonner", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/sonner")), + files: ["registry/default/ui/sonner.tsx"], + }, "switch": { name: "switch", type: "components:ui", @@ -439,6 +474,48 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/card-with-form")), files: ["registry/default/example/card-with-form.tsx"], }, + "carousel-demo": { + name: "carousel-demo", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-demo")), + files: ["registry/default/example/carousel-demo.tsx"], + }, + "carousel-size": { + name: "carousel-size", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-size")), + files: ["registry/default/example/carousel-size.tsx"], + }, + "carousel-spacing": { + name: "carousel-spacing", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-spacing")), + files: ["registry/default/example/carousel-spacing.tsx"], + }, + "carousel-orientation": { + name: "carousel-orientation", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-orientation")), + files: ["registry/default/example/carousel-orientation.tsx"], + }, + "carousel-api": { + name: "carousel-api", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-api")), + files: ["registry/default/example/carousel-api.tsx"], + }, + "carousel-plugin": { + name: "carousel-plugin", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/default/example/carousel-plugin")), + files: ["registry/default/example/carousel-plugin.tsx"], + }, "checkbox-demo": { name: "checkbox-demo", type: "components:example", @@ -509,6 +586,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/combobox-popover")), files: ["registry/default/example/combobox-popover.tsx"], }, + "combobox-responsive": { + name: "combobox-responsive", + type: "components:example", + registryDependencies: ["combobox","popover","drawer"], + component: React.lazy(() => import("@/registry/default/example/combobox-responsive")), + files: ["registry/default/example/combobox-responsive.tsx"], + }, "command-demo": { name: "command-demo", type: "components:example", @@ -579,6 +663,20 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/dialog-close-button")), files: ["registry/default/example/dialog-close-button.tsx"], }, + "drawer-demo": { + name: "drawer-demo", + type: "components:example", + registryDependencies: ["drawer"], + component: React.lazy(() => import("@/registry/default/example/drawer-demo")), + files: ["registry/default/example/drawer-demo.tsx"], + }, + "drawer-dialog": { + name: "drawer-dialog", + type: "components:example", + registryDependencies: ["drawer","dialog"], + component: React.lazy(() => import("@/registry/default/example/drawer-dialog")), + files: ["registry/default/example/drawer-dialog.tsx"], + }, "dropdown-menu-demo": { name: "dropdown-menu-demo", type: "components:example", @@ -677,6 +775,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/navigation-menu-demo")), files: ["registry/default/example/navigation-menu-demo.tsx"], }, + "pagination-demo": { + name: "pagination-demo", + type: "components:example", + registryDependencies: ["pagination"], + component: React.lazy(() => import("@/registry/default/example/pagination-demo")), + files: ["registry/default/example/pagination-demo.tsx"], + }, "popover-demo": { name: "popover-demo", type: "components:example", @@ -705,6 +810,34 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/radio-group-form")), files: ["registry/default/example/radio-group-form.tsx"], }, + "resizable-demo": { + name: "resizable-demo", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-demo")), + files: ["registry/default/example/resizable-demo.tsx"], + }, + "resizable-demo-with-handle": { + name: "resizable-demo-with-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-demo-with-handle")), + files: ["registry/default/example/resizable-demo-with-handle.tsx"], + }, + "resizable-vertical": { + name: "resizable-vertical", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-vertical")), + files: ["registry/default/example/resizable-vertical.tsx"], + }, + "resizable-handle": { + name: "resizable-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-handle")), + files: ["registry/default/example/resizable-handle.tsx"], + }, "scroll-area-demo": { name: "scroll-area-demo", type: "components:example", @@ -775,6 +908,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/default/example/slider-demo")), files: ["registry/default/example/slider-demo.tsx"], }, + "sonner-demo": { + name: "sonner-demo", + type: "components:example", + registryDependencies: ["sonner"], + component: React.lazy(() => import("@/registry/default/example/sonner-demo")), + files: ["registry/default/example/sonner-demo.tsx"], + }, "switch-demo": { name: "switch-demo", type: "components:example", @@ -1147,6 +1287,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/ui/card")), files: ["registry/new-york/ui/card.tsx"], }, + "carousel": { + name: "carousel", + type: "components:ui", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/new-york/ui/carousel")), + files: ["registry/new-york/ui/carousel.tsx"], + }, "checkbox": { name: "checkbox", type: "components:ui", @@ -1182,6 +1329,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/ui/dialog")), files: ["registry/new-york/ui/dialog.tsx"], }, + "drawer": { + name: "drawer", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/new-york/ui/drawer")), + files: ["registry/new-york/ui/drawer.tsx"], + }, "dropdown-menu": { name: "dropdown-menu", type: "components:ui", @@ -1231,6 +1385,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/ui/navigation-menu")), files: ["registry/new-york/ui/navigation-menu.tsx"], }, + "pagination": { + name: "pagination", + type: "components:ui", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/new-york/ui/pagination")), + files: ["registry/new-york/ui/pagination.tsx"], + }, "popover": { name: "popover", type: "components:ui", @@ -1252,6 +1413,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/ui/radio-group")), files: ["registry/new-york/ui/radio-group.tsx"], }, + "resizable": { + name: "resizable", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/new-york/ui/resizable")), + files: ["registry/new-york/ui/resizable.tsx"], + }, "scroll-area": { name: "scroll-area", type: "components:ui", @@ -1294,6 +1462,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/ui/slider")), files: ["registry/new-york/ui/slider.tsx"], }, + "sonner": { + name: "sonner", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/new-york/ui/sonner")), + files: ["registry/new-york/ui/sonner.tsx"], + }, "switch": { name: "switch", type: "components:ui", @@ -1518,6 +1693,48 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/card-with-form")), files: ["registry/new-york/example/card-with-form.tsx"], }, + "carousel-demo": { + name: "carousel-demo", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-demo")), + files: ["registry/new-york/example/carousel-demo.tsx"], + }, + "carousel-size": { + name: "carousel-size", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-size")), + files: ["registry/new-york/example/carousel-size.tsx"], + }, + "carousel-spacing": { + name: "carousel-spacing", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-spacing")), + files: ["registry/new-york/example/carousel-spacing.tsx"], + }, + "carousel-orientation": { + name: "carousel-orientation", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-orientation")), + files: ["registry/new-york/example/carousel-orientation.tsx"], + }, + "carousel-api": { + name: "carousel-api", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-api")), + files: ["registry/new-york/example/carousel-api.tsx"], + }, + "carousel-plugin": { + name: "carousel-plugin", + type: "components:example", + registryDependencies: ["carousel"], + component: React.lazy(() => import("@/registry/new-york/example/carousel-plugin")), + files: ["registry/new-york/example/carousel-plugin.tsx"], + }, "checkbox-demo": { name: "checkbox-demo", type: "components:example", @@ -1588,6 +1805,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/combobox-popover")), files: ["registry/new-york/example/combobox-popover.tsx"], }, + "combobox-responsive": { + name: "combobox-responsive", + type: "components:example", + registryDependencies: ["combobox","popover","drawer"], + component: React.lazy(() => import("@/registry/new-york/example/combobox-responsive")), + files: ["registry/new-york/example/combobox-responsive.tsx"], + }, "command-demo": { name: "command-demo", type: "components:example", @@ -1658,6 +1882,20 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/dialog-close-button")), files: ["registry/new-york/example/dialog-close-button.tsx"], }, + "drawer-demo": { + name: "drawer-demo", + type: "components:example", + registryDependencies: ["drawer"], + component: React.lazy(() => import("@/registry/new-york/example/drawer-demo")), + files: ["registry/new-york/example/drawer-demo.tsx"], + }, + "drawer-dialog": { + name: "drawer-dialog", + type: "components:example", + registryDependencies: ["drawer","dialog"], + component: React.lazy(() => import("@/registry/new-york/example/drawer-dialog")), + files: ["registry/new-york/example/drawer-dialog.tsx"], + }, "dropdown-menu-demo": { name: "dropdown-menu-demo", type: "components:example", @@ -1756,6 +1994,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/navigation-menu-demo")), files: ["registry/new-york/example/navigation-menu-demo.tsx"], }, + "pagination-demo": { + name: "pagination-demo", + type: "components:example", + registryDependencies: ["pagination"], + component: React.lazy(() => import("@/registry/new-york/example/pagination-demo")), + files: ["registry/new-york/example/pagination-demo.tsx"], + }, "popover-demo": { name: "popover-demo", type: "components:example", @@ -1784,6 +2029,34 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/radio-group-form")), files: ["registry/new-york/example/radio-group-form.tsx"], }, + "resizable-demo": { + name: "resizable-demo", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/new-york/example/resizable-demo")), + files: ["registry/new-york/example/resizable-demo.tsx"], + }, + "resizable-demo-with-handle": { + name: "resizable-demo-with-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/new-york/example/resizable-demo-with-handle")), + files: ["registry/new-york/example/resizable-demo-with-handle.tsx"], + }, + "resizable-vertical": { + name: "resizable-vertical", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/new-york/example/resizable-vertical")), + files: ["registry/new-york/example/resizable-vertical.tsx"], + }, + "resizable-handle": { + name: "resizable-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/new-york/example/resizable-handle")), + files: ["registry/new-york/example/resizable-handle.tsx"], + }, "scroll-area-demo": { name: "scroll-area-demo", type: "components:example", @@ -1854,6 +2127,13 @@ export const Index: Record = { component: React.lazy(() => import("@/registry/new-york/example/slider-demo")), files: ["registry/new-york/example/slider-demo.tsx"], }, + "sonner-demo": { + name: "sonner-demo", + type: "components:example", + registryDependencies: ["sonner"], + component: React.lazy(() => import("@/registry/new-york/example/sonner-demo")), + files: ["registry/new-york/example/sonner-demo.tsx"], + }, "switch-demo": { name: "switch-demo", type: "components:example", diff --git a/apps/www/app/docs/[[...slug]]/page.tsx b/apps/www/app/docs/[[...slug]]/page.tsx index 0e82b35078..8d91f69835 100644 --- a/apps/www/app/docs/[[...slug]]/page.tsx +++ b/apps/www/app/docs/[[...slug]]/page.tsx @@ -4,13 +4,12 @@ import { allDocs } from "contentlayer/generated" import "@/styles/mdx.css" import type { Metadata } from "next" import Link from "next/link" -import { ChevronRightIcon } from "@radix-ui/react-icons" +import { ChevronRightIcon, ExternalLinkIcon } from "@radix-ui/react-icons" import Balancer from "react-wrap-balancer" import { siteConfig } from "@/config/site" import { getTableOfContents } from "@/lib/toc" import { absoluteUrl, cn } from "@/lib/utils" -import { Icons } from "@/components/icons" import { Mdx } from "@/components/mdx-components" import { DocsPager } from "@/components/pager" import { DashboardTableOfContents } from "@/components/toc" @@ -107,27 +106,28 @@ export default async function DocPage({ params }: DocPageProps) {

)} - {doc.radix ? ( + {doc.links ? (
- {doc.radix?.link && ( + {doc.links?.doc && ( - - Radix UI + Docs + )} - {doc.radix?.api && ( + {doc.links?.api && ( API Reference + )}
diff --git a/apps/www/app/docs/layout.tsx b/apps/www/app/docs/layout.tsx index 7168fce1a0..e131e23367 100644 --- a/apps/www/app/docs/layout.tsx +++ b/apps/www/app/docs/layout.tsx @@ -11,7 +11,7 @@ export default function DocsLayout({ children }: DocsLayoutProps) {
diff --git a/apps/www/app/examples/authentication/page.tsx b/apps/www/app/examples/authentication/page.tsx index b838f102b8..c994b222c0 100644 --- a/apps/www/app/examples/authentication/page.tsx +++ b/apps/www/app/examples/authentication/page.tsx @@ -40,7 +40,7 @@ export default function AuthenticationPage() { > Login -
+
shadcn/ui - Beautifully designed components built with Radix UI and Tailwind - CSS. + Beautifully designed components that you can copy and paste into + your apps. Accessible. Customizable. Open Source.
diff --git a/apps/www/app/examples/dashboard/components/overview.tsx b/apps/www/app/examples/dashboard/components/overview.tsx index 4c52428a44..80b085f0c6 100644 --- a/apps/www/app/examples/dashboard/components/overview.tsx +++ b/apps/www/app/examples/dashboard/components/overview.tsx @@ -71,7 +71,12 @@ export function Overview() { axisLine={false} tickFormatter={(value) => `$${value}`} /> - + ) diff --git a/apps/www/app/examples/dashboard/components/team-switcher.tsx b/apps/www/app/examples/dashboard/components/team-switcher.tsx index 14b2752a6e..284ca79945 100644 --- a/apps/www/app/examples/dashboard/components/team-switcher.tsx +++ b/apps/www/app/examples/dashboard/components/team-switcher.tsx @@ -100,6 +100,7 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) { SC diff --git a/apps/www/app/examples/layout.tsx b/apps/www/app/examples/layout.tsx index 2a2a672e4c..57d44ff4fa 100644 --- a/apps/www/app/examples/layout.tsx +++ b/apps/www/app/examples/layout.tsx @@ -1,16 +1,16 @@ import { Metadata } from "next" import Link from "next/link" -import { ArrowRightIcon } from "@radix-ui/react-icons" import { cn } from "@/lib/utils" +import { Announcement } from "@/components/announcement" import { ExamplesNav } from "@/components/examples-nav" import { + PageActions, PageHeader, PageHeaderDescription, PageHeaderHeading, } from "@/components/page-header" import { buttonVariants } from "@/registry/new-york/ui/button" -import { Separator } from "@/registry/new-york/ui/separator" export const metadata: Metadata = { title: "Examples", @@ -25,27 +25,17 @@ export default function ExamplesLayout({ children }: ExamplesLayoutProps) { return ( <>
- - - 🎉 {" "} - Style, a new CLI and more. - - Introducing Style, a new CLI and more. - - - + + - Check out some examples. + Check out some examples Examples Dashboard, cards, authentication. Some examples built using the components. Use this as a guide to build your own. -
+ Components -
+
-
+
{children}
diff --git a/apps/www/app/examples/mail/components/account-switcher.tsx b/apps/www/app/examples/mail/components/account-switcher.tsx new file mode 100644 index 0000000000..f8dc77a162 --- /dev/null +++ b/apps/www/app/examples/mail/components/account-switcher.tsx @@ -0,0 +1,63 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/registry/new-york/ui/select" + +interface AccountSwitcherProps { + isCollapsed: boolean + accounts: { + label: string + email: string + icon: React.ReactNode + }[] +} + +export function AccountSwitcher({ + isCollapsed, + accounts, +}: AccountSwitcherProps) { + const [selectedAccount, setSelectedAccount] = React.useState( + accounts[0].email + ) + + return ( + + ) +} diff --git a/apps/www/app/examples/mail/components/mail-display.tsx b/apps/www/app/examples/mail/components/mail-display.tsx new file mode 100644 index 0000000000..53885cea08 --- /dev/null +++ b/apps/www/app/examples/mail/components/mail-display.tsx @@ -0,0 +1,254 @@ +import addDays from "date-fns/addDays" +import addHours from "date-fns/addHours" +import format from "date-fns/format" +import nextSaturday from "date-fns/nextSaturday" +import { + Archive, + ArchiveX, + Clock, + Forward, + MoreVertical, + Reply, + ReplyAll, + Trash2, +} from "lucide-react" + +import { + DropdownMenuContent, + DropdownMenuItem, +} from "@/registry/default/ui/dropdown-menu" +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/registry/new-york/ui/avatar" +import { Button } from "@/registry/new-york/ui/button" +import { Calendar } from "@/registry/new-york/ui/calendar" +import { + DropdownMenu, + DropdownMenuTrigger, +} from "@/registry/new-york/ui/dropdown-menu" +import { Label } from "@/registry/new-york/ui/label" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/registry/new-york/ui/popover" +import { Separator } from "@/registry/new-york/ui/separator" +import { Switch } from "@/registry/new-york/ui/switch" +import { Textarea } from "@/registry/new-york/ui/textarea" +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/registry/new-york/ui/tooltip" +import { Mail } from "@/app/examples/mail/data" + +interface MailDisplayProps { + mail: Mail | null +} + +export function MailDisplay({ mail }: MailDisplayProps) { + const today = new Date() + + return ( +
+
+
+ + + + + Archive + + + + + + Move to junk + + + + + + Move to trash + + + + + + + + + + +
+
Snooze until
+
+ + + + +
+
+
+ +
+
+
+ Snooze +
+
+
+ + + + + Reply + + + + + + Reply all + + + + + + Forward + +
+ + + + + + + Mark as unread + Star thread + Add label + Mute thread + + +
+ + {mail ? ( +
+
+
+ + + + {mail.name + .split(" ") + .map((chunk) => chunk[0]) + .join("")} + + +
+
{mail.name}
+
{mail.subject}
+
+ Reply-To: {mail.email} +
+
+
+ {mail.date && ( +
+ {format(new Date(mail.date), "PPpp")} +
+ )} +
+ +
+ {mail.text} +
+ +
+
+
+