promote-email-templates 0.0.19 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.react-email/.eslintrc.js +52 -0
  2. package/.react-email/.prettierignore +3 -0
  3. package/.react-email/.prettierrc.js +8 -0
  4. package/.react-email/license.md +7 -0
  5. package/.react-email/next.config.js +36 -0
  6. package/.react-email/package.json +1 -0
  7. package/.react-email/postcss.config.js +8 -0
  8. package/.react-email/readme.md +44 -0
  9. package/.react-email/src/actions/get-email-path-from-slug.ts +26 -0
  10. package/.react-email/src/actions/get-emails-directory-metadata.spec.ts +73 -0
  11. package/.react-email/src/actions/get-emails-directory-metadata.ts +91 -0
  12. package/.react-email/src/actions/render-email-by-path.tsx +59 -0
  13. package/.react-email/src/app/favicon.ico +0 -0
  14. package/.react-email/src/app/globals.css +35 -0
  15. package/.react-email/src/app/inter.ts +7 -0
  16. package/.react-email/src/app/layout.tsx +36 -0
  17. package/.react-email/src/app/logo.png +0 -0
  18. package/.react-email/src/app/page.tsx +47 -0
  19. package/.react-email/src/app/preview/[...slug]/page.tsx +65 -0
  20. package/.react-email/src/app/preview/[...slug]/preview.tsx +141 -0
  21. package/.react-email/src/app/preview/[...slug]/rendering-error.tsx +40 -0
  22. package/.react-email/src/components/button.tsx +90 -0
  23. package/.react-email/src/components/code-container.tsx +145 -0
  24. package/.react-email/src/components/code.tsx +112 -0
  25. package/.react-email/src/components/heading.tsx +113 -0
  26. package/.react-email/src/components/icons/icon-arrow-down.tsx +16 -0
  27. package/.react-email/src/components/icons/icon-base.tsx +24 -0
  28. package/.react-email/src/components/icons/icon-button.tsx +23 -0
  29. package/.react-email/src/components/icons/icon-check.tsx +19 -0
  30. package/.react-email/src/components/icons/icon-clipboard.tsx +40 -0
  31. package/.react-email/src/components/icons/icon-download.tsx +19 -0
  32. package/.react-email/src/components/icons/icon-file.tsx +19 -0
  33. package/.react-email/src/components/icons/icon-folder-open.tsx +19 -0
  34. package/.react-email/src/components/icons/icon-folder.tsx +18 -0
  35. package/.react-email/src/components/icons/icon-hide-sidebar.tsx +23 -0
  36. package/.react-email/src/components/icons/icon-monitor.tsx +19 -0
  37. package/.react-email/src/components/icons/icon-phone.tsx +26 -0
  38. package/.react-email/src/components/icons/icon-source.tsx +19 -0
  39. package/.react-email/src/components/index.ts +7 -0
  40. package/.react-email/src/components/logo.tsx +64 -0
  41. package/.react-email/src/components/send.tsx +135 -0
  42. package/.react-email/src/components/shell.tsx +115 -0
  43. package/.react-email/src/components/sidebar/index.ts +1 -0
  44. package/.react-email/src/components/sidebar/sidebar-directory-children.tsx +134 -0
  45. package/.react-email/src/components/sidebar/sidebar-directory.tsx +106 -0
  46. package/.react-email/src/components/sidebar/sidebar.tsx +45 -0
  47. package/.react-email/src/components/text.tsx +99 -0
  48. package/.react-email/src/components/tooltip-content.tsx +32 -0
  49. package/.react-email/src/components/tooltip.tsx +19 -0
  50. package/.react-email/src/components/topbar.tsx +161 -0
  51. package/.react-email/src/contexts/emails.tsx +127 -0
  52. package/.react-email/src/hooks/use-hot-reload.ts +35 -0
  53. package/.react-email/src/hooks/use-rendering-metadata.ts +36 -0
  54. package/.react-email/src/utils/cn.ts +6 -0
  55. package/.react-email/src/utils/constants.ts +6 -0
  56. package/.react-email/src/utils/copy-text-to-clipboard.ts +7 -0
  57. package/.react-email/src/utils/emails-directory-absolute-path.ts +34 -0
  58. package/.react-email/src/utils/get-email-component.ts +108 -0
  59. package/.react-email/src/utils/improve-error-with-sourcemap.ts +55 -0
  60. package/.react-email/src/utils/index.ts +5 -0
  61. package/.react-email/src/utils/language-map.ts +7 -0
  62. package/.react-email/src/utils/static-node-modules-for-vm.ts +92 -0
  63. package/.react-email/src/utils/types/as.ts +26 -0
  64. package/.react-email/src/utils/types/email-template.ts +8 -0
  65. package/.react-email/src/utils/types/error-object.ts +11 -0
  66. package/.react-email/src/utils/types/hot-reload-change.ts +6 -0
  67. package/.react-email/src/utils/types/hot-reload-event.ts +6 -0
  68. package/.react-email/src/utils/unreachable.ts +8 -0
  69. package/.react-email/tailwind.config.ts +94 -0
  70. package/dist/index.d.mts +238 -83
  71. package/dist/index.d.ts +238 -83
  72. package/dist/index.js +364 -105
  73. package/dist/index.mjs +360 -105
  74. package/package.json +1 -1
  75. package/emails/admin/abort-order-request.tsx +0 -58
  76. package/emails/admin/index.ts +0 -2
  77. package/emails/admin/revert-payment-request-admin.tsx +0 -54
  78. package/emails/all/index.ts +0 -1
  79. package/emails/all/welcome.tsx +0 -104
  80. package/emails/brand/evidences-accepted-brand.tsx +0 -59
  81. package/emails/brand/evidences-submitted-brand.tsx +0 -65
  82. package/emails/brand/index.ts +0 -6
  83. package/emails/brand/new-order-created-brand.tsx +0 -74
  84. package/emails/brand/order-accepted-brand.tsx +0 -63
  85. package/emails/brand/order-cancelled-brand.tsx +0 -68
  86. package/emails/brand/order-rejected-brand.tsx +0 -79
  87. package/emails/creator/evidences-approved-creator.tsx +0 -62
  88. package/emails/creator/evidences-rejected-creator.tsx +0 -74
  89. package/emails/creator/index.ts +0 -5
  90. package/emails/creator/new-order-created-creator.tsx +0 -70
  91. package/emails/creator/order-cancelled-creator.tsx +0 -69
  92. package/emails/creator/order-payment-creator.tsx +0 -58
  93. package/emails/index.ts +0 -5
  94. package/emails/shared/components/base-head.tsx +0 -19
  95. package/emails/shared/components/comment-component.tsx +0 -32
  96. package/emails/shared/components/footer.tsx +0 -84
  97. package/emails/shared/components/header.tsx +0 -24
  98. package/emails/shared/components/new-order-info.tsx +0 -60
  99. package/emails/shared/components/payment-amount.tsx +0 -37
  100. package/emails/shared/components/user-Info.tsx +0 -55
  101. package/emails/shared/index.ts +0 -3
  102. package/emails/shared/styles.ts +0 -72
  103. package/emails/shared/types.ts +0 -179
  104. package/emails/shared/values.ts +0 -19
