@collabchron/notiq 0.2.0

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 (188) hide show
  1. package/README.md +71 -0
  2. package/components.json +21 -0
  3. package/eslint.config.mjs +16 -0
  4. package/next.config.ts +12 -0
  5. package/package.json +108 -0
  6. package/postcss.config.mjs +5 -0
  7. package/public/file.svg +1 -0
  8. package/public/globe.svg +1 -0
  9. package/public/images/icons/plus.svg +10 -0
  10. package/public/next.svg +1 -0
  11. package/public/vercel.svg +1 -0
  12. package/public/window.svg +1 -0
  13. package/src/app/actions.ts +2 -0
  14. package/src/app/api/ai/route.ts +175 -0
  15. package/src/app/api/edgestore/[...edgestore]/route.ts +28 -0
  16. package/src/app/favicon.ico +0 -0
  17. package/src/app/globals.css +205 -0
  18. package/src/app/layout.tsx +38 -0
  19. package/src/app/page.tsx +12 -0
  20. package/src/components/editor/Core.tsx +220 -0
  21. package/src/components/editor/hooks/instructions-messages.ts +300 -0
  22. package/src/components/editor/hooks/use-mobile.ts +19 -0
  23. package/src/components/editor/hooks/useReport.ts +67 -0
  24. package/src/components/editor/hooks/useResizeObservert.ts +22 -0
  25. package/src/components/editor/index.tsx +39 -0
  26. package/src/components/editor/lexical-on-change.tsx +28 -0
  27. package/src/components/editor/nodes/CollapsibleNode/CollapsibleContainerNode.ts +92 -0
  28. package/src/components/editor/nodes/CollapsibleNode/CollapsibleContentNode.ts +65 -0
  29. package/src/components/editor/nodes/CollapsibleNode/CollapsibleTitleNode.ts +105 -0
  30. package/src/components/editor/nodes/EquationNode/EquationComponent.tsx +143 -0
  31. package/src/components/editor/nodes/EquationNode/EquationNode.tsx +170 -0
  32. package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +228 -0
  33. package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx +137 -0
  34. package/src/components/editor/nodes/ExcalidrawNode/ImageResizer.tsx +317 -0
  35. package/src/components/editor/nodes/ExcalidrawNode/index.tsx +204 -0
  36. package/src/components/editor/nodes/FigmaNode/FigmaNode.tsx +134 -0
  37. package/src/components/editor/nodes/Hint/HintComponet.tsx +221 -0
  38. package/src/components/editor/nodes/Hint/index.tsx +190 -0
  39. package/src/components/editor/nodes/ImageNode/index.tsx +328 -0
  40. package/src/components/editor/nodes/InlineImageNode/InlineImageComponent.tsx +383 -0
  41. package/src/components/editor/nodes/InlineImageNode/InlineImageNode.css +94 -0
  42. package/src/components/editor/nodes/InlineImageNode/InlineImageNode.tsx +309 -0
  43. package/src/components/editor/nodes/LayoutNode/LayoutContainerNode.ts +146 -0
  44. package/src/components/editor/nodes/LayoutNode/LayoutItemNode.ts +79 -0
  45. package/src/components/editor/nodes/PollNode/index.tsx +204 -0
  46. package/src/components/editor/nodes/Stepper/index.tsx +260 -0
  47. package/src/components/editor/nodes/TweetNode/index.tsx +214 -0
  48. package/src/components/editor/nodes/index.ts +81 -0
  49. package/src/components/editor/plugins/AutoEmbedPlugin/index.tsx +350 -0
  50. package/src/components/editor/plugins/AutoLinkPlugin/index.tsx +56 -0
  51. package/src/components/editor/plugins/CodeActionMenuPlugin/components/CopyButton.tsx +70 -0
  52. package/src/components/editor/plugins/CodeActionMenuPlugin/components/PrettierButton.tsx +192 -0
  53. package/src/components/editor/plugins/CodeActionMenuPlugin/index.tsx +217 -0
  54. package/src/components/editor/plugins/CodeActionMenuPlugin/utils.ts +26 -0
  55. package/src/components/editor/plugins/CodeHighlightPlugin/index.ts +21 -0
  56. package/src/components/editor/plugins/CollapsiblePlugin/Collapsible.css +76 -0
  57. package/src/components/editor/plugins/CollapsiblePlugin/index.ts +228 -0
  58. package/src/components/editor/plugins/DragDropPastePlugin/index.tsx +44 -0
  59. package/src/components/editor/plugins/DraggableBlockPlugin/index.tsx +52 -0
  60. package/src/components/editor/plugins/EquationsPlugin/index.tsx +85 -0
  61. package/src/components/editor/plugins/ExcalidrawPlugin/index.tsx +98 -0
  62. package/src/components/editor/plugins/FigmaPlugin/index.tsx +42 -0
  63. package/src/components/editor/plugins/FloatingLinkEditorPlugin/index.tsx +445 -0
  64. package/src/components/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +275 -0
  65. package/src/components/editor/plugins/ImagesPlugin/index.tsx +222 -0
  66. package/src/components/editor/plugins/InlineImagePlugin/index.tsx +351 -0
  67. package/src/components/editor/plugins/LayoutPlugin/index.tsx +238 -0
  68. package/src/components/editor/plugins/LinkPlugin/index.tsx +36 -0
  69. package/src/components/editor/plugins/LinkWithMetaData/index.tsx +271 -0
  70. package/src/components/editor/plugins/MarkdownShortcutPlugin/index.tsx +11 -0
  71. package/src/components/editor/plugins/MarkdownTransformers/index.tsx +304 -0
  72. package/src/components/editor/plugins/PollPlugin/index.tsx +49 -0
  73. package/src/components/editor/plugins/ShortcutsPlugin/index.tsx +180 -0
  74. package/src/components/editor/plugins/ShortcutsPlugin/shortcuts.ts +253 -0
  75. package/src/components/editor/plugins/SlashCommand/index.tsx +621 -0
  76. package/src/components/editor/plugins/SpeechToTextPlugin/index.ts +127 -0
  77. package/src/components/editor/plugins/TabFocusPlugin/index.ts +58 -0
  78. package/src/components/editor/plugins/TableCellActionMenuPlugin/index.tsx +759 -0
  79. package/src/components/editor/plugins/TableCellResizer/index.tsx +438 -0
  80. package/src/components/editor/plugins/TableHoverActionsPlugin/index.tsx +314 -0
  81. package/src/components/editor/plugins/TablePlugin/index.tsx +99 -0
  82. package/src/components/editor/plugins/ToolbarPlugin/index.tsx +522 -0
  83. package/src/components/editor/plugins/TwitterPlugin/index.ts +35 -0
  84. package/src/components/editor/plugins/YouTubeNode/index.tsx +179 -0
  85. package/src/components/editor/plugins/YouTubePlugin/index.ts +41 -0
  86. package/src/components/editor/themes/editor-theme.ts +113 -0
  87. package/src/components/editor/themes/theme.css +377 -0
  88. package/src/components/editor/utils/ai.ts +291 -0
  89. package/src/components/editor/utils/canUseDOM.ts +12 -0
  90. package/src/components/editor/utils/editorFormatting.ts +282 -0
  91. package/src/components/editor/utils/environment.ts +50 -0
  92. package/src/components/editor/utils/extract-data.ts +166 -0
  93. package/src/components/editor/utils/getAllLexicalChildren.ts +13 -0
  94. package/src/components/editor/utils/getDOMRangeRect.ts +27 -0
  95. package/src/components/editor/utils/getSelectedNode.ts +27 -0
  96. package/src/components/editor/utils/gif.ts +29 -0
  97. package/src/components/editor/utils/invariant.ts +15 -0
  98. package/src/components/editor/utils/setFloatingElemPosition.ts +51 -0
  99. package/src/components/editor/utils/setFloatingElemPositionForLinkEditor.ts +40 -0
  100. package/src/components/editor/utils/setNodePlaceholderFromSelection/getNodePlaceholder.ts +51 -0
  101. package/src/components/editor/utils/setNodePlaceholderFromSelection/setNodePlaceholderFromSelection.ts +15 -0
  102. package/src/components/editor/utils/setNodePlaceholderFromSelection/setPlaceholderOnSelection.ts +114 -0
  103. package/src/components/editor/utils/setNodePlaceholderFromSelection/styles.css +6 -0
  104. package/src/components/editor/utils/url.ts +109 -0
  105. package/src/components/editor/utils/useLayoutEffect.ts +13 -0
  106. package/src/components/providers/QueryProvider.tsx +15 -0
  107. package/src/components/providers/SharedHistoryContext.tsx +28 -0
  108. package/src/components/providers/ToolbarContext.tsx +123 -0
  109. package/src/components/providers/theme-provider.tsx +11 -0
  110. package/src/components/theme/ModeToggle.tsx +40 -0
  111. package/src/components/ui/FileInput.tsx +40 -0
  112. package/src/components/ui/Input.css +32 -0
  113. package/src/components/ui/Select.css +42 -0
  114. package/src/components/ui/Select.tsx +36 -0
  115. package/src/components/ui/TextInput.tsx +48 -0
  116. package/src/components/ui/ai/ai-button.tsx +574 -0
  117. package/src/components/ui/ai/border.tsx +99 -0
  118. package/src/components/ui/ai/placeholder-input-vanish.tsx +282 -0
  119. package/src/components/ui/button.tsx +89 -0
  120. package/src/components/ui/card.tsx +76 -0
  121. package/src/components/ui/checkbox.tsx +30 -0
  122. package/src/components/ui/command.tsx +153 -0
  123. package/src/components/ui/dialog/Dialog.css +25 -0
  124. package/src/components/ui/dialog/Dialog.tsx +34 -0
  125. package/src/components/ui/dialog.tsx +122 -0
  126. package/src/components/ui/drop-downs/background-color.tsx +183 -0
  127. package/src/components/ui/drop-downs/block-format.tsx +159 -0
  128. package/src/components/ui/drop-downs/code.tsx +42 -0
  129. package/src/components/ui/drop-downs/color.tsx +177 -0
  130. package/src/components/ui/drop-downs/font-size.tsx +138 -0
  131. package/src/components/ui/drop-downs/font.tsx +155 -0
  132. package/src/components/ui/drop-downs/index.tsx +122 -0
  133. package/src/components/ui/drop-downs/insert-node.tsx +213 -0
  134. package/src/components/ui/drop-downs/text-align.tsx +123 -0
  135. package/src/components/ui/drop-downs/text-format.tsx +104 -0
  136. package/src/components/ui/dropdown-menu.tsx +201 -0
  137. package/src/components/ui/equation/EquationEditor.css +38 -0
  138. package/src/components/ui/equation/EquationEditor.tsx +56 -0
  139. package/src/components/ui/equation/KatexEquationAlterer.css +41 -0
  140. package/src/components/ui/equation/KatexEquationAlterer.tsx +83 -0
  141. package/src/components/ui/equation/KatexRenderer.tsx +66 -0
  142. package/src/components/ui/excalidraw/ExcalidrawModal.css +64 -0
  143. package/src/components/ui/excalidraw/ExcalidrawModal.tsx +234 -0
  144. package/src/components/ui/excalidraw/Modal.css +62 -0
  145. package/src/components/ui/excalidraw/Modal.tsx +110 -0
  146. package/src/components/ui/hover-card.tsx +29 -0
  147. package/src/components/ui/image/error-image.tsx +17 -0
  148. package/src/components/ui/image/file-upload.tsx +240 -0
  149. package/src/components/ui/image/image-resizer.tsx +297 -0
  150. package/src/components/ui/image/image-toolbar.tsx +264 -0
  151. package/src/components/ui/image/index.tsx +408 -0
  152. package/src/components/ui/image/lazy-image.tsx +68 -0
  153. package/src/components/ui/image/lazy-video.tsx +71 -0
  154. package/src/components/ui/input.tsx +22 -0
  155. package/src/components/ui/models/custom-dialog.tsx +320 -0
  156. package/src/components/ui/models/insert-gif.tsx +90 -0
  157. package/src/components/ui/models/insert-image.tsx +52 -0
  158. package/src/components/ui/models/insert-poll.tsx +29 -0
  159. package/src/components/ui/models/insert-table.tsx +62 -0
  160. package/src/components/ui/models/use-model.tsx +91 -0
  161. package/src/components/ui/poll/poll-component.tsx +304 -0
  162. package/src/components/ui/popover.tsx +33 -0
  163. package/src/components/ui/progress.tsx +28 -0
  164. package/src/components/ui/scroll-area.tsx +48 -0
  165. package/src/components/ui/separator.tsx +31 -0
  166. package/src/components/ui/skeleton.tsx +15 -0
  167. package/src/components/ui/sonner.tsx +31 -0
  168. package/src/components/ui/stepper/step.tsx +179 -0
  169. package/src/components/ui/stepper/stepper.tsx +89 -0
  170. package/src/components/ui/textarea.tsx +22 -0
  171. package/src/components/ui/toggle.tsx +71 -0
  172. package/src/components/ui/tooltip.tsx +32 -0
  173. package/src/components/ui/write/text-format-floting-toolbar.tsx +346 -0
  174. package/src/lib/edgestore.ts +9 -0
  175. package/src/lib/pinecone-client.ts +0 -0
  176. package/src/lib/utils.ts +6 -0
  177. package/src/utils/docSerialization.ts +77 -0
  178. package/src/utils/emoji-list.ts +16615 -0
  179. package/src/utils/getDOMRangeRect.ts +27 -0
  180. package/src/utils/getSelectedNode.ts +27 -0
  181. package/src/utils/getThemeSelector.ts +25 -0
  182. package/src/utils/isMobileWidth.ts +7 -0
  183. package/src/utils/joinClasses.ts +13 -0
  184. package/src/utils/setFloatingElemPosition.ts +74 -0
  185. package/src/utils/setFloatingElemPositionForLinkEditor.ts +46 -0
  186. package/src/utils/swipe.ts +127 -0
  187. package/src/utils/url.ts +38 -0
  188. package/tsconfig.json +27 -0
