@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,138 @@
1
+ import * as React from "react";
2
+
3
+ import { LexicalEditor } from "lexical";
4
+ import { Minus, Plus } from "lucide-react";
5
+ import { Button } from "@/components/ui/button";
6
+ import { cn } from "@/lib/utils";
7
+ import { MAX_ALLOWED_FONT_SIZE, MIN_ALLOWED_FONT_SIZE } from "@/components/providers/ToolbarContext";
8
+ import { updateFontSize, updateFontSizeInSelection, UpdateFontSizeType } from "../../editor/utils/editorFormatting";
9
+ import { SHORTCUTS } from "../../editor/plugins/ShortcutsPlugin/shortcuts";
10
+ import { Input } from "@/components/ui/input";
11
+
12
+ export function parseAllowedFontSize(input: string): string {
13
+ const match = input.match(/^(\d+(?:\.\d+)?)px$/);
14
+ if (match) {
15
+ const n = Number(match[1]);
16
+ if (n >= MIN_ALLOWED_FONT_SIZE && n <= MAX_ALLOWED_FONT_SIZE) {
17
+ return input;
18
+ }
19
+ }
20
+ return "";
21
+ }
22
+
23
+ export default function FontSize({
24
+ selectionFontSize,
25
+ disabled,
26
+ editor,
27
+ className,
28
+ classNameContent
29
+ }: {
30
+ selectionFontSize: string;
31
+ disabled: boolean;
32
+ editor: LexicalEditor;
33
+ className?:string,
34
+ classNameContent?:string
35
+ }) {
36
+ const [inputValue, setInputValue] = React.useState<string>(selectionFontSize);
37
+ const [inputChangeFlag, setInputChangeFlag] = React.useState<boolean>(false);
38
+ const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
39
+ const inputValueNumber = Number(inputValue);
40
+
41
+ if (e.key === "Tab") {
42
+ return;
43
+ }
44
+ if (["e", "E", "+", "-"].includes(e.key) || isNaN(inputValueNumber)) {
45
+ e.preventDefault();
46
+ setInputValue("");
47
+ return;
48
+ }
49
+ setInputChangeFlag(true);
50
+ if (e.key === "Enter" || e.key === "Escape") {
51
+ e.preventDefault();
52
+
53
+ updateFontSizeByInputValue(inputValueNumber);
54
+ }
55
+ };
56
+ const handleInputBlur = () => {
57
+ if (inputValue !== "" && inputChangeFlag) {
58
+ const inputValueNumber = Number(inputValue);
59
+ updateFontSizeByInputValue(inputValueNumber);
60
+ }
61
+ };
62
+
63
+ const updateFontSizeByInputValue = (inputValueNumber: number) => {
64
+ let updatedFontSize = inputValueNumber;
65
+ if (inputValueNumber > MAX_ALLOWED_FONT_SIZE) {
66
+ updatedFontSize = MAX_ALLOWED_FONT_SIZE;
67
+ } else if (inputValueNumber < MIN_ALLOWED_FONT_SIZE) {
68
+ updatedFontSize = MIN_ALLOWED_FONT_SIZE;
69
+ }
70
+
71
+ setInputValue(String(updatedFontSize));
72
+ updateFontSizeInSelection(editor, String(updatedFontSize) + "px", null);
73
+ setInputChangeFlag(false);
74
+ };
75
+
76
+ React.useEffect(() => {
77
+ setInputValue(selectionFontSize);
78
+ }, [selectionFontSize]);
79
+ return (
80
+ <div className={cn("flex flex-row items-center gap-1",classNameContent)}>
81
+ <Button
82
+ type="button"
83
+ className={
84
+ cn("h-7 min-w-[29px] w-[29px] px-[6px] border-none cursor-pointer",className)
85
+ }
86
+ tip={`decrement ${SHORTCUTS.INCREASE_FONT_SIZE}`}
87
+ disabled={
88
+ disabled ||
89
+ (selectionFontSize !== "" &&
90
+ Number(inputValue) <= MIN_ALLOWED_FONT_SIZE)
91
+ }
92
+ variant={"outline"}
93
+ size={"Toolbar"}
94
+ onClick={() =>
95
+ updateFontSize(editor, UpdateFontSizeType.decrement, inputValue)
96
+ }
97
+ >
98
+ <Minus className="w-[15px] h-[15px]" />
99
+ </Button>
100
+
101
+ <Input
102
+ type="number"
103
+
104
+ value={inputValue}
105
+ disabled={disabled}
106
+ className={
107
+ cn("h-7 min-w-[29px] w-[29px] px-[6px] border-none cursor-text",className)
108
+ }
109
+ min={MIN_ALLOWED_FONT_SIZE}
110
+ max={MAX_ALLOWED_FONT_SIZE}
111
+ onChange={(e) => setInputValue(e.target.value)}
112
+ onKeyDown={handleKeyPress}
113
+ onBlur={handleInputBlur}
114
+ />
115
+ <Button
116
+ type="button"
117
+ tip={`increment ${SHORTCUTS.DECREASE_FONT_SIZE}`}
118
+
119
+ className={
120
+ cn("h-7 min-w-[29px] w-[29px] px-[6px] border-none cursor-pointer",className)
121
+ }
122
+
123
+ disabled={
124
+ disabled ||
125
+ (selectionFontSize !== "" &&
126
+ Number(inputValue) >= MAX_ALLOWED_FONT_SIZE)
127
+ }
128
+ variant={"outline"}
129
+ size={"Toolbar"}
130
+ onClick={() =>
131
+ updateFontSize(editor, UpdateFontSizeType.increment, inputValue)
132
+ }
133
+ >
134
+ <Plus className="w-4 h-4" />
135
+ </Button>
136
+ </div>
137
+ );
138
+ }
@@ -0,0 +1,155 @@
1
+ import { $getSelection, LexicalEditor } from "lexical";
2
+ import React, { CSSProperties, useCallback } from "react";
3
+ import { $patchStyleText } from "@lexical/selection";
4
+ import { DropDown } from ".";
5
+
6
+ interface FontOption {
7
+ label: string;
8
+ func: () => void;
9
+ style: CSSProperties;
10
+ }
11
+
12
+ export default function Font({
13
+ editor,
14
+ style,
15
+ disabled,
16
+ value,
17
+ sideOffset,
18
+ side,
19
+ ShowChevronsUpDown,
20
+ }: {
21
+ editor: LexicalEditor;
22
+ disabled: boolean;
23
+ value: string;
24
+ style?: React.CSSProperties;
25
+ ShowChevronsUpDown?: boolean;
26
+ side?: "top" | "right" | "bottom" | "left" | undefined;
27
+ sideOffset?: number;
28
+ }) {
29
+ const applyFont = useCallback(
30
+ (font: string) => {
31
+ editor.update(() => {
32
+ const selection = $getSelection();
33
+ if (selection !== null) {
34
+ $patchStyleText(selection, {
35
+ ["font-family"]: font,
36
+ });
37
+ }
38
+ });
39
+ },
40
+ [editor, style]
41
+ );
42
+
43
+ const FONT_FAMILY_OPTIONS: FontOption[] = [
44
+ {
45
+ label: "Arial",
46
+ func: () => applyFont("Arial"),
47
+ style: { fontFamily: "Arial" },
48
+ },
49
+ {
50
+ label: "Courier New",
51
+ func: () => applyFont("Courier New"),
52
+ style: { fontFamily: "Courier New" },
53
+ },
54
+ {
55
+ label: "Georgia",
56
+ func: () => applyFont("Georgia"),
57
+ style: { fontFamily: "Georgia" },
58
+ },
59
+ {
60
+ label: "Times New Roman",
61
+ func: () => applyFont("Times New Roman"),
62
+ style: { fontFamily: "Times New Roman" },
63
+ },
64
+ {
65
+ label: "Trebuchet MS",
66
+ func: () => applyFont("Trebuchet MS"),
67
+ style: { fontFamily: "Trebuchet MS" },
68
+ },
69
+ {
70
+ label: "Verdana",
71
+ func: () => applyFont("Verdana"),
72
+ style: { fontFamily: "Verdana" },
73
+ },
74
+ {
75
+ label: "Comic Sans MS",
76
+ func: () => applyFont("Comic Sans MS"),
77
+ style: { fontFamily: "Comic Sans MS" },
78
+ },
79
+ {
80
+ label: "Calibri",
81
+ func: () => applyFont("Calibri"),
82
+ style: { fontFamily: "Calibri" },
83
+ },
84
+ {
85
+ label: "Poppins",
86
+ func: () => applyFont("Poppins"),
87
+ style: { fontFamily: "Poppins" },
88
+ },
89
+ {
90
+ label: "Alegreya",
91
+ func: () => applyFont("Alegreya"),
92
+ style: { fontFamily: "Alegreya" },
93
+ },
94
+ {
95
+ label: "Bree Serif",
96
+ func: () => applyFont("Bree Serif"),
97
+ style: { fontFamily: "Bree Serif" },
98
+ },
99
+ {
100
+ label: "Cambria",
101
+ func: () => applyFont("Cambria"),
102
+ style: { fontFamily: "Cambria" },
103
+ },
104
+ {
105
+ label: "Impact",
106
+ func: () => applyFont("Impact"),
107
+ style: { fontFamily: "Impact" },
108
+ },
109
+ {
110
+ label: "Lexend",
111
+ func: () => applyFont("Lexend"),
112
+ style: { fontFamily: "Lexend" },
113
+ },
114
+ {
115
+ label: "Lobster",
116
+ func: () => applyFont("Lobster"),
117
+ style: { fontFamily: "Lobster" },
118
+ },
119
+ {
120
+ label: "Lora",
121
+ func: () => applyFont("Lora"),
122
+ style: { fontFamily: "Lora" },
123
+ },
124
+ {
125
+ label: "Permanent Marker",
126
+ func: () => applyFont("Permanent Marker"),
127
+ style: { fontFamily: "Permanent Marker" },
128
+ },
129
+ {
130
+ label: "Ultra",
131
+ func: () => applyFont("Ultra"),
132
+ style: { fontFamily: "Ultra" },
133
+ },
134
+ {
135
+ label: "Reenie Beanie",
136
+ func: () => applyFont("Reenie Beanie"),
137
+ style: { fontFamily: "Reenie Beanie" },
138
+ },
139
+ ];
140
+
141
+
142
+ return (
143
+ <DropDown
144
+ ShowChevronsUpDown={ShowChevronsUpDown}
145
+ side={side}
146
+ sideOffset={sideOffset}
147
+ className="h-7 min-w-[29px] w-[29px] px-2 border-none cursor-pointer hover:bg-zinc-100 hover:text-zinc-900"
148
+ PopoverContentClassName={{ minWidth: "80px", width: "150px" }}
149
+ TriggerClassName={{ ...style, width: "100%" }}
150
+ disabled={disabled}
151
+ TriggerLabel={value}
152
+ values={FONT_FAMILY_OPTIONS}
153
+ />
154
+ );
155
+ }
@@ -0,0 +1,122 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Check, ChevronsUpDown } from "lucide-react";
5
+ import { Button } from "@/components/ui/button";
6
+ import {
7
+ Command,
8
+ CommandEmpty,
9
+ CommandGroup,
10
+ CommandInput,
11
+ CommandItem,
12
+ CommandList,
13
+ CommandShortcut,
14
+ } from "@/components/ui/command";
15
+ import {
16
+ Popover,
17
+ PopoverContent,
18
+ PopoverTrigger,
19
+ } from "@/components/ui/popover";
20
+ import { cn } from "@/lib/utils";
21
+
22
+ interface values {
23
+ icon?: React.ReactNode;
24
+ label: string;
25
+ desc?: string;
26
+ func?: () => void;
27
+ style?: React.CSSProperties;
28
+ isSelected?: boolean;
29
+ shortcuts?: string;
30
+
31
+ }
32
+ interface Props {
33
+ TriggerLabel: React.ReactNode | string;
34
+ TriggerClassName?: React.CSSProperties;
35
+ className?: string;
36
+ PopoverContentClassName?: React.CSSProperties;
37
+ values: values[];
38
+ disabled: boolean;
39
+ triggerVariants?:"ghost" | "default" |"outline" |"link" | "secondary" | "destructive"
40
+ ShowChevronsUpDown?:boolean
41
+ side?: "top" | "right" | "bottom" | "left" | undefined
42
+ sideOffset?:number
43
+ }
44
+
45
+ export function DropDown({
46
+ className,
47
+ TriggerLabel,
48
+ TriggerClassName,
49
+ values,
50
+ disabled,
51
+ PopoverContentClassName,
52
+ triggerVariants="outline",
53
+ ShowChevronsUpDown=true,
54
+ side="bottom",
55
+ sideOffset=5
56
+ }: Props) {
57
+ const [value, setValue] = React.useState("");
58
+
59
+ return (
60
+ <Popover modal={false}>
61
+ <PopoverTrigger disabled={disabled} asChild>
62
+ <Button
63
+ variant={triggerVariants}
64
+ role="combobox"
65
+ size={"Toolbar"}
66
+ style={TriggerClassName}
67
+ className={className}
68
+ >
69
+ <div className="flex flex-row justify-center gap-x-3 items-center">
70
+ {TriggerLabel}
71
+ </div>
72
+ {ShowChevronsUpDown && <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />}
73
+ </Button>
74
+ </PopoverTrigger>
75
+ <PopoverContent
76
+ side={side}
77
+ sideOffset={sideOffset}
78
+ style={PopoverContentClassName!}
79
+ className="w-[200px] p-0 dropdown-portal"
80
+ >
81
+ <Command>
82
+ <CommandInput placeholder="Search..." />
83
+ <CommandList>
84
+ <CommandEmpty>No found.</CommandEmpty>
85
+ <CommandGroup>
86
+ {values.map((framework) => (
87
+ <CommandItem
88
+ key={framework.label}
89
+ value={framework.label}
90
+ style={framework.style}
91
+ className={cn(
92
+ "cursor-pointer",
93
+ value === framework.label && "bg-gray-300/10",
94
+ )}
95
+ onSelect={(currentValue) => {
96
+ setValue(currentValue === value ? "" : currentValue);
97
+ if (framework.func) framework?.func();
98
+ }}
99
+ >
100
+ <div className="flex w-full flex-row items-center justify-between">
101
+ <div className="flex items-center gap-4 flex-row">
102
+ {framework.icon}
103
+ <div className="flex flex-col">
104
+ {framework.label}
105
+ <span className="text-sm text-muted-foreground">
106
+ {framework.desc}
107
+ </span>
108
+ </div>
109
+ </div>
110
+ {framework.shortcuts && (
111
+ <CommandShortcut>{framework.shortcuts}</CommandShortcut>
112
+ )}
113
+ </div>
114
+ </CommandItem>
115
+ ))}
116
+ </CommandGroup>
117
+ </CommandList>
118
+ </Command>
119
+ </PopoverContent>
120
+ </Popover>
121
+ );
122
+ }
@@ -0,0 +1,213 @@
1
+ import { LexicalEditor } from "lexical";
2
+ import React, { useMemo, lazy, Suspense } from "react";
3
+ import useModal from "../models/use-model";
4
+ import { AlertCircle, Columns2, Columns3, Columns4, DraftingCompassIcon, Figma, FlipHorizontal2, Image, ImagePlay, PencilRuler, Plus, SquareChevronRight, SquarePenIcon, Table, Twitter, Youtube } from "lucide-react";
5
+ import { INSERT_HORIZONTAL_RULE_COMMAND } from "@lexical/react/LexicalHorizontalRuleNode";
6
+ import { DropDown } from ".";
7
+ import { INSERT_IMAGE_COMMAND, InsertImagePayload } from "../../editor/plugins/ImagesPlugin";
8
+ import { Skeleton } from "@/components/ui/skeleton";
9
+ import { INSERT_LAYOUT_COMMAND } from "../../editor/plugins/LayoutPlugin";
10
+ import { INSERT_COLLAPSIBLE_COMMAND } from "../../editor/plugins/CollapsiblePlugin";
11
+ import { AutoEmbedDialog, FigmaEmbedConfig, TwitterEmbedConfig, YoutubeEmbedConfig } from "../../editor/plugins/AutoEmbedPlugin";
12
+ import { INSERT_HINT_COMMAND } from "../../editor/nodes/Hint";
13
+ import { INSERT_EXCALIDRAW_COMMAND } from "../../editor/plugins/ExcalidrawPlugin";
14
+
15
+ const InsertImageDialog = lazy(() => import("@/components/ui/models/insert-image").then(module => ({ default: module.InsertImageDialog })));
16
+ const InsertGif = lazy(() => import("../models/insert-gif"));
17
+ const InsertTableBody = lazy(() => import("@/components/ui/models/insert-table").then(module => ({ default: module.InsertTable })));
18
+ const InsertPoll = lazy(() =>
19
+ import("@/components/ui/models/insert-poll").then(module => ({ default: module.InsertPoll }))
20
+ );
21
+
22
+ interface Items {
23
+ label: string;
24
+ icon: React.ReactNode;
25
+ func: () => void;
26
+ shortcuts?: string;
27
+ }
28
+
29
+ export default function InsertNode({
30
+ disabled,
31
+ editor,
32
+ }: {
33
+ disabled: boolean;
34
+ editor: LexicalEditor;
35
+ }) {
36
+ const [model, showModal] = useModal();
37
+ const insertGifOnClick = (payload: InsertImagePayload) => {
38
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
39
+ };
40
+
41
+ const items: Items[] = useMemo(
42
+ () => [
43
+ {
44
+ label: "Horizontal Rule",
45
+ icon: <FlipHorizontal2 className="w-4 h-4" />,
46
+ func: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined),
47
+ },
48
+ {
49
+ label: "Image",
50
+ icon: <Image className="size-4" />,
51
+ func: () => {
52
+ showModal(
53
+ "Insert Image",
54
+ "Please select an image to upload.",
55
+ (onClose) => (
56
+ <Suspense fallback={<Skeleton className="mx-2 w-[350px] h-[350px]" />}>
57
+ <InsertImageDialog activeEditor={editor} onClose={onClose} />
58
+ </Suspense>
59
+ ),
60
+ true
61
+ );
62
+ },
63
+ },
64
+ {
65
+ label: "GIF",
66
+ icon: <ImagePlay className="w-4 h-4" />,
67
+ func: () => {
68
+ showModal(
69
+ "Insert GIF",
70
+ "Please select a GIF to upload.",
71
+ (onClose) => (
72
+ <Suspense fallback={<Skeleton className="mx-2 w-[400px] h-[400px]" />}>
73
+ <InsertGif insertGifOnClick={insertGifOnClick} onClose={onClose} />
74
+ </Suspense>
75
+ ),
76
+ true
77
+ );
78
+ },
79
+ },
80
+ {
81
+ label: "Table",
82
+ icon: <Table className="w-4 h-4" />,
83
+ func: () => {
84
+ showModal(
85
+ "Insert Table",
86
+ "Please configure your table.",
87
+ (onClose) => (
88
+ <Suspense fallback={<Skeleton className="mx-2 w-[400px] h-[100px]" />}>
89
+ <InsertTableBody activeEditor={editor} onClose={onClose} />
90
+ </Suspense>
91
+ ),
92
+ true
93
+ );
94
+ },
95
+ },
96
+ {
97
+ label: "ExcaliDraw",
98
+ icon: <DraftingCompassIcon className="w-4 h-4" />,
99
+ func: () => {
100
+ editor.dispatchCommand(INSERT_EXCALIDRAW_COMMAND, undefined);
101
+ },
102
+ },
103
+ {
104
+ label: "Poll",
105
+ icon: <SquarePenIcon className="w-4 h-4" />,
106
+ func: () => {
107
+ showModal(
108
+ "Create Poll",
109
+ "Please type your question.",
110
+ (onClose) => (
111
+ <Suspense fallback={<Skeleton className="mx-2 w-[400px] h-[100px]" />}>
112
+ <InsertPoll activeEditor={editor} onClose={onClose} />
113
+ </Suspense>
114
+ ),
115
+ true
116
+ );
117
+ },
118
+ },
119
+ {
120
+ label: "2 columns (equal width)",
121
+ icon: <Columns2 className="w-4 h-4" />,
122
+ func: () => {
123
+ editor.dispatchCommand(INSERT_LAYOUT_COMMAND, "1fr 1fr");
124
+ },
125
+ },
126
+ {
127
+ label: "3 columns (equal width)",
128
+ icon: <Columns3 className="w-4 h-4" />,
129
+ func: () => {
130
+ editor.dispatchCommand(INSERT_LAYOUT_COMMAND, "1fr 1fr 1fr");
131
+ },
132
+ },
133
+ {
134
+ label: "4 columns (equal width)",
135
+ icon: <Columns4 className="w-4 h-4" />,
136
+ func: () => {
137
+ editor.dispatchCommand(INSERT_LAYOUT_COMMAND, "1fr 1fr 1fr 1fr");
138
+ },
139
+ },
140
+ {
141
+ label: "2 columns (25% - 75%)",
142
+ icon: <Columns2 className="w-4 h-4" />,
143
+ func: () => {
144
+ editor.dispatchCommand(INSERT_LAYOUT_COMMAND, "1fr 3fr");
145
+ },
146
+ },
147
+ {
148
+ label: "Collapsible container",
149
+ icon: <SquareChevronRight className="w-4 h-4" />,
150
+ func: () => {
151
+ editor.dispatchCommand(INSERT_COLLAPSIBLE_COMMAND, undefined);
152
+ },
153
+ },
154
+ {
155
+ label: "Twitter",
156
+ icon: <Twitter className="w-4 h-4" />,
157
+ func: () => {
158
+
159
+ showModal("Twitter tweet", "Insert a URL to embed a live preview. Works with Twitter, Google Drive, Vimeo, and more.", (onClose) => (
160
+ <AutoEmbedDialog embedConfig={TwitterEmbedConfig} onClose={onClose} />
161
+ ), true);
162
+ },
163
+ },
164
+ {
165
+ label: "Youtube",
166
+ icon: <Youtube />,
167
+ func: () => {
168
+
169
+ showModal("Youtube", "Insert a URL to embed a live preview. Works with YouTube, Google Drive, Vimeo, and more.", (onClose) => (
170
+ <AutoEmbedDialog embedConfig={YoutubeEmbedConfig} onClose={onClose} />
171
+ ), true);
172
+ },
173
+ },
174
+ {
175
+ label: "Figma",
176
+ icon: <Figma />,
177
+ func: () => {
178
+
179
+ showModal("Figma", "Insert a URL to embed a live preview. Works with Figma.", (onClose) => (
180
+ <AutoEmbedDialog embedConfig={FigmaEmbedConfig} onClose={onClose} />
181
+ ), true);
182
+ },
183
+ },
184
+ {
185
+ label: "Hint",
186
+ icon: <AlertCircle />,
187
+ func: () => {
188
+ editor.dispatchCommand(INSERT_HINT_COMMAND, 'info')
189
+ }
190
+ }
191
+
192
+ ],
193
+ [editor, showModal]
194
+ );
195
+
196
+ return (
197
+ <>
198
+ <DropDown
199
+ values={items}
200
+ TriggerClassName={{ width: "115px", border: "none" }}
201
+ className="cursor-pointer"
202
+ TriggerLabel={
203
+ <>
204
+ <Plus />
205
+ <span>Insert</span>
206
+ </>
207
+ }
208
+ disabled={disabled}
209
+ />
210
+ {model}
211
+ </>
212
+ );
213
+ }