@@ -0,0 +1,134 @@
1
+ import { AnimatePresence, LayoutGroup, motion } from 'framer-motion';
2
+ import * as Collapsible from '@radix-ui/react-collapsible';
3
+ import Link from 'next/link';
4
+ import { useSearchParams } from 'next/navigation';
5
+ import type { EmailsDirectory } from '../../actions/get-emails-directory-metadata';
6
+ import {
7
+ emailsDirectoryAbsolutePath,
8
+ pathSeparator,
9
+ } from '../../utils/emails-directory-absolute-path';
10
+ import { cn } from '../../utils';
11
+ import { IconFile } from '../icons/icon-file';
12
+ import { SidebarDirectory } from './sidebar-directory';
13
+
14
+ export const SidebarDirectoryChildren = (props: {
15
+ emailsDirectoryMetadata: EmailsDirectory;
16
+ currentEmailOpenSlug?: string;
17
+ open: boolean;
18
+ isRoot?: boolean;
19
+ }) => {
20
+ const searchParams = useSearchParams();
21
+ const directoryPathRelativeToEmailsDirectory =
22
+ props.emailsDirectoryMetadata.absolutePath
23
+ .replace(`${emailsDirectoryAbsolutePath}${pathSeparator}`, '')
24
+ .replace(emailsDirectoryAbsolutePath, '')
25
+ .trim();
26
+ const isBaseEmailsDirectory =
27
+ props.emailsDirectoryMetadata.absolutePath === emailsDirectoryAbsolutePath;
28
+
29
+ return (
30
+ <AnimatePresence initial={false}>
31
+ {props.open ? (
32
+ <Collapsible.Content
33
+ asChild
34
+ className="relative data-[root=true]:mt-2 overflow-y-hidden pl-1"
35
+ forceMount
36
+ >
37
+ <motion.div
38
+ animate={{ opacity: 1, height: 'auto' }}
39
+ exit={{ opacity: 0, height: 0 }}
40
+ initial={{ opacity: 0, height: 0 }}
41
+ >
42
+ {props.isRoot ? null : (
43
+ <div className="line absolute left-2.5 w-px h-full bg-slate-6" />
44
+ )}
45
+
46
+ <div className="data-[root=true]:py-2 flex flex-col truncate">
47
+ <LayoutGroup id="sidebar">
48
+ {props.emailsDirectoryMetadata.subDirectories.map(
49
+ (subDirectory) => (
50
+ <SidebarDirectory
51
+ className="pl-4 py-0"
52
+ currentEmailOpenSlug={props.currentEmailOpenSlug}
53
+ emailsDirectoryMetadata={subDirectory}
54
+ key={subDirectory.absolutePath}
55
+ />
56
+ ),
57
+ )}
58
+
59
+ {props.emailsDirectoryMetadata.emailFilenames.map(
60
+ (emailFilename, index) => {
61
+ const emailSlug = `${directoryPathRelativeToEmailsDirectory}${
62
+ !isBaseEmailsDirectory ? pathSeparator : ''
63
+ }${emailFilename}`;
64
+ const removeExtensionFrom = (path: string) => {
65
+ if (
66
+ path.split('.').pop() === 'tsx' ||
67
+ path.split('.').pop() === 'jsx' ||
68
+ path.split('.').pop() === 'js'
69
+ ) {
70
+ return path.split('.').slice(0, -1).join('.');
71
+ }
72
+
73
+ return path;
74
+ };
75
+ const isCurrentPage = props.currentEmailOpenSlug
76
+ ? removeExtensionFrom(props.currentEmailOpenSlug) ===
77
+ emailSlug
78
+ : false;
79
+
80
+ return (
81
+ <Link
82
+ href={{
83
+ pathname: `/preview/${emailSlug}`,
84
+ search: searchParams.toString(),
85
+ }}
86
+ key={emailSlug}
87
+ >
88
+ <motion.span
89
+ animate={{ x: 0, opacity: 1 }}
90
+ className={cn(
91
+ 'text-[14px] flex items-center align-middle pl-3 h-8 max-w-full rounded-md text-slate-11 relative transition-colors',
92
+ {
93
+ 'text-cyan-11': isCurrentPage,
94
+ 'hover:text-slate-12':
95
+ props.currentEmailOpenSlug !== emailSlug,
96
+ },
97
+ )}
98
+ initial={{ x: -10 + -index * 1.5, opacity: 0 }}
99
+ transition={{
100
+ x: { delay: 0.03 * index, duration: 0.2 },
101
+ opacity: { delay: 0.03 * index, duration: 0.2 },
102
+ }}
103
+ >
104
+ {isCurrentPage ? (
105
+ <motion.span
106
+ animate={{ opacity: 1 }}
107
+ className="absolute left-0 right-0 top-0 bottom-0 rounded-md bg-cyan-5 opacity-0"
108
+ exit={{ opacity: 0 }}
109
+ initial={{ opacity: 0 }}
110
+ >
111
+ {!props.isRoot && (
112
+ <div className="bg-cyan-11 w-px absolute top-1 left-1.5 h-6" />
113
+ )}
114
+ </motion.span>
115
+ ) : null}
116
+ <IconFile
117
+ className="absolute left-4 w-[24px] h-[24px]"
118
+ height="24"
119
+ width="24"
120
+ />
121
+ <span className="truncate pl-8">{emailFilename}</span>
122
+ </motion.span>
123
+ </Link>
124
+ );
125
+ },
126
+ )}
127
+ </LayoutGroup>
128
+ </div>
129
+ </motion.div>
130
+ </Collapsible.Content>
131
+ ) : null}
132
+ </AnimatePresence>
133
+ );
134
+ };
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+ import * as Collapsible from '@radix-ui/react-collapsible';
3
+ import * as React from 'react';
4
+ import { cn } from '../../utils';
5
+ import {
6
+ emailsDirectoryAbsolutePath,
7
+ pathSeparator,
8
+ } from '../../utils/emails-directory-absolute-path';
9
+ import { type EmailsDirectory } from '../../actions/get-emails-directory-metadata';
10
+ import { Heading } from '../heading';
11
+ import { IconFolder } from '../icons/icon-folder';
12
+ import { IconFolderOpen } from '../icons/icon-folder-open';
13
+ import { IconArrowDown } from '../icons/icon-arrow-down';
14
+ import { SidebarDirectoryChildren } from './sidebar-directory-children';
15
+
16
+ interface SidebarDirectoryProps {
17
+ emailsDirectoryMetadata: EmailsDirectory;
18
+ className?: string;
19
+ currentEmailOpenSlug?: string;
20
+ }
21
+
22
+ const persistedOpenDirectories = new Set<string>();
23
+
24
+ export const SidebarDirectory = ({
25
+ emailsDirectoryMetadata: directoryMetadata,
26
+ className,
27
+ currentEmailOpenSlug,
28
+ }: SidebarDirectoryProps) => {
29
+ const isBaseEmailsDirectory =
30
+ directoryMetadata.absolutePath === emailsDirectoryAbsolutePath;
31
+ const directoryPathRelativeToBaseEmailsDirectory =
32
+ directoryMetadata.absolutePath
33
+ .replace(`${emailsDirectoryAbsolutePath}${pathSeparator}`, '')
34
+ .replace(emailsDirectoryAbsolutePath, '')
35
+ .trim();
36
+ const doesDirectoryContainCurrentEmailOpen = currentEmailOpenSlug
37
+ ? currentEmailOpenSlug.includes(directoryPathRelativeToBaseEmailsDirectory)
38
+ : false;
39
+
40
+ const isEmpty =
41
+ directoryMetadata.emailFilenames.length > 0 ||
42
+ directoryMetadata.subDirectories.length > 0;
43
+
44
+ const [open, setOpen] = React.useState(
45
+ persistedOpenDirectories.has(directoryMetadata.absolutePath) ||
46
+ isBaseEmailsDirectory ||
47
+ doesDirectoryContainCurrentEmailOpen,
48
+ );
49
+
50
+ return (
51
+ <Collapsible.Root
52
+ className={cn('group', className)}
53
+ data-root={isBaseEmailsDirectory}
54
+ onOpenChange={(isOpening) => {
55
+ if (isOpening) {
56
+ persistedOpenDirectories.add(directoryMetadata.absolutePath);
57
+ } else {
58
+ persistedOpenDirectories.delete(directoryMetadata.absolutePath);
59
+ }
60
+
61
+ setOpen(isOpening);
62
+ }}
63
+ open={open}
64
+ >
65
+ <Collapsible.Trigger
66
+ className={cn(
67
+ 'text-[14px] flex items-center font-medium gap-2 justify-between w-full my-1',
68
+ {
69
+ 'cursor-pointer': !isEmpty,
70
+ },
71
+ )}
72
+ >
73
+ <div className="flex items-center text-slate-11 transition ease-in-out duration-200 hover:text-slate-12 gap-1">
74
+ {open ? (
75
+ <IconFolderOpen height="24" width="24" />
76
+ ) : (
77
+ <IconFolder height="24" width="24" />
78
+ )}
79
+ <Heading
80
+ as="h3"
81
+ className="transition ease-in-out duration-200 hover:text-slate-12"
82
+ color="gray"
83
+ size="2"
84
+ weight="medium"
85
+ >
86
+ {directoryMetadata.directoryName}
87
+ </Heading>
88
+ </div>
89
+ {isEmpty ? (
90
+ <IconArrowDown
91
+ className="data-[open=true]:rotate-180 transition-transform opacity-60 justify-self-end"
92
+ data-open={open}
93
+ />
94
+ ) : null}
95
+ </Collapsible.Trigger>
96
+
97
+ {isEmpty ? (
98
+ <SidebarDirectoryChildren
99
+ currentEmailOpenSlug={currentEmailOpenSlug}
100
+ emailsDirectoryMetadata={directoryMetadata}
101
+ open={open}
102
+ />
103
+ ) : null}
104
+ </Collapsible.Root>
105
+ );
106
+ };
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as Collapsible from '@radix-ui/react-collapsible';
5
+ import { useEmails } from '../../contexts/emails';
6
+ import { cn } from '../../utils';
7
+ import { Logo } from '../logo';
8
+ import { SidebarDirectoryChildren } from './sidebar-directory-children';
9
+
10
+ interface SidebarProps {
11
+ className?: string;
12
+ currentEmailOpenSlug?: string;
13
+ style?: React.CSSProperties;
14
+ }
15
+
16
+ export const Sidebar = ({
17
+ className,
18
+ currentEmailOpenSlug,
19
+ style,
20
+ }: SidebarProps) => {
21
+ const { emailsDirectoryMetadata } = useEmails();
22
+
23
+ return (
24
+ <aside
25
+ className={cn('border-r flex flex-col border-slate-6', className)}
26
+ style={{ ...style }}
27
+ >
28
+ <div className="p-4 h-[70px] flex-shrink items-center hidden lg:flex">
29
+ <Logo />
30
+ </div>
31
+ <nav className="p-4 flex-grow lg:pt-0 pl-0 w-screen h-[calc(100vh_-_70px)] lg:w-full lg:min-w-[275px] lg:max-w-[275px] flex flex-col overflow-y-auto">
32
+ <Collapsible.Root>
33
+ <React.Suspense>
34
+ <SidebarDirectoryChildren
35
+ currentEmailOpenSlug={currentEmailOpenSlug}
36
+ emailsDirectoryMetadata={emailsDirectoryMetadata}
37
+ isRoot
38
+ open
39
+ />
40
+ </React.Suspense>
41
+ </Collapsible.Root>
42
+ </nav>
43
+ </aside>
44
+ );
45
+ };
@@ -0,0 +1,99 @@
1
+ import * as SlotPrimitive from '@radix-ui/react-slot';
2
+ import * as React from 'react';
3
+ import { type As, unreachable, cn } from '../utils';
4
+
5
+ export type TextSize = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
6
+ export type TextColor = 'gray' | 'white';
7
+ export type TextTransform = 'uppercase' | 'lowercase' | 'capitalize';
8
+ export type TextWeight = 'normal' | 'medium';
9
+
10
+ interface TextOwnProps {
11
+ size?: TextSize;
12
+ color?: TextColor;
13
+ transform?: TextTransform;
14
+ weight?: TextWeight;
15
+ }
16
+
17
+ type TextProps = As<'span', 'div', 'p'> & TextOwnProps;
18
+
19
+ export const Text = React.forwardRef<HTMLSpanElement, Readonly<TextProps>>(
20
+ (
21
+ {
22
+ as: Tag = 'span',
23
+ size = '2',
24
+ color = 'gray',
25
+ transform,
26
+ weight = 'normal',
27
+ className,
28
+ children,
29
+ ...props
30
+ },
31
+ forwardedRef,
32
+ ) => (
33
+ <SlotPrimitive.Slot
34
+ className={cn(
35
+ className,
36
+ transform,
37
+ getSizesClassNames(size),
38
+ getColorClassNames(color),
39
+ getWeightClassNames(weight),
40
+ )}
41
+ ref={forwardedRef}
42
+ {...props}
43
+ >
44
+ <Tag>{children}</Tag>
45
+ </SlotPrimitive.Slot>
46
+ ),
47
+ );
48
+
49
+ const getSizesClassNames = (size: TextSize | undefined) => {
50
+ switch (size) {
51
+ case '1':
52
+ return 'text-xs';
53
+ case undefined:
54
+ case '2':
55
+ return 'text-sm';
56
+ case '3':
57
+ return 'text-base';
58
+ case '4':
59
+ return 'text-lg';
60
+ case '5':
61
+ return ['text-17px', 'md:text-xl tracking-[-0.16px]'];
62
+ case '6':
63
+ return 'text-2xl tracking-[-0.288px]';
64
+ case '7':
65
+ return 'text-[28px] leading-[34px] tracking-[-0.416px]';
66
+ case '8':
67
+ return 'text-[35px] leading-[42px] tracking-[-0.64px]';
68
+ case '9':
69
+ return 'text-6xl leading-[73px] tracking-[-0.896px]';
70
+ default:
71
+ return unreachable(size);
72
+ }
73
+ };
74
+
75
+ const getColorClassNames = (color: TextColor | undefined) => {
76
+ switch (color) {
77
+ case 'white':
78
+ return 'text-slate-12';
79
+ case undefined:
80
+ case 'gray':
81
+ return 'text-slate-11';
82
+ default:
83
+ return unreachable(color);
84
+ }
85
+ };
86
+
87
+ const getWeightClassNames = (weight: TextWeight | undefined) => {
88
+ switch (weight) {
89
+ case undefined:
90
+ case 'normal':
91
+ return 'font-normal';
92
+ case 'medium':
93
+ return 'font-medium';
94
+ default:
95
+ return unreachable(weight);
96
+ }
97
+ };
98
+
99
+ Text.displayName = 'Text';
@@ -0,0 +1,32 @@
1
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
2
+ import * as React from 'react';
3
+ import { cn } from '../utils';
4
+ import { inter } from '../app/inter';
5
+
6
+ type ContentElement = React.ElementRef<typeof TooltipPrimitive.Content>;
7
+ type ContentProps = React.ComponentPropsWithoutRef<
8
+ typeof TooltipPrimitive.Content
9
+ >;
10
+
11
+ export type TooltipProps = ContentProps;
12
+
13
+ export const TooltipContent = React.forwardRef<
14
+ ContentElement,
15
+ Readonly<TooltipProps>
16
+ >(({ sideOffset = 6, children, ...props }, forwardedRef) => (
17
+ <TooltipPrimitive.Portal>
18
+ <TooltipPrimitive.Content
19
+ {...props}
20
+ className={cn(
21
+ 'bg-black border border-slate-6 z-20 px-3 py-2 rounded-md text-xs',
22
+ `${inter.variable} font-sans`,
23
+ )}
24
+ ref={forwardedRef}
25
+ sideOffset={sideOffset}
26
+ >
27
+ {children}
28
+ </TooltipPrimitive.Content>
29
+ </TooltipPrimitive.Portal>
30
+ ));
31
+
32
+ TooltipContent.displayName = 'TooltipContent';
@@ -0,0 +1,19 @@
1
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
2
+ import * as React from 'react';
3
+ import { TooltipContent } from './tooltip-content';
4
+
5
+ type RootProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root>;
6
+
7
+ export type TooltipProps = RootProps;
8
+
9
+ export const TooltipRoot: React.FC<Readonly<TooltipProps>> = ({
10
+ children,
11
+ ...props
12
+ }) => <TooltipPrimitive.Root {...props}>{children}</TooltipPrimitive.Root>;
13
+
14
+ export const Tooltip = Object.assign(TooltipRoot, {
15
+ Arrow: TooltipPrimitive.TooltipArrow,
16
+ Provider: TooltipPrimitive.TooltipProvider,
17
+ Content: TooltipContent,
18
+ Trigger: TooltipPrimitive.TooltipTrigger,
19
+ });
@@ -0,0 +1,161 @@
1
+ 'use client';
2
+ import * as ToggleGroup from '@radix-ui/react-toggle-group';
3
+ import { motion } from 'framer-motion';
4
+ import * as React from 'react';
5
+ import { cn } from '../utils';
6
+ import { tabTransition } from '../utils/constants';
7
+ import { Heading } from './heading';
8
+ import { IconHideSidebar } from './icons/icon-hide-sidebar';
9
+ import { IconMonitor } from './icons/icon-monitor';
10
+ import { IconPhone } from './icons/icon-phone';
11
+ import { IconSource } from './icons/icon-source';
12
+ import { Send } from './send';
13
+ import { Tooltip } from './tooltip';
14
+
15
+ interface TopbarProps {
16
+ currentEmailOpenSlug: string;
17
+ activeView?: string;
18
+ markup?: string;
19
+ onToggleSidebar?: () => void;
20
+ setActiveView?: (view: string) => void;
21
+ }
22
+
23
+ export const Topbar: React.FC<Readonly<TopbarProps>> = ({
24
+ currentEmailOpenSlug,
25
+ markup,
26
+ activeView,
27
+ setActiveView,
28
+ onToggleSidebar,
29
+ }) => {
30
+ return (
31
+ <Tooltip.Provider>
32
+ <header className="flex relative items-center px-4 justify-between h-[70px] border-b border-slate-6">
33
+ <Tooltip>
34
+ <Tooltip.Trigger asChild>
35
+ <button
36
+ className="hidden lg:flex rounded-lg px-2 py-2 transition ease-in-out duration-200 relative hover:bg-slate-5 text-slate-11 hover:text-slate-12"
37
+ onClick={() => {
38
+ if (onToggleSidebar) {
39
+ onToggleSidebar();
40
+ }
41
+ }}
42
+ type="button"
43
+ >
44
+ <IconHideSidebar height={20} width={20} />
45
+ </button>
46
+ </Tooltip.Trigger>
47
+ <Tooltip.Content>Show/hide sidebar</Tooltip.Content>
48
+ </Tooltip>
49
+
50
+ <div className="items-center overflow-hidden hidden lg:flex text-center absolute left-1/2 transform -translate-x-1/2 top-1/2 -translate-y-1/2">
51
+ <Heading as="h2" className="truncate" size="2" weight="medium">
52
+ {currentEmailOpenSlug}
53
+ </Heading>
54
+ </div>
55
+
56
+ <div className="flex gap-3 justify-between lg:justify-start w-full lg:w-fit">
57
+ <ToggleGroup.Root
58
+ aria-label="View mode"
59
+ className="inline-block items-center bg-slate-2 border border-slate-6 rounded-md overflow-hidden h-[36px]"
60
+ onValueChange={(value) => {
61
+ if (value) setActiveView?.(value);
62
+ }}
63
+ type="single"
64
+ value={activeView}
65
+ >
66
+ <ToggleGroup.Item value="desktop">
67
+ <Tooltip>
68
+ <Tooltip.Trigger asChild>
69
+ <div
70
+ className={cn(
71
+ 'px-3 py-2 transition ease-in-out duration-200 relative hover:text-slate-12',
72
+ {
73
+ 'text-slate-11': activeView !== 'desktop',
74
+ 'text-slate-12': activeView === 'desktop',
75
+ },
76
+ )}
77
+ >
78
+ {activeView === 'desktop' && (
79
+ <motion.span
80
+ animate={{ opacity: 1 }}
81
+ className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
82
+ exit={{ opacity: 0 }}
83
+ initial={{ opacity: 0 }}
84
+ layoutId="topbar-tabs"
85
+ transition={tabTransition}
86
+ />
87
+ )}
88
+ <IconMonitor />
89
+ </div>
90
+ </Tooltip.Trigger>
91
+ <Tooltip.Content>Desktop</Tooltip.Content>
92
+ </Tooltip>
93
+ </ToggleGroup.Item>
94
+ <ToggleGroup.Item value="mobile">
95
+ <Tooltip>
96
+ <Tooltip.Trigger asChild>
97
+ <div
98
+ className={cn(
99
+ 'px-3 py-2 transition ease-in-out duration-200 relative hover:text-slate-12',
100
+ {
101
+ 'text-slate-11': activeView !== 'mobile',
102
+ 'text-slate-12': activeView === 'mobile',
103
+ },
104
+ )}
105
+ >
106
+ {activeView === 'mobile' && (
107
+ <motion.span
108
+ animate={{ opacity: 1 }}
109
+ className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
110
+ exit={{ opacity: 0 }}
111
+ initial={{ opacity: 0 }}
112
+ layoutId="topbar-tabs"
113
+ transition={tabTransition}
114
+ />
115
+ )}
116
+ <IconPhone />
117
+ </div>
118
+ </Tooltip.Trigger>
119
+ <Tooltip.Content>Mobile</Tooltip.Content>
120
+ </Tooltip>
121
+ </ToggleGroup.Item>
122
+ <ToggleGroup.Item value="source">
123
+ <Tooltip>
124
+ <Tooltip.Trigger asChild>
125
+ <div
126
+ className={cn(
127
+ 'px-3 py-2 transition ease-in-out duration-200 relative hover:text-slate-12',
128
+ {
129
+ 'text-slate-11': activeView !== 'source',
130
+ 'text-slate-12': activeView === 'source',
131
+ },
132
+ )}
133
+ >
134
+ {activeView === 'source' && (
135
+ <motion.span
136
+ animate={{ opacity: 1 }}
137
+ className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
138
+ exit={{ opacity: 0 }}
139
+ initial={{ opacity: 0 }}
140
+ layoutId="topbar-tabs"
141
+ transition={tabTransition}
142
+ />
143
+ )}
144
+ <IconSource />
145
+ </div>
146
+ </Tooltip.Trigger>
147
+ <Tooltip.Content>Code</Tooltip.Content>
148
+ </Tooltip>
149
+ </ToggleGroup.Item>
150
+ </ToggleGroup.Root>
151
+
152
+ {markup ? (
153
+ <div className="flex justify-end">
154
+ <Send markup={markup} />
155
+ </div>
156
+ ) : null}
157
+ </div>
158
+ </header>
159
+ </Tooltip.Provider>
160
+ );
161
+ };