@@ -0,0 +1,122 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
5
+ import { X } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ const Dialog = DialogPrimitive.Root
10
+
11
+ const DialogTrigger = DialogPrimitive.Trigger
12
+
13
+ const DialogPortal = DialogPrimitive.Portal
14
+
15
+ const DialogClose = DialogPrimitive.Close
16
+
17
+ const DialogOverlay = React.forwardRef<
18
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
19
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
20
+ >(({ className, ...props }, ref) => (
21
+ <DialogPrimitive.Overlay
22
+ ref={ref}
23
+ className={cn(
24
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
25
+ className
26
+ )}
27
+ {...props}
28
+ />
29
+ ))
30
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31
+
32
+ const DialogContent = React.forwardRef<
33
+ React.ElementRef<typeof DialogPrimitive.Content>,
34
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
35
+ >(({ className, children, ...props }, ref) => (
36
+ <DialogPortal>
37
+ <DialogOverlay />
38
+ <DialogPrimitive.Content
39
+ ref={ref}
40
+ className={cn(
41
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
42
+ className
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
48
+ <X className="h-4 w-4" />
49
+ <span className="sr-only">Close</span>
50
+ </DialogPrimitive.Close>
51
+ </DialogPrimitive.Content>
52
+ </DialogPortal>
53
+ ))
54
+ DialogContent.displayName = DialogPrimitive.Content.displayName
55
+
56
+ const DialogHeader = ({
57
+ className,
58
+ ...props
59
+ }: React.HTMLAttributes<HTMLDivElement>) => (
60
+ <div
61
+ className={cn(
62
+ "flex flex-col space-y-1.5 text-center sm:text-left",
63
+ className
64
+ )}
65
+ {...props}
66
+ />
67
+ )
68
+ DialogHeader.displayName = "DialogHeader"
69
+
70
+ const DialogFooter = ({
71
+ className,
72
+ ...props
73
+ }: React.HTMLAttributes<HTMLDivElement>) => (
74
+ <div
75
+ className={cn(
76
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ )
82
+ DialogFooter.displayName = "DialogFooter"
83
+
84
+ const DialogTitle = React.forwardRef<
85
+ React.ElementRef<typeof DialogPrimitive.Title>,
86
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
87
+ >(({ className, ...props }, ref) => (
88
+ <DialogPrimitive.Title
89
+ ref={ref}
90
+ className={cn(
91
+ "text-lg font-semibold leading-none tracking-tight",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ ))
97
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
98
+
99
+ const DialogDescription = React.forwardRef<
100
+ React.ElementRef<typeof DialogPrimitive.Description>,
101
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
102
+ >(({ className, ...props }, ref) => (
103
+ <DialogPrimitive.Description
104
+ ref={ref}
105
+ className={cn("text-sm text-muted-foreground", className)}
106
+ {...props}
107
+ />
108
+ ))
109
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
110
+
111
+ export {
112
+ Dialog,
113
+ DialogPortal,
114
+ DialogOverlay,
115
+ DialogTrigger,
116
+ DialogClose,
117
+ DialogContent,
118
+ DialogHeader,
119
+ DialogFooter,
120
+ DialogTitle,
121
+ DialogDescription,
122
+ }
@@ -0,0 +1,183 @@
1
+ import { $getSelection, LexicalEditor } from "lexical";
2
+ import React, { useCallback } from "react";
3
+ import { $patchStyleText } from "@lexical/selection";
4
+ import { useTheme } from "next-themes";
5
+ import {
6
+ Popover,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ } from "@/components/ui/popover";
10
+ import { Button } from "@/components/ui/button";
11
+ import { cn } from "@/lib/utils";
12
+ import { Separator } from "@/components/ui/separator";
13
+ import { BaselineIcon, PaintBucketIcon } from "lucide-react";
14
+
15
+ export default function BackgroundColor({
16
+ disabled,
17
+ color,
18
+ bgColor,
19
+ editor,
20
+ isTable = false,
21
+ side = "bottom",
22
+ sideOffset = 0,
23
+ style,
24
+ }: {
25
+ disabled: boolean;
26
+ color?: string;
27
+ bgColor?: string;
28
+ editor: LexicalEditor;
29
+ isTable?: boolean;
30
+ style?: React.CSSProperties;
31
+ side?: "bottom" | "left" | "right" | "top";
32
+ sideOffset?: number;
33
+ }) {
34
+ const { theme } = useTheme();
35
+
36
+ const applyStyleText = useCallback(
37
+ (styles: Record<string, string>, skipHistoryStack?: boolean) => {
38
+ editor.update(
39
+ () => {
40
+ const selection = $getSelection();
41
+ if (selection !== null) {
42
+ $patchStyleText(selection, styles);
43
+ }
44
+ },
45
+ skipHistoryStack ? { tag: "historic" } : {}
46
+ );
47
+ },
48
+ [editor]
49
+ );
50
+ const onFontColorSelect = useCallback(
51
+ (value: string, skipHistoryStack: boolean) => {
52
+ applyStyleText({ color: value }, skipHistoryStack);
53
+ },
54
+ [applyStyleText]
55
+ );
56
+
57
+ const onBgColorSelect = useCallback(
58
+ (value: string, skipHistoryStack: boolean) => {
59
+ applyStyleText({ "background-color": value }, skipHistoryStack);
60
+ },
61
+ [applyStyleText]
62
+ );
63
+ const dark = React.useMemo(
64
+ () => ({
65
+ font: {
66
+ default: "white",
67
+ Gray: "var(--font-gray)",
68
+ Brown: "var(--font-brown)",
69
+ Orange: "var(--font-orange)",
70
+ Yellow: "var(--font-yellow)",
71
+ Green: "var(--font-green)",
72
+ Blue: "var(--font-blue)",
73
+ Purple: "var(--font-purple)",
74
+ Pink: "var(--font-pink)",
75
+ Red: "var(--font-red)",
76
+ },
77
+ background: {
78
+ default: "none",
79
+ Gray: "var(--background-gray)",
80
+ Brown: "var(--background-brown)",
81
+ Orange: "var(--background-orange)",
82
+ Yellow: "var(--background-yellow)",
83
+ Green: "var(--background-green)",
84
+ Blue: "var(--background-blue)",
85
+ Purple: "var(--background-purple)",
86
+ Pink: "var(--background-pink)",
87
+ Red: "var(--background-red)",
88
+ },
89
+ }),
90
+ []
91
+ );
92
+
93
+ const light = React.useMemo(
94
+ () => ({
95
+ font: {
96
+ Gray: "var(--font-gray)",
97
+ Brown: "var(--font-brown)",
98
+ Orange: "var(--font-orange)",
99
+ Yellow: "var(--font-yellow)",
100
+ Green: "var(--font-green)",
101
+ Blue: "var(--font-blue)",
102
+ Purple: "var(--font-purple)",
103
+ Pink: "var(--font-pink)",
104
+ Red: "var(--font-red)",
105
+ },
106
+ background: {
107
+ Gray: "var(--background-gray)",
108
+ Brown: "var(--background-brown)",
109
+ Orange: "var(--background-orange)",
110
+ Yellow: "var(--background-yellow)",
111
+ Green: "var(--background-green)",
112
+ Blue: "var(--background-blue)",
113
+ Purple: "var(--background-purple)",
114
+ Pink: "var(--background-pink)",
115
+ Red: "var(--background-red)",
116
+ },
117
+ }),
118
+ []
119
+ );
120
+
121
+ const themeColor = React.useMemo(
122
+ () => (theme === "dark" ? dark : light),
123
+ [theme, dark, light]
124
+ );
125
+
126
+
127
+ return (
128
+ <Popover>
129
+ <PopoverTrigger asChild disabled={disabled}>
130
+ {!isTable ? (
131
+ <Button
132
+ style={{
133
+ ...style, background: bgColor === "#fff" ? "transparent" : bgColor,
134
+ }}
135
+ variant={"transparent"}
136
+ className="px-2 border-none cursor-pointer hover:dark-bg-accent hover:text-foreground"
137
+ size="Toolbar"
138
+ onMouseDown={(e) => e.preventDefault()}
139
+ >
140
+ <PaintBucketIcon className="h-7 w-7" />
141
+ </Button>
142
+ ) : (
143
+ <div
144
+ style={{
145
+ ...style, background: bgColor === "#fff" ? "transparent" : bgColor,
146
+ }}
147
+ onMouseDown={(e) => e.preventDefault()}
148
+ className="cursor-pointer"
149
+ >
150
+ Background
151
+ </div>
152
+ )}
153
+ </PopoverTrigger>
154
+ <PopoverContent className="max-w-32 w-full p-2 z-[250]" side={side} sideOffset={sideOffset}>
155
+ <div className="flex flex-col">
156
+ <div className="flex flex-col gap-y-1">
157
+ <span className="text-[10px] md:text-[14px] cursor-default font-bold text-gray-500">
158
+ Background
159
+ </span>
160
+ <div className="w-full flex flex-wrap gap-1">
161
+ {Object.entries(themeColor.background).map(
162
+ ([_, colorValue]) => (
163
+ <Button
164
+ key={colorValue}
165
+ onClick={() => onBgColorSelect(colorValue, false)}
166
+
167
+ type="button"
168
+ className={cn(
169
+ "w-[18px] p-0 h-[18px] rounded-[3px]",
170
+ colorValue === bgColor && "ring-2 ring-offset-2"
171
+ )}
172
+ style={{ background: colorValue }}
173
+ onMouseDown={(e) => e.preventDefault()}
174
+ />
175
+ )
176
+ )}
177
+ </div>
178
+ </div>
179
+ </div>
180
+ </PopoverContent>
181
+ </Popover>
182
+ );
183
+ }
@@ -0,0 +1,159 @@
1
+ import { useMemo } from "react";
2
+ import {
3
+ Pilcrow,
4
+ Heading1,
5
+ Heading2,
6
+ Heading3,
7
+ Heading4,
8
+ Heading5,
9
+ Heading6,
10
+ List,
11
+ ListTodo,
12
+ ListOrdered,
13
+ Braces,
14
+ Quote,
15
+ } from "lucide-react";
16
+ import {
17
+ formatBulletList,
18
+ formatCheckList,
19
+ formatCode,
20
+ formatHeading,
21
+ formatNumberedList,
22
+ formatParagraph,
23
+ formatQuote,
24
+ } from "@/components/editor/utils/editorFormatting";
25
+ import { LexicalEditor } from "lexical";
26
+ import { DropDown } from ".";
27
+
28
+ const blockTypeToBlockName = {
29
+ paragraph: "Paragraph",
30
+ h1: "Heading 1",
31
+ h2: "Heading 2",
32
+ h3: "Heading 3",
33
+ h4: "Heading 4",
34
+ h5: "Heading 5",
35
+ h6: "Heading 6",
36
+ bullet: "Bullet List",
37
+ check: "Checklist",
38
+ number: "Numbered List",
39
+ code: "Code Block",
40
+ quote: "Blockquote",
41
+ };
42
+
43
+ export default function BlockFormatDropDown({
44
+ editor,
45
+ blockType,
46
+ disabled = false,
47
+ style,
48
+ ShowChevronsUpDown=true,
49
+ side,
50
+ sideOffset
51
+ }: {
52
+ blockType: keyof typeof blockTypeToBlockName;
53
+ editor: LexicalEditor;
54
+ disabled?: boolean;
55
+ style?: React.CSSProperties;
56
+ ShowChevronsUpDown?:boolean
57
+ side?: "top" | "right" | "bottom" | "left" | undefined
58
+ sideOffset?:number
59
+ }) {
60
+ const Blocks = useMemo(
61
+ () => ({
62
+ paragraph: {
63
+ icon: <Pilcrow className="size-4" />,
64
+ label: "paragraph",
65
+ desc: "Just start writing plain text.",
66
+ func: () => formatParagraph(editor),
67
+ },
68
+ h1: {
69
+ icon: <Heading1 className="size-4" />,
70
+ desc: "Heading 1 for main titles.",
71
+ label: "Heading 1",
72
+ func: () => formatHeading(editor, blockType, "h1"),
73
+ },
74
+ h2: {
75
+ icon: <Heading2 className="size-4" />,
76
+ desc: "Heading 2 for major sections.",
77
+ label: "Heading 2",
78
+ func: () => formatHeading(editor, blockType, "h2"),
79
+ },
80
+ h3: {
81
+ icon: <Heading3 className="size-4" />,
82
+ desc: "Heading 3 for sub-sections.",
83
+ label: "Heading 3",
84
+ func: () => formatHeading(editor, blockType, "h3"),
85
+ },
86
+ h4: {
87
+ icon: <Heading4 className="size-4" />,
88
+ desc: "Heading 4 for minor sections.",
89
+ label: "Heading 4",
90
+ func: () => formatHeading(editor, blockType, "h4"),
91
+ },
92
+ h5: {
93
+ icon: <Heading5 className="size-4" />,
94
+ desc: "Heading 5 for small headings.",
95
+ label: "Heading 5",
96
+ func: () => formatHeading(editor, blockType, "h5"),
97
+ },
98
+ h6: {
99
+ icon: <Heading6 className="size-4" />,
100
+ desc: "Heading 6 for tiny headings.",
101
+ label: "Heading 6",
102
+ func: () => formatHeading(editor, blockType, "h6"),
103
+ },
104
+ bullet: {
105
+ icon: <List className="size-4" />,
106
+ desc: "Bullet list for unordered items.",
107
+ label: "Bullet List",
108
+ func: () => formatBulletList(editor, blockType),
109
+ },
110
+ check: {
111
+ icon: <ListTodo className="size-4" />,
112
+ desc: "Checklist for tasks or to-dos.",
113
+ label: "check box",
114
+ func: () => formatCheckList(editor, blockType),
115
+ },
116
+ number: {
117
+ icon: <ListOrdered className="size-4" />,
118
+ desc: "Numbered list for ordered items.",
119
+ label: "Numbered list",
120
+ func: () => formatNumberedList(editor, blockType),
121
+ },
122
+ code: {
123
+ icon: <Braces className="size-4" />,
124
+ desc: "Code block for snippets.",
125
+ label: "Code",
126
+ func: () => formatCode(editor, blockType),
127
+ },
128
+ quote: {
129
+ icon: <Quote className="size-4" />,
130
+ desc: "Blockquote for quotations.",
131
+ label: "Blockquote",
132
+ func: () => formatQuote(editor, blockType),
133
+ },
134
+
135
+ }),
136
+ [editor]
137
+ );
138
+
139
+
140
+ const currentBlock = Blocks[blockType] || Blocks.paragraph;
141
+
142
+ return (
143
+ <DropDown
144
+ TriggerClassName={{...style,width:"100%"}}
145
+ disabled={disabled}
146
+ side={side}
147
+ sideOffset={sideOffset}
148
+ className="h-7 min-w-[29px] w-[29px] px-2 border-none cursor-pointer dark:bg-zinc-850 hover:bg-zinc-100 hover:text-zinc-900 dark:border-zinc-800"
149
+ TriggerLabel={
150
+ <>
151
+ {currentBlock.icon}
152
+ <span className="max-sm:hidden">{currentBlock.label}</span>
153
+ </>
154
+ }
155
+ ShowChevronsUpDown={ShowChevronsUpDown}
156
+ values={Object.values(Blocks)}
157
+ />
158
+ );
159
+ }
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import {
3
+ CODE_LANGUAGE_FRIENDLY_NAME_MAP,
4
+ getLanguageFriendlyName,
5
+ } from "@lexical/code";
6
+ import { DropDown } from ".";
7
+
8
+ function getCodeLanguageOptions(): [string, string][] {
9
+ const options: [string, string][] = [];
10
+ for (const [lang, friendlyName] of Object.entries(
11
+ CODE_LANGUAGE_FRIENDLY_NAME_MAP
12
+ )) {
13
+ options.push([lang, friendlyName]);
14
+ }
15
+ return options;
16
+ }
17
+
18
+ export default function CodeList({
19
+ onCodeLanguageSelect,
20
+ disabled = false,
21
+ codeLanguage,
22
+ }: {
23
+ onCodeLanguageSelect: (v: string) => void;
24
+ disabled?: boolean;
25
+ codeLanguage: string;
26
+ }) {
27
+ const CODE_LANGUAGE_OPTIONS = getCodeLanguageOptions();
28
+
29
+ const languageButtons = CODE_LANGUAGE_OPTIONS.map(([lang]) => ({
30
+ label: lang,
31
+ func: () => onCodeLanguageSelect(lang),
32
+ }));
33
+
34
+ return (
35
+ <DropDown
36
+ values={languageButtons}
37
+ disabled={disabled}
38
+ TriggerClassName={{ maxWidth: "200px", minWidth: "60px", width: "130px" }}
39
+ TriggerLabel={getLanguageFriendlyName(codeLanguage)}
40
+ />
41
+ );
42
+ }
@@ -0,0 +1,177 @@
1
+ import { $getSelection, LexicalEditor } from "lexical";
2
+ import React, { useCallback } from "react";
3
+ import { $patchStyleText } from "@lexical/selection";
4
+ import { useTheme } from "next-themes";
5
+ import {
6
+ Popover,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ } from "@/components/ui/popover";
10
+ import { Button } from "@/components/ui/button";
11
+ import { cn } from "@/lib/utils";
12
+ import { Separator } from "@/components/ui/separator";
13
+ import { BaselineIcon } from "lucide-react";
14
+
15
+ export default function Color({
16
+ disabled,
17
+ color,
18
+ bgColor,
19
+ editor,
20
+ isTable = false,
21
+ side = "bottom",
22
+ sideOffset = 0,
23
+ style,
24
+ }: {
25
+ disabled: boolean;
26
+ color?: string;
27
+ bgColor?: string;
28
+ editor: LexicalEditor;
29
+ isTable?: boolean;
30
+ style?: React.CSSProperties;
31
+ side?: "bottom" | "left" | "right" | "top";
32
+ sideOffset?: number;
33
+ }) {
34
+ const { theme } = useTheme();
35
+
36
+ const applyStyleText = useCallback(
37
+ (styles: Record<string, string>, skipHistoryStack?: boolean) => {
38
+ editor.update(
39
+ () => {
40
+ const selection = $getSelection();
41
+ if (selection !== null) {
42
+ $patchStyleText(selection, styles);
43
+ }
44
+ },
45
+ skipHistoryStack ? { tag: "historic" } : {}
46
+ );
47
+ },
48
+ [editor]
49
+ );
50
+ const onFontColorSelect = useCallback(
51
+ (value: string, skipHistoryStack: boolean) => {
52
+ applyStyleText({ color: value }, skipHistoryStack);
53
+ },
54
+ [applyStyleText]
55
+ );
56
+
57
+ const onBgColorSelect = useCallback(
58
+ (value: string, skipHistoryStack: boolean) => {
59
+ applyStyleText({ "background-color": value }, skipHistoryStack);
60
+ },
61
+ [applyStyleText]
62
+ );
63
+ const dark = React.useMemo(
64
+ () => ({
65
+ font: {
66
+ default: "white",
67
+ Gray: "var(--font-gray)",
68
+ Brown: "var(--font-brown)",
69
+ Orange: "var(--font-orange)",
70
+ Yellow: "var(--font-yellow)",
71
+ Green: "var(--font-green)",
72
+ Blue: "var(--font-blue)",
73
+ Purple: "var(--font-purple)",
74
+ Pink: "var(--font-pink)",
75
+ Red: "var(--font-red)",
76
+ },
77
+ background: {
78
+ default: "none",
79
+ Gray: "var(--background-gray)",
80
+ Brown: "var(--background-brown)",
81
+ Orange: "var(--background-orange)",
82
+ Yellow: "var(--background-yellow)",
83
+ Green: "var(--background-green)",
84
+ Blue: "var(--background-blue)",
85
+ Purple: "var(--background-purple)",
86
+ Pink: "var(--background-pink)",
87
+ Red: "var(--background-red)",
88
+ },
89
+ }),
90
+ []
91
+ );
92
+
93
+ const light = React.useMemo(
94
+ () => ({
95
+ font: {
96
+ Gray: "var(--font-gray)",
97
+ Brown: "var(--font-brown)",
98
+ Orange: "var(--font-orange)",
99
+ Yellow: "var(--font-yellow)",
100
+ Green: "var(--font-green)",
101
+ Blue: "var(--font-blue)",
102
+ Purple: "var(--font-purple)",
103
+ Pink: "var(--font-pink)",
104
+ Red: "var(--font-red)",
105
+ },
106
+ background: {
107
+ Gray: "var(--background-gray)",
108
+ Brown: "var(--background-brown)",
109
+ Orange: "var(--background-orange)",
110
+ Yellow: "var(--background-yellow)",
111
+ Green: "var(--background-green)",
112
+ Blue: "var(--background-blue)",
113
+ Purple: "var(--background-purple)",
114
+ Pink: "var(--background-pink)",
115
+ Red: "var(--background-red)",
116
+ },
117
+ }),
118
+ []
119
+ );
120
+
121
+ const themeColor = React.useMemo(
122
+ () => (theme === "dark" ? dark : light),
123
+ [theme, dark, light]
124
+ );
125
+
126
+
127
+ return (
128
+ <Popover>
129
+ <PopoverTrigger asChild disabled={disabled}>
130
+ {!isTable ? (
131
+ <Button
132
+ style={{
133
+ ...style,
134
+ color: theme === "dark" && color === "#000" ? "white" :
135
+ theme !== "dark" && color === "#fff" ? "black" : color,
136
+ }}
137
+ variant={"transparent"}
138
+ className="px-2 border-none cursor-pointer hover:dark-bg-accent hover:text-foreground"
139
+ size="Toolbar"
140
+ onMouseDown={(e) => e.preventDefault()}
141
+ >
142
+ <BaselineIcon />
143
+ </Button>
144
+ ) : (<></>)}
145
+ </PopoverTrigger>
146
+ <PopoverContent className="max-w-32 w-full p-2 z-[250]" side={side} sideOffset={sideOffset}>
147
+ <div className="flex flex-col">
148
+ {!isTable && (
149
+ <div className="flex flex-col gap-y-1">
150
+ <span className="text-[10px] cursor-default font-bold text-gray-500">
151
+ Font color
152
+ </span>
153
+ <div className="w-full flex flex-wrap gap-1">
154
+ {Object.entries(themeColor.font).map(
155
+ ([_, colorValue]) => (
156
+ <Button
157
+ key={colorValue}
158
+ type="button"
159
+ onClick={() => onFontColorSelect(colorValue, true)}
160
+ className={cn(
161
+ "w-[18px] p-0 h-[18px] rounded-[3px]",
162
+ colorValue === color && "ring-2 ring-offset-2"
163
+ )}
164
+ style={{ background: colorValue }}
165
+ onMouseDown={(e) => e.preventDefault()}
166
+ />
167
+ )
168
+ )}
169
+ </div>
170
+ <Separator className="my-2 h-[1px]" />
171
+ </div>
172
+ )}
173
+ </div>
174
+ </PopoverContent>
175
+ </Popover>
176
+ );
177
+ }