@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
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Notiq
2
+
3
+ A modern, extensible note-taking and document editor built with Next.js, TypeScript, Tailwind CSS, and Lexical. Features include rich text editing, image and media embeds, equations, polls, and more.
4
+
5
+ ## Features
6
+
7
+ - ⚡️ Fast, responsive editor powered by Lexical
8
+ - 🖼️ Image, inline image, and media embeds (YouTube, Twitter, Figma, GIFs)
9
+ - 🧮 Equation and math support (KaTeX)
10
+ - 📊 Polls, tables, and code blocks
11
+ - 🎨 Customizable themes with Tailwind CSS
12
+ - 🗂️ Modular plugin architecture
13
+ - 🌐 Next.js app with API routes
14
+
15
+ ## Getting Started
16
+
17
+ ### Prerequisites
18
+
19
+ - Node.js (v18+ recommended)
20
+ - pnpm (or npm/yarn)
21
+
22
+ ### Installation
23
+
24
+ ```bash
25
+ pnpm install
26
+ ```
27
+
28
+ ### Development
29
+
30
+ ```bash
31
+ pnpm dev
32
+ ```
33
+
34
+ Open [http://localhost:3000](http://localhost:3000) in your browser.
35
+
36
+ ### Build
37
+
38
+ ```bash
39
+ pnpm build
40
+ ```
41
+
42
+ ## Project Structure
43
+
44
+ - `src/app/` — Next.js app routes and layout
45
+ - `src/components/editor/` — Editor core, plugins, nodes, and UI
46
+ - `src/components/ui/` — Reusable UI components
47
+ - `src/lib/` — Utility libraries (EdgeStore, Pinecone, etc.)
48
+ - `public/` — Static assets
49
+
50
+ ## Editor Plugins & Nodes
51
+
52
+ - **Plugins:** Toolbar, Floating Toolbar, AutoEmbed, Equations, Excalidraw, Inline Images, Polls, Tables, Code Actions, Slash Commands, etc.
53
+ - **Nodes:** ImageNode, InlineImageNode, EquationNode, ExcalidrawNode, PollNode, etc.
54
+
55
+ ## Customization
56
+
57
+ - Tailwind CSS config: `tailwind.config.ts`
58
+ - ESLint config: `eslint.config.mjs`
59
+ - Editor themes: `src/components/editor/themes/`
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork the repo
64
+ 2. Create your feature branch (`git checkout -b feature/foo`)
65
+ 3. Commit your changes (`git commit -am 'Add feature'`)
66
+ 4. Push to the branch (`git push origin feature/foo`)
67
+ 5. Create a Pull Request
68
+
69
+ ## License
70
+
71
+ MIT
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.ts",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
@@ -0,0 +1,16 @@
1
+ import { dirname } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { FlatCompat } from "@eslint/eslintrc";
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ const compat = new FlatCompat({
9
+ baseDirectory: __dirname,
10
+ });
11
+
12
+ const eslintConfig = [
13
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
14
+ ];
15
+
16
+ export default eslintConfig;
package/next.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ typescript: {
5
+ ignoreBuildErrors: true,
6
+ },
7
+ eslint: {
8
+ ignoreDuringBuilds: true,
9
+ },
10
+ };
11
+
12
+ export default nextConfig;
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@collabchron/notiq",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "description": "Notion AI + Figma + Excalidraw + 3D + Code Editor + Markdown Editor + Real-time Collaboration + Embeds + More = Notiq",
6
+ "author": "Chinonso Chikelue (fluantiX) <chinonsoneft@gmail.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/chinonsochikelue/notiq.git"
11
+ },
12
+ "scripts": {
13
+ "dev": "next dev --turbopack",
14
+ "build": "next build",
15
+ "start": "next start",
16
+ "lint": "next lint"
17
+ },
18
+ "dependencies": {
19
+ "@ai-sdk/openai": "^2.0.30",
20
+ "@ai-sdk/react": "^2.0.44",
21
+ "@edgestore/react": "^0.5.4",
22
+ "@edgestore/server": "^0.5.4",
23
+ "@excalidraw/excalidraw": "^0.18.0",
24
+ "@lexical/clipboard": "^0.35.0",
25
+ "@lexical/code": "^0.35.0",
26
+ "@lexical/code-shiki": "^0.35.0",
27
+ "@lexical/devtools-core": "^0.35.0",
28
+ "@lexical/dragon": "^0.35.0",
29
+ "@lexical/eslint-plugin": "^0.35.0",
30
+ "@lexical/file": "^0.35.0",
31
+ "@lexical/hashtag": "^0.35.0",
32
+ "@lexical/headless": "^0.35.0",
33
+ "@lexical/history": "^0.35.0",
34
+ "@lexical/html": "^0.35.0",
35
+ "@lexical/link": "^0.35.0",
36
+ "@lexical/list": "^0.35.0",
37
+ "@lexical/mark": "^0.35.0",
38
+ "@lexical/markdown": "^0.35.0",
39
+ "@lexical/offset": "^0.35.0",
40
+ "@lexical/overflow": "^0.35.0",
41
+ "@lexical/react": "^0.35.0",
42
+ "@lexical/rich-text": "^0.35.0",
43
+ "@lexical/selection": "^0.35.0",
44
+ "@lexical/table": "^0.35.0",
45
+ "@lexical/text": "^0.35.0",
46
+ "@lexical/utils": "^0.35.0",
47
+ "@lexical/yjs": "^0.35.0",
48
+ "@mantine/hooks": "^8.3.1",
49
+ "@pinecone-database/pinecone": "^6.1.2",
50
+ "@radix-ui/react-checkbox": "^1.3.3",
51
+ "@radix-ui/react-dialog": "^1.1.15",
52
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
53
+ "@radix-ui/react-hover-card": "^1.1.15",
54
+ "@radix-ui/react-popover": "^1.1.15",
55
+ "@radix-ui/react-progress": "^1.1.7",
56
+ "@radix-ui/react-scroll-area": "^1.2.10",
57
+ "@radix-ui/react-separator": "^1.1.7",
58
+ "@radix-ui/react-slot": "^1.2.3",
59
+ "@radix-ui/react-toggle": "^1.1.10",
60
+ "@radix-ui/react-tooltip": "^1.2.8",
61
+ "@react-three/fiber": "^9.3.0",
62
+ "@tailwindcss/postcss": "^4.1.13",
63
+ "@tanstack/react-query": "^5.87.4",
64
+ "@uiw/react-color": "^2.8.0",
65
+ "ai": "^5.0.44",
66
+ "class-variance-authority": "^0.7.1",
67
+ "clsx": "^2.1.1",
68
+ "cmdk": "^1.1.1",
69
+ "framer-motion": "^12.23.12",
70
+ "katex": "^0.16.22",
71
+ "lexical": "^0.35.0",
72
+ "lodash-es": "^4.17.21",
73
+ "lucide-react": "^0.544.0",
74
+ "motion": "^12.23.12",
75
+ "next-themes": "^0.4.6",
76
+ "openai": "^5.20.2",
77
+ "react": "^19.1.1",
78
+ "react-dom": "^19.1.1",
79
+ "react-error-boundary": "^6.0.0",
80
+ "react-markdown": "^10.1.0",
81
+ "redis": "^5.8.2",
82
+ "sonner": "^2.0.7",
83
+ "tailwind-merge": "^3.3.1",
84
+ "tailwindcss-animate": "^1.0.7",
85
+ "three": "^0.180.0",
86
+ "tw-animate-css": "^1.3.8",
87
+ "zod": "^4.1.8",
88
+ "zustand": "^5.0.8"
89
+ },
90
+ "devDependencies": {
91
+ "@eslint/eslintrc": "^3.3.1",
92
+ "@tailwindcss/typography": "^0.5.16",
93
+ "@tanstack/eslint-plugin-query": "^5.86.0",
94
+ "@types/lodash-es": "^4.17.12",
95
+ "@types/node": "^24.4.0",
96
+ "@types/react": "^19.1.13",
97
+ "@types/react-dom": "^19.1.9",
98
+ "@types/three": "^0.180.0",
99
+ "autoprefixer": "^10.4.21",
100
+ "eslint": "^9.35.0",
101
+ "eslint-config-next": "15.5.3",
102
+ "next": "15.5.3",
103
+ "postcss": "^8.5.6",
104
+ "prettier": "3.6.2",
105
+ "tailwindcss": "^4.1.13",
106
+ "typescript": "^5.9.2"
107
+ }
108
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1,10 @@
1
+ <svg
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ fill="none"
4
+ viewBox="0 0 24 24"
5
+ stroke="currentColor"
6
+ strokeWidth="2"
7
+ className="w-6 h-6"
8
+ >
9
+ <path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
10
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,2 @@
1
+ "use server"
2
+
@@ -0,0 +1,175 @@
1
+ import {
2
+ AIAction,
3
+ autoCompleteInstruction,
4
+ FixSpellingGrammarInstruction,
5
+ improveMesgInstruction,
6
+ MakeLongInstruction,
7
+ MakeShortInstruction,
8
+ SimplifyLanguageInstruction,
9
+ StepsInstruction,
10
+ } from "@/components/editor/hooks/instructions-messages";
11
+ import { ExtractedBlock } from "@/components/editor/utils/extract-data";
12
+ import { openai } from "@ai-sdk/openai";
13
+ import { CoreMessage, streamText } from "ai";
14
+ import { createClient } from "redis";
15
+
16
+
17
+
18
+ const client = createClient({
19
+ username: "default",
20
+ password: process.env.REDIS_PASSWORD,
21
+ socket: {
22
+ host: process.env.REDIS_URL,
23
+ port: parseInt(process.env.REDIS_PORT!),
24
+ },
25
+ });
26
+
27
+ client.connect().catch((err) => console.error("Redis connection error:", err));
28
+
29
+ export const maxDuration = 30;
30
+ const MAX_TOKEN = 60000;
31
+
32
+ function estimateTokenCount(text: string): number {
33
+ return Math.ceil(text.length / 4);
34
+ }
35
+
36
+
37
+ function computeHash(text: string): string {
38
+ let hash = 0;
39
+ for (let i = 0; i < text.length; i++) {
40
+ hash = (hash << 5) - hash + text.charCodeAt(i);
41
+ hash |= 0; // Convert to 32bit integer
42
+ }
43
+ return hash.toString();
44
+ }
45
+
46
+ function flattenBlocks(blocks: ExtractedBlock[]): string {
47
+ return blocks
48
+ .map((block) => {
49
+ let content = block.content;
50
+ if (block.children) {
51
+ content += `\n${flattenBlocks(block.children)}`;
52
+ }
53
+ return content;
54
+ })
55
+ .join("\n\n");
56
+ }
57
+
58
+ /**
59
+ * Asynchronously process the raw context JSON string.
60
+ * It checks Redis for a cached version (valid for 30 seconds),
61
+ * and if not found, processes the JSON into flat text, applies smart truncation,
62
+ * stores it in Redis, and returns the processed text.
63
+ */
64
+
65
+
66
+ async function processContext(rawContext: string): Promise<string> {
67
+ const currentHash = computeHash(rawContext);
68
+ const cacheKey = `context:${currentHash}`;
69
+
70
+ try {
71
+ const cached = await client.get(cacheKey);
72
+ if (cached) {
73
+ const cachedData = JSON.parse(cached);
74
+ if (Date.now() - cachedData.timestamp < 30000) {
75
+ console.log("Returning cached context from Redis");
76
+ return cachedData.processedText;
77
+ }
78
+ }
79
+ } catch (error) {
80
+ console.error("Redis error while fetching cache:", error);
81
+ }
82
+
83
+ try {
84
+ const blocks: ExtractedBlock[] = JSON.parse(rawContext);
85
+ let processedText = flattenBlocks(blocks);
86
+
87
+ // If processed text is too long, preserve important sections and truncate
88
+ if (estimateTokenCount(processedText) > MAX_TOKEN) {
89
+ const importantSections = blocks
90
+ .filter((b) =>
91
+ [
92
+ "heading",
93
+ "Collapsible",
94
+ "Table",
95
+ "text",
96
+ "paragraph",
97
+ "list",
98
+ "quote",
99
+ "code",
100
+ "CollapsibleContent",
101
+ "Collapsible",
102
+ "list-item",
103
+ ].includes(b.blockType)
104
+ )
105
+ .map((b) => b.content + (b.children ? `\n${flattenBlocks(b.children)}` : ""))
106
+ .join("\n\n");
107
+
108
+ processedText = `${importantSections}\n\n${
109
+ blocks
110
+ .filter((b) => !["heading", "quote", "Table","paragraph"].includes(b.blockType))
111
+ .map((b) => b.content)
112
+ .join("\n")
113
+ }`.slice(0, MAX_TOKEN * 4);
114
+ }
115
+
116
+ // Store in Redis with an expiration of 30 seconds
117
+ const cacheData = JSON.stringify({ processedText, timestamp: Date.now() });
118
+ try {
119
+ await client.set(cacheKey, cacheData, { EX: maxDuration });
120
+ } catch (error) {
121
+ console.error("Redis error while setting cache:", error);
122
+ }
123
+
124
+ return processedText;
125
+ } catch (error) {
126
+ console.error("Context processing failed:", error);
127
+ return rawContext.slice(0, MAX_TOKEN * 4);
128
+ }
129
+ }
130
+
131
+ function buildSystemMessage(action: AIAction, context: string): string {
132
+ const baseInstructions: any = {
133
+ autoComplete: autoCompleteInstruction,
134
+ FixSpellingGrammar: FixSpellingGrammarInstruction,
135
+ ImproveWriting: improveMesgInstruction,
136
+ MakeLongInstruction: MakeLongInstruction,
137
+ MakeShortInstruction: MakeShortInstruction,
138
+ SimplifyLanguage: SimplifyLanguageInstruction,
139
+ Steps: StepsInstruction,
140
+ ChatWithSelectedString: `You're an editor assistant. Use all the provided context from the document to answer the user's question directly in concise Markdown format. Answer ONLY the question without including additional suggestions or extra context. If the blog does not contain the necessary data, you may supplement your answer with external information.
141
+ Context:
142
+ ${context}`,
143
+ GenerateAgain: `Improve the response based on the full content.
144
+ Context:
145
+ ${context}
146
+ Consider: 1. Phrasing 2. Details 3. Alternatives`,
147
+ default: "You are a professional writing assistant",
148
+ };
149
+
150
+ return baseInstructions[action] || baseInstructions.default!;
151
+ }
152
+
153
+ export async function POST(req: Request) {
154
+ const { prompt: userQuestion, action, context } = await req.json();
155
+ const processedContext = context ? await processContext(context) : "";
156
+ const systemMessage = buildSystemMessage(action, processedContext);
157
+ const messages: CoreMessage[] = [
158
+ { role: "system", content: systemMessage },
159
+ { role: "user", content: userQuestion },
160
+ ];
161
+ try {
162
+ const result = streamText({
163
+ model: openai("gpt-4o"),
164
+ messages,
165
+ temperature: 0.2,
166
+ });
167
+
168
+ return result.toDataStreamResponse();
169
+ } catch (error) {
170
+ console.error("Streaming failed:", error);
171
+ return new Response("Error generating response", { status: 500 });
172
+ }
173
+
174
+
175
+ }
@@ -0,0 +1,28 @@
1
+ import { initEdgeStore } from '@edgestore/server';
2
+ import { createEdgeStoreNextHandler } from '@edgestore/server/adapters/next/app';
3
+
4
+ // Initialize the EdgeStore
5
+ const es = initEdgeStore.create();
6
+
7
+ /**
8
+ * This is the main router for the Edge Store buckets.
9
+ * We're configuring a file bucket that allows all file types and limits size to 1GB.
10
+ */
11
+ const edgeStoreRouter = es.router({
12
+ publicFiles: es.fileBucket({
13
+ // Set file size limit to 1 GB (1 GB = 1,073,741,824 bytes)
14
+ maxSize: 1_073_741_824,
15
+ }),
16
+ });
17
+
18
+ // Create the handler for the GET and POST routes
19
+ const handler = createEdgeStoreNextHandler({
20
+ router: edgeStoreRouter,
21
+ });
22
+
23
+ export { handler as GET, handler as POST };
24
+
25
+ /**
26
+ * This type is used to create the type-safe client for the frontend.
27
+ */
28
+ export type EdgeStoreRouter = typeof edgeStoreRouter;
Binary file
@@ -0,0 +1,205 @@
1
+ /* @import url('https://fonts.googleapis.com/css2?family=Monomakh&display=swap'); */
2
+
3
+
4
+ @tailwind base;
5
+ @tailwind components;
6
+ @tailwind utilities;
7
+ @import "tailwindcss";
8
+ @plugin "@tailwindcss/typography";
9
+
10
+ body {
11
+ font-family: Arial, Helvetica, sans-serif;
12
+ }
13
+
14
+ input[type="number"]::-webkit-inner-spin-button,
15
+ input[type="number"]::-webkit-outer-spin-button {
16
+ -webkit-appearance: none;
17
+ margin: 0;
18
+ }
19
+
20
+ .select-none {
21
+ user-select: none;
22
+ }
23
+
24
+ #toolbar {
25
+ scrollbar-width: none;
26
+ /* Firefox */
27
+ }
28
+
29
+ #toolbar::-webkit-scrollbar {
30
+ display: none;
31
+ /* Chrome, Safari, Edge */
32
+ }
33
+
34
+ .code {
35
+ scrollbar-width: none;
36
+ /* Firefox */
37
+ }
38
+
39
+ .code::-webkit-scrollbar {
40
+ display: none;
41
+ /* Chrome, Safari, Edge */
42
+ }
43
+
44
+ @layer base {
45
+ :root {
46
+ --font-gray: #9B9A97;
47
+ --font-brown: #64473A;
48
+ --font-orange: #D9730D;
49
+ --font-yellow: #DFAB01;
50
+ --font-green: #0F7B6C;
51
+ --font-blue: #0B6E99;
52
+ --font-purple: #6940A5;
53
+ --font-pink: #AD1A72;
54
+ --font-red: #E03E3E;
55
+
56
+
57
+ --background-gray: #EBECED;
58
+ --background-brown: #E9E5E3;
59
+ --background-orange: #FAEBDD;
60
+ --background-yellow: #FBF3DB;
61
+ --background-green: #DDEDEA;
62
+ --background-blue: #DDEDEA;
63
+ --background-purple: #EAE4F2;
64
+ --background-pink: #F4DFEB;
65
+ --background-red: #FBE4E4;
66
+
67
+ --background: 0 0% 100%;
68
+ --foreground: 0 0% 3.9%;
69
+ --card: 0 0% 100%;
70
+ --card-foreground: 0 0% 3.9%;
71
+ --popover: 0 0% 100%;
72
+ --popover-foreground: 0 0% 3.9%;
73
+ --primary: 0 0% 9%;
74
+ --primary-foreground: 0 0% 98%;
75
+ --secondary: 0 0% 96.1%;
76
+ --secondary-foreground: 0 0% 9%;
77
+ --muted: 0 0% 96.1%;
78
+ --muted-foreground: 0 0% 45.1%;
79
+ --accent: 0 0% 96.1%;
80
+ --accent-foreground: 0 0% 9%;
81
+ --destructive: 0 84.2% 60.2%;
82
+ --destructive-foreground: 0 0% 98%;
83
+ --border: 0 0% 89.8%;
84
+ --input: 0 0% 89.8%;
85
+ --ring: 0 0% 3.9%;
86
+ --chart-1: 12 76% 61%;
87
+ --chart-2: 173 58% 39%;
88
+ --chart-3: 197 37% 24%;
89
+ --chart-4: 43 74% 66%;
90
+ --chart-5: 27 87% 67%;
91
+ --radius: 0.5rem;
92
+ }
93
+
94
+ .dark {
95
+
96
+ --font-gray: #9B9A97;
97
+ --font-brown: #937264;
98
+ --font-orange: #FFA344;
99
+ --font-yellow: #FFDC49;
100
+ --font-green: #4DAB9A;
101
+ --font-blue: #529CCA;
102
+ --font-purple: #9A6DD7;
103
+ --font-pink: #E255A1;
104
+ --font-red: #FF7369;
105
+
106
+
107
+ --background-gray: #454B4E;
108
+ --background-brown: #434040;
109
+ --background-orange: #594A3A;
110
+ --background-yellow: #59563B;
111
+ --background-green: #354C4B;
112
+ --background-blue: #364954;
113
+ --background-purple: #443F57;
114
+ --background-pink: #533B4C;
115
+ --background-red: #594141;
116
+
117
+ --background: 0 0% 3.9%;
118
+ --foreground: 0 0% 98%;
119
+ --card: 0 0% 3.9%;
120
+ --card-foreground: 0 0% 98%;
121
+ --popover: 0 0% 3.9%;
122
+ --popover-foreground: 0 0% 98%;
123
+ --primary: 0 0% 98%;
124
+ --primary-foreground: 0 0% 9%;
125
+ --secondary: 0 0% 14.9%;
126
+ --secondary-foreground: 0 0% 98%;
127
+ --muted: 0 0% 14.9%;
128
+ --muted-foreground: 0 0% 63.9%;
129
+ --accent: 0 0% 14.9%;
130
+ --accent-foreground: 0 0% 98%;
131
+ --destructive: 0 62.8% 30.6%;
132
+ --destructive-foreground: 0 0% 98%;
133
+ --border: 0 0% 14.9%;
134
+ --input: 0 0% 14.9%;
135
+ --ring: 0 0% 83.1%;
136
+ --chart-1: 220 70% 50%;
137
+ --chart-2: 160 60% 45%;
138
+ --chart-3: 30 80% 55%;
139
+ --chart-4: 280 65% 60%;
140
+ --chart-5: 340 75% 55%;
141
+ }
142
+ }
143
+
144
+ .editor-shell .editor-image .image-edit-button {
145
+ border: 1px solid rgba(0, 0, 0, 0.3);
146
+ border-radius: 5px;
147
+ background-image: url(/src/images/icons/pencil-fill.svg);
148
+ background-size: 16px;
149
+ background-position: center;
150
+ background-repeat: no-repeat;
151
+ width: 35px;
152
+ height: 35px;
153
+ vertical-align: -0.25em;
154
+ position: absolute;
155
+ right: 4px;
156
+ top: 4px;
157
+ cursor: pointer;
158
+ user-select: none;
159
+ }
160
+
161
+ .editor-shell .editor-image .image-edit-button:hover {
162
+ background-color: rgba(60, 132, 244, 0.1);
163
+ }
164
+
165
+ .editor-shell .inline-editor-image .image-edit-button {
166
+ display: block;
167
+ position: absolute;
168
+ top: 12px;
169
+ right: 12px;
170
+ padding: 6px 8px;
171
+ margin: 0 auto;
172
+ border: 1px solid rgba(255, 255, 255, 0.3);
173
+ border-radius: 5px;
174
+ background-color: rgba(0, 0, 0, 0.5);
175
+ min-width: 60px;
176
+ color: #fff;
177
+ cursor: pointer;
178
+ user-select: none;
179
+ }
180
+
181
+ .editor-shell .inline-editor-image .image-edit-button:hover {
182
+ background-color: rgba(60, 132, 244, 0.5);
183
+ }
184
+
185
+
186
+ /* @layer base {
187
+ * {
188
+ @apply border-border;
189
+ }
190
+ body {
191
+ @apply bg-background text-foreground;
192
+ }
193
+ } */
194
+
195
+
196
+
197
+ /* @layer base {
198
+ * {
199
+ @apply border border-border outline-ring/50;
200
+ }
201
+
202
+ body {
203
+ @apply bg-background text-foreground;
204
+ }
205
+ } */