aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/web/app/(canvas)/canvas/page.tsx81
-rw-r--r--apps/web/app/(dash)/menu.tsx8
-rw-r--r--apps/web/app/(editor)/ai.md43
-rw-r--r--apps/web/app/(editor)/components/aigenerate.tsx186
-rw-r--r--apps/web/app/(editor)/components/editorcommands.tsx85
-rw-r--r--apps/web/app/(editor)/components/extensions.ts141
-rw-r--r--apps/web/app/(editor)/components/image-upload.ts50
-rw-r--r--apps/web/app/(editor)/components/selectors/bgcolor-selector.tsx107
-rw-r--r--apps/web/app/(editor)/components/selectors/color-selector.tsx111
-rw-r--r--apps/web/app/(editor)/components/selectors/link-selector.tsx95
-rw-r--r--apps/web/app/(editor)/components/selectors/node-selector.tsx126
-rw-r--r--apps/web/app/(editor)/components/selectors/text-buttons.tsx63
-rw-r--r--apps/web/app/(editor)/components/slash-command.tsx163
-rw-r--r--apps/web/app/(editor)/components/topbar.tsx68
-rw-r--r--apps/web/app/(editor)/components/ui/asksvg.tsx12
-rw-r--r--apps/web/app/(editor)/components/ui/autocompletesvg.tsx12
-rw-r--r--apps/web/app/(editor)/components/ui/crazy-spinner.tsx11
-rw-r--r--apps/web/app/(editor)/components/ui/magic.tsx8
-rw-r--r--apps/web/app/(editor)/components/ui/rewritesvg.tsx11
-rw-r--r--apps/web/app/(editor)/components/ui/translatesvg.tsx12
-rw-r--r--apps/web/app/(editor)/editor.tsx55
-rw-r--r--apps/web/app/(editor)/editor/page.tsx8
-rw-r--r--apps/web/app/(editor)/layout.tsx12
-rw-r--r--apps/web/app/(editor)/lib/content.ts231
-rw-r--r--apps/web/app/(editor)/lib/debouncedsave.ts20
-rw-r--r--apps/web/app/(editor)/lib/editorprops.ts16
-rw-r--r--apps/web/app/(editor)/lib/use-local-storage.ts27
-rw-r--r--apps/web/app/(editor)/styles/globals.css168
-rw-r--r--apps/web/app/(editor)/styles/prosemirror.css203
-rw-r--r--packages/ui/components/canvas/draggableComponent.tsx72
-rw-r--r--packages/ui/icons/autocomplete.svg15
-rw-r--r--packages/ui/icons/block.svg15
-rw-r--r--packages/ui/icons/canvas.svg3
-rw-r--r--packages/ui/icons/drag.svg (renamed from apps/web/app/(canvas)/svg.tsx)85
-rw-r--r--packages/ui/icons/index.ts16
-rw-r--r--packages/ui/icons/link.svg15
-rw-r--r--packages/ui/icons/settings.svg14
37 files changed, 183 insertions, 2185 deletions
diff --git a/apps/web/app/(canvas)/canvas/page.tsx b/apps/web/app/(canvas)/canvas/page.tsx
index c24e2c73..ea3cee1b 100644
--- a/apps/web/app/(canvas)/canvas/page.tsx
+++ b/apps/web/app/(canvas)/canvas/page.tsx
@@ -1,17 +1,12 @@
"use client";
-// import Canvas from "./_components/canvas";
import { Canvas } from "../canvas";
import React, { useState } from "react";
-// import ReactTextareaAutosize from "react-textarea-autosize";
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
-import {
- DragSvg,
- SettingsSvg,
- LinkSvg,
- ThreeDBlock,
- TextLoadingSvg,
-} from "../svg";
+import { SettingsIcon, DragIcon } from "@repo/ui/icons";
+import DraggableComponentsContainer from "@repo/ui/components/canvas/draggableComponent";
+import { AutocompleteIcon, blockIcon } from "@repo/ui/icons";
+import Image from "next/image";
function page() {
const [value, setValue] = useState("");
@@ -45,7 +40,7 @@ function page() {
>
<div className="flex items-center justify-between bg-[#2C3439] px-4 py-2 text-lg font-medium text-[#989EA4]">
Change Filters
- <SettingsSvg />
+ <Image src={SettingsIcon} alt="setting-icon" />
</div>
<div className="px-3 py-5">
<input
@@ -59,47 +54,7 @@ function page() {
/>
</div>
{visible ? (
- <div className="flex flex-col gap-10">
- <div className="flex gap-4 px-3 text-[#989EA4]">
- <TextLoadingSvg />
- <h1>
- Nvidia will most likely create monopoly in software
- industry as they are already largest player in GPU
- hardware by 20...
- </h1>
- </div>
- <div className="flex gap-4 px-3 text-[#989EA4]">
- <ThreeDBlock />
- <div className="flex flex-col gap-2">
- <div>
- <h1 className="line-clamp-3">
- Nvidia currently dominates the GPU hardware market,
- with a market share over 97%. This has led some to
- argue...
- </h1>
- </div>
- <p className="line-clamp-1 text-[#369DFD]">
- From space: GPU GOATS
- </p>
- </div>
- </div>
- <div className="flex gap-4 px-3 text-[#989EA4]">
- <LinkSvg />
- <div className="flex flex-col gap-2">
- <div>
- <h1 className="line-clamp-3">
- Nvidia currently dominates the GPU hardware market,
- with a market share over 97%. This has led some to
- argue...
- </h1>
- </div>
- <p className="line-clamp-1 text-[#369DFD]">
- Page url:
- https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia
- </p>
- </div>
- </div>
- </div>
+ <SidePanel />
) : (
<h1 className="text-center py-10 text-xl">Need more space to show!</h1>
)}
@@ -112,7 +67,7 @@ function page() {
<div
className={`rounded-lg bg-[#2F363B] ${!fullScreen && "px-1"} transition-all py-2`}
>
- <DragSvg />
+ <Image src={DragIcon} alt="drag-icon" />
</div>
{/* </div> */}
</PanelResizeHandle>
@@ -129,4 +84,26 @@ function page() {
);
}
+const content= [
+ {
+ content: "Nvidia currently dominates the GPU hardware market, with a market share over 97%. This has led some to argue...",
+ icon: AutocompleteIcon,
+ iconAlt: "Autocomplete",
+ extraInfo: "Page Url: https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia",
+ },
+ {
+ content: "Nvidia currently dominates the GPU hardware market, with a market share over 97%. This has led some to argue...",
+ icon: blockIcon,
+ iconAlt: "Autocomplete",
+ extraInfo: "Page Url: https://www.cnbc.com/2024/05/23/nvidia-keeps-hitting-records-can-investors-still-buy-the-stock.html?&qsearchterm=nvidia",
+ },
+
+]
+
+function SidePanel(){
+ return (
+ <DraggableComponentsContainer content={content} />
+ )
+}
+
export default page;
diff --git a/apps/web/app/(dash)/menu.tsx b/apps/web/app/(dash)/menu.tsx
index 035e8e3f..f40c22e4 100644
--- a/apps/web/app/(dash)/menu.tsx
+++ b/apps/web/app/(dash)/menu.tsx
@@ -1,6 +1,6 @@
import React from "react";
import Image from "next/image";
-import { MemoriesIcon, ExploreIcon, HistoryIcon } from "@repo/ui/icons";
+import { MemoriesIcon, ExploreIcon, HistoryIcon, CanvasIcon } from "@repo/ui/icons";
import Link from "next/link";
function Menu() {
@@ -16,9 +16,9 @@ function Menu() {
url: "/explore",
},
{
- icon: HistoryIcon,
- text: "History",
- url: "/history",
+ icon: CanvasIcon,
+ text: "Canvas",
+ url: "/canvas",
},
];
diff --git a/apps/web/app/(editor)/ai.md b/apps/web/app/(editor)/ai.md
deleted file mode 100644
index 1528a7bd..00000000
--- a/apps/web/app/(editor)/ai.md
+++ /dev/null
@@ -1,43 +0,0 @@
-## to access the editor
-```
-import { useEditor } from "novel";
-const editor = useEditor()
-```
-
-## to get previous text
-```
-import { getPrevText } from "novel/utils";
-const pos = editor.state.selection.from;
-const text = getPrevText(editor, pos);
-```
-
-## selected content into markdown format
-```
-const slice = editor.state.selection.content();
-const text = editor.storage.markdown.serializer.serialize(slice.content);
-```
-
-## replace Selection
-```
-const selection = editor.view.state.selection;
-editor.chain().focus()
- .insertContentAt(
- {
- from: selection.from,
- to: selection.to,
- },
- completion,
- )
- .run();
-```
-
-
-## to insert after
-```
-const selection = editor.view.state.selection;
-editor
- .chain()
- .focus()
- .insertContentAt(selection.to + 1, completion)
- .run();
-```
diff --git a/apps/web/app/(editor)/components/aigenerate.tsx b/apps/web/app/(editor)/components/aigenerate.tsx
deleted file mode 100644
index de9b2a3f..00000000
--- a/apps/web/app/(editor)/components/aigenerate.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-import React, { useEffect, useRef, useState } from "react";
-import Magic from "./ui/magic";
-import CrazySpinner from "./ui/crazy-spinner";
-import Asksvg from "./ui/asksvg";
-import Rewritesvg from "./ui/rewritesvg";
-import Translatesvg from "./ui/translatesvg";
-import Autocompletesvg from "./ui/autocompletesvg";
-import { motion, AnimatePresence } from "framer-motion";
-import type { Editor } from "@tiptap/core";
-import { useEditor } from "novel";
-import { NodeSelection } from "prosemirror-state";
-
-function Aigenerate() {
- const [visible, setVisible] = useState(false);
- const [generating, setGenerating] = useState(false);
-
- const { editor } = useEditor();
- const setGeneratingfn = (v: boolean) => setGenerating(v);
-
- return (
- <div className="z-[60] bg-[#171B1F] fixed left-0 bottom-0 w-screen flex justify-center pt-4 pb-6">
- <motion.div
- animate={{
- y: visible ? "30%" : 0,
- }}
- onClick={() => {
- setVisible(!visible);
- if (visible) editor?.commands.unsetAIHighlight();
- }}
- className={`select-none relative z-[70] rounded-3xl text-[#369DFD] bg-[#21303D] px-4 py-3 text-sm flex gap-2 items-center font-medium whitespace-nowrap overflow-hidden transition-[width] w-[6.25rem] ${visible && "w-[10.55rem]"}`}
- >
- <Magic className="h-4 w-4 shrink-0 translate-y-[5%]" />
- {visible && generating ? (
- <>
- Generating <CrazySpinner />
- </>
- ) : visible ? (
- <>Press Commands</>
- ) : (
- <>Ask AI</>
- )}
- </motion.div>
- <motion.div
- initial={{
- opacity: 0,
- y: 20,
- }}
- animate={{
- y: visible ? "-60%" : 20,
- opacity: visible ? 1 : 0,
- }}
- whileHover={{ scale: 1.05 }}
- transition={{
- duration: 0.2,
- }}
- className="absolute z-50 top-0"
- >
- {/* TODO: handle Editor not initalised, maybe with a loading state. */}
- <ToolBar setGeneratingfn={setGeneratingfn} editor={editor} />
- <div className="h-8 w-18rem bg-blue-600 blur-[16rem]" />
- </motion.div>
- </div>
- );
-}
-
-export default Aigenerate;
-
-const options = [
- <>
- <Translatesvg />
- Translate
- </>,
- <>
- <Rewritesvg />
- Change Tone
- </>,
- <>
- <Asksvg />
- Ask Gemini
- </>,
- <>
- <Autocompletesvg />
- Auto Complete
- </>,
-];
-
-function ToolBar({
- editor,
- setGeneratingfn,
-}: {
- editor: Editor;
- setGeneratingfn: (v: boolean) => void;
-}) {
- const [index, setIndex] = useState(0);
-
- return (
- <div
- className={
- "select-none flex gap-6 bg-[#1F2428] active:scale-[.98] transition rounded-3xl px-1 py-1 text-sm font-medium"
- }
- >
- {options.map((item, idx) => (
- <div
- key={idx}
- className="relative block h-full w-full px-3 py-2 text-[#989EA4]"
- onMouseEnter={() => setIndex(idx)}
- >
- <AnimatePresence>
- {index === idx && (
- <motion.span
- onClick={() =>
- AigenerateContent({ idx, editor, setGeneratingfn })
- }
- className="absolute select-none inset-0 block h-full w-full rounded-xl bg-[#33393D]"
- layoutId="hoverBackground"
- initial={{ opacity: 0 }}
- animate={{
- opacity: 1,
- transition: { duration: 0.15 },
- }}
- exit={{
- opacity: 0,
- transition: { duration: 0.15, delay: 0.2 },
- }}
- />
- )}
- </AnimatePresence>
- <div className="select-none flex items-center whitespace-nowrap gap-3 relative z-[60] pointer-events-none">
- {item}
- </div>
- </div>
- ))}
- </div>
- );
-}
-
-async function AigenerateContent({
- idx,
- editor,
- setGeneratingfn,
-}: {
- idx: number;
- editor: Editor;
- setGeneratingfn: (v: boolean) => void;
-}) {
- setGeneratingfn(true);
-
- const { from, to } = editor.view.state.selection;
-
- const slice = editor.state.selection.content();
- const text = editor.storage.markdown.serializer.serialize(slice.content);
-
- const request = [
- "Translate to hindi written in english, do not write anything else",
- "change tone, improve the way be more formal",
- "ask, answer the question",
- "continue this, minimum 80 characters, do not repeat just continue don't use ... to denote start",
- ];
-
- const resp = await fetch("/api/editorai", {
- method: "POST",
- body: JSON.stringify({
- context: text,
- request: request[idx],
- }),
- });
-
- const reader = resp.body?.getReader();
- let done = false;
- let position = to;
- while (!done && reader) {
- const { value, done: d } = await reader.read();
- done = d;
-
- const decoded = new TextDecoder().decode(value);
- console.log(decoded);
- editor
- .chain()
- .focus()
- .insertContentAt(position + 1, decoded)
- .run();
- position += decoded.length;
- }
-
- setGeneratingfn(false);
-}
diff --git a/apps/web/app/(editor)/components/editorcommands.tsx b/apps/web/app/(editor)/components/editorcommands.tsx
deleted file mode 100644
index 8e80df46..00000000
--- a/apps/web/app/(editor)/components/editorcommands.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import React, { useState } from "react";
-import {
- EditorBubble,
- EditorCommand,
- EditorCommandEmpty,
- EditorCommandItem,
- EditorCommandList,
-} from "novel";
-import { suggestionItems } from "./slash-command";
-import { Separator } from "@repo/ui/shadcn/separator";
-import { NodeSelector } from "./selectors/node-selector";
-import { LinkSelector } from "./selectors/link-selector";
-import { TextButtons } from "./selectors/text-buttons";
-import { ColorSelector } from "./selectors/color-selector";
-import { BgColorSelector } from "./selectors/bgcolor-selector";
-
-function EditorCommands() {
- return (
- <>
- <SlashCommand />
- <PopupMenu />
- </>
- );
-}
-
-function SlashCommand() {
- return (
- <EditorCommand className="z-50 h-auto max-h-[330px] min-w-[20rem] overflow-y-auto rounded-lg bg-[#1F2428] shadow-md transition-all">
- <EditorCommandEmpty className="px-4 text-lg text-muted-foreground">
- No results
- </EditorCommandEmpty>
- <EditorCommandList>
- {suggestionItems.map((item) => (
- <EditorCommandItem
- value={item.title}
- onCommand={(val) => item.command(val)}
- className="flex w-full items-center space-x-4 rounded-md px-4 py-3 text-left text-sm hover:bg-accent aria-selected:bg-[#21303D] group/command"
- key={item.title}
- >
- <div className="flex h-11 w-11 items-center justify-center rounded-md bg-[#2D343A] group-aria-selected/command:bg-[#369DFD33] stroke-[#989EA4] group-aria-selected/command:stroke-[#369DFD]">
- {item.icon}
- </div>
- <div>
- <p className="font-medium text-[#FFFFFF] group-aria-selected/command:text-[#369DFD]">
- {item.title}
- </p>
- <p className="text-xs text-muted-foreground group-aria-selected/command:text-[#369DFDB2]">
- {item.description}
- </p>
- </div>
- </EditorCommandItem>
- ))}
- </EditorCommandList>
- </EditorCommand>
- );
-}
-
-function PopupMenu() {
- const [openNode, setOpenNode] = useState(false);
- const [openColor, setOpenColor] = useState(false);
- const [openBgColor, setOpenBgColor] = useState(false);
- const [openLink, setOpenLink] = useState(false);
- const [openMenu, setOpenMenu] = useState(false);
- return (
- <EditorBubble
- tippyOptions={{
- placement: openMenu ? "bottom-start" : "top",
- }}
- className="flex w-fit max-w-[90vw] overflow-hidden bg-[#1F2428] text-white rounded "
- >
- <Separator orientation="vertical" />
- <NodeSelector open={openNode} onOpenChange={setOpenNode} />
- <Separator orientation="vertical" />
- <LinkSelector open={openLink} onOpenChange={setOpenLink} />
- <Separator orientation="vertical" />
- <TextButtons />
- <Separator orientation="vertical" />
- <ColorSelector open={openColor} onOpenChange={setOpenColor} />
- <Separator orientation="vertical" />
- <BgColorSelector open={openBgColor} onOpenChange={setOpenBgColor} />
- </EditorBubble>
- );
-}
-
-export default EditorCommands;
diff --git a/apps/web/app/(editor)/components/extensions.ts b/apps/web/app/(editor)/components/extensions.ts
deleted file mode 100644
index 0c581154..00000000
--- a/apps/web/app/(editor)/components/extensions.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import {
- AIHighlight,
- CharacterCount,
- CodeBlockLowlight,
- GlobalDragHandle,
- HorizontalRule,
- Placeholder,
- StarterKit,
- TaskItem,
- TaskList,
- TiptapImage,
- TiptapLink,
- UpdatedImage,
- Youtube,
-} from "novel/extensions";
-import { UploadImagesPlugin } from "novel/plugins";
-
-import { cx } from "class-variance-authority";
-import { common, createLowlight } from "lowlight";
-
-//TODO I am using cx here to get tailwind autocomplete working, idk if someone else can write a regex to just capture the class key in objects
-const aiHighlight = AIHighlight;
-//You can overwrite the placeholder with your own configuration
-const placeholder = Placeholder;
-const tiptapLink = TiptapLink.configure({
- HTMLAttributes: {
- class: cx(
- "text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer",
- ),
- },
-});
-
-const tiptapImage = TiptapImage.extend({
- addProseMirrorPlugins() {
- return [
- UploadImagesPlugin({
- imageClass: cx("opacity-40 rounded-lg border border-stone-200"),
- }),
- ];
- },
-}).configure({
- allowBase64: true,
- HTMLAttributes: {
- class: cx("rounded-lg border border-muted"),
- },
-});
-
-const updatedImage = UpdatedImage.configure({
- HTMLAttributes: {
- class: cx("rounded-lg border border-muted"),
- },
-});
-
-const taskList = TaskList.configure({
- HTMLAttributes: {
- class: cx("not-prose pl-2 "),
- },
-});
-const taskItem = TaskItem.configure({
- HTMLAttributes: {
- class: cx("flex gap-2 items-start my-4"),
- },
- nested: true,
-});
-
-const horizontalRule = HorizontalRule.configure({
- HTMLAttributes: {
- class: cx("mt-4 mb-6 border-t border-muted-foreground"),
- },
-});
-
-const starterKit = StarterKit.configure({
- bulletList: {
- HTMLAttributes: {
- class: cx("list-disc list-outside leading-3 -mt-2"),
- },
- },
- orderedList: {
- HTMLAttributes: {
- class: cx("list-decimal list-outside leading-3 -mt-2"),
- },
- },
- listItem: {
- HTMLAttributes: {
- class: cx("leading-normal -mb-2"),
- },
- },
- blockquote: {
- HTMLAttributes: {
- class: cx("border-l-4 border-primary"),
- },
- },
- codeBlock: {
- HTMLAttributes: {
- class: cx("rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium"),
- },
- },
- code: {
- HTMLAttributes: {
- class: cx("rounded-md bg-muted px-1.5 py-1 font-mono font-medium"),
- spellcheck: "false",
- },
- },
- horizontalRule: false,
- dropcursor: {
- color: "#DBEAFE",
- width: 4,
- },
- gapcursor: false,
-});
-
-const codeBlockLowlight = CodeBlockLowlight.configure({
- // configure lowlight: common / all / use highlightJS in case there is a need to specify certain language grammars only
- // common: covers 37 language grammars which should be good enough in most cases
- lowlight: createLowlight(common),
-});
-
-const youtube = Youtube.configure({
- HTMLAttributes: {
- class: cx("rounded-lg border border-muted"),
- },
- inline: false,
-});
-
-const characterCount = CharacterCount.configure();
-
-export const defaultExtensions = [
- starterKit,
- placeholder,
- tiptapLink,
- tiptapImage,
- updatedImage,
- taskList,
- taskItem,
- horizontalRule,
- aiHighlight,
- codeBlockLowlight,
- youtube,
- characterCount,
- GlobalDragHandle,
-];
diff --git a/apps/web/app/(editor)/components/image-upload.ts b/apps/web/app/(editor)/components/image-upload.ts
deleted file mode 100644
index d10be168..00000000
--- a/apps/web/app/(editor)/components/image-upload.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { createImageUpload } from "novel/plugins";
-import { toast } from "sonner";
-
-const onUpload = (file: File) => {
- //Endpoint: to upload the image
- const promise = fetch("", {
- method: "POST",
- body: file,
- });
-
- return new Promise((resolve, reject) => {
- toast.promise(
- promise.then(async (res) => {
- if (res.status === 200) {
- const { url } = (await res.json()) as { url: string };
- const image = new Image();
- image.src = url;
- image.onload = () => {
- resolve(url);
- };
- } else {
- throw new Error("Error uploading image. Please try again.");
- }
- }),
- {
- loading: "Uploading image...",
- success: "Image uploaded successfully.",
- error: (e) => {
- reject(e);
- return e.message;
- },
- },
- );
- });
-};
-
-export const uploadFn = createImageUpload({
- onUpload,
- validateFn: (file) => {
- if (!file.type.includes("image/")) {
- toast.error("File type not supported.");
- return false;
- }
- if (file.size / 1024 / 1024 > 20) {
- toast.error("File size too big (max 20MB).");
- return false;
- }
- return true;
- },
-});
diff --git a/apps/web/app/(editor)/components/selectors/bgcolor-selector.tsx b/apps/web/app/(editor)/components/selectors/bgcolor-selector.tsx
deleted file mode 100644
index 77da0f03..00000000
--- a/apps/web/app/(editor)/components/selectors/bgcolor-selector.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import { Check, ChevronDown } from "lucide-react";
-import { EditorBubbleItem, useEditor } from "novel";
-
-import { Button } from "@repo/ui/shadcn/button";
-import { Popover, PopoverContent, PopoverTrigger } from "@repo/ui/shadcn/popover";
-export interface BubbleColorMenuItem {
- name: string;
- color: string;
-}
-
-const HIGHLIGHT_COLORS: BubbleColorMenuItem[] = [
- {
- name: "Default",
- color: "var(--novel-highlight-default)",
- },
- {
- name: "Purple",
- color: "var(--novel-highlight-purple)",
- },
- {
- name: "Red",
- color: "var(--novel-highlight-red)",
- },
- {
- name: "Yellow",
- color: "var(--novel-highlight-yellow)",
- },
- {
- name: "Blue",
- color: "var(--novel-highlight-blue)",
- },
- {
- name: "Green",
- color: "var(--novel-highlight-green)",
- },
- {
- name: "Orange",
- color: "var(--novel-highlight-orange)",
- },
- {
- name: "Pink",
- color: "var(--novel-highlight-pink)",
- },
- {
- name: "Gray",
- color: "var(--novel-highlight-gray)",
- },
-];
-
-interface ColorSelectorProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
-}
-
-export const BgColorSelector = ({ open, onOpenChange }: ColorSelectorProps) => {
- const { editor } = useEditor();
-
- if (!editor) return null;
-
- const activeHighlightItem = HIGHLIGHT_COLORS.find(({ color }) => editor.isActive("highlight", { color }));
-
- return (
- <Popover modal={true} open={open} onOpenChange={onOpenChange}>
- <PopoverTrigger asChild>
- <Button size="sm" className="gap-2 rounded-none" variant="ghost">
- <span
- className="rounded-sm px-1"
- style={{
- backgroundColor: activeHighlightItem?.color,
- }}
- >
- A
- </span>
- <ChevronDown className="h-4 w-4" />
- </Button>
- </PopoverTrigger>
-
- <PopoverContent
- sideOffset={5}
- className="my-1 border-none bg-[#1F2428] flex max-h-80 w-48 flex-col overflow-hidden overflow-y-auto rounded border p-1 shadow-xl "
- align="start"
- >
- <div>
- <div className="my-1 px-2 text-sm font-semibold text-muted-foreground">Background</div>
- {HIGHLIGHT_COLORS.map(({ name, color }) => (
- <EditorBubbleItem
- key={name}
- onSelect={() => {
- editor.commands.unsetHighlight();
- name !== "Default" && editor.commands.setHighlight({ color });
- }}
- className="flex cursor-pointer items-center justify-between px-2 py-1 text-sm hover:bg-[#21303D]"
- >
- <div className="flex items-center gap-2">
- <div className="rounded-sm px-2 py-px font-medium" style={{ backgroundColor: color }}>
- A
- </div>
- <span>{name}</span>
- </div>
- {editor.isActive("highlight", { color }) && <Check className="h-4 w-4" />}
- </EditorBubbleItem>
- ))}
- </div>
- </PopoverContent>
- </Popover>
- );
-};
diff --git a/apps/web/app/(editor)/components/selectors/color-selector.tsx b/apps/web/app/(editor)/components/selectors/color-selector.tsx
deleted file mode 100644
index 557c4255..00000000
--- a/apps/web/app/(editor)/components/selectors/color-selector.tsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import { Check, ChevronDown } from "lucide-react";
-import { EditorBubbleItem, useEditor } from "novel";
-
-import { Button } from "@repo/ui/shadcn/button";
-import { Popover, PopoverContent, PopoverTrigger } from "@repo/ui/shadcn/popover";
-export interface BubbleColorMenuItem {
- name: string;
- color: string;
-}
-
-const TEXT_COLORS: BubbleColorMenuItem[] = [
- {
- name: "Default",
- color: "var(--novel-black)",
- },
- {
- name: "Purple",
- color: "#9333EA",
- },
- {
- name: "Red",
- color: "#E00000",
- },
- {
- name: "Yellow",
- color: "#EAB308",
- },
- {
- name: "Blue",
- color: "#2563EB",
- },
- {
- name: "Green",
- color: "#008A00",
- },
- {
- name: "Orange",
- color: "#FFA500",
- },
- {
- name: "Pink",
- color: "#BA4081",
- },
- {
- name: "Gray",
- color: "#A8A29E",
- },
-];
-
-
-interface ColorSelectorProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
-}
-
-export const ColorSelector = ({ open, onOpenChange }: ColorSelectorProps) => {
- const { editor } = useEditor();
-
- if (!editor) return null;
- const activeColorItem = TEXT_COLORS.find(({ color }) => editor.isActive("textStyle", { color }));
-
- return (
- <Popover modal={true} open={open} onOpenChange={onOpenChange}>
- <PopoverTrigger asChild>
- <Button size="sm" className="gap-2 rounded-none" variant="ghost">
- <span
- className="rounded-sm px-1"
- style={{
- color: activeColorItem?.color
- }}
- >
- A
- </span>
- <ChevronDown className="h-4 w-4" />
- </Button>
- </PopoverTrigger>
-
- <PopoverContent
- sideOffset={5}
- className="my-1 border-none bg-[#1F2428] flex max-h-80 w-48 flex-col overflow-hidden overflow-y-auto rounded border p-1 shadow-xl "
- align="start"
- >
- <div className="flex flex-col">
- <div className="my-1 px-2 text-sm font-semibold text-muted-foreground">Color</div>
- {TEXT_COLORS.map(({ name, color }) => (
- <EditorBubbleItem
- key={name}
- onSelect={() => {
- editor.commands.unsetColor();
- name !== "Default" &&
- editor
- .chain()
- .focus()
- .setColor(color || "")
- .run();
- }}
- className="flex cursor-pointer items-center justify-between px-2 py-1 text-sm hover:bg-accent"
- >
- <div className="flex items-center gap-2">
- <div className="rounded-sm px-2 py-px font-medium" style={{ color }}>
- A
- </div>
- <span>{name}</span>
- </div>
- </EditorBubbleItem>
- ))}
- </div>
- </PopoverContent>
- </Popover>
- );
-};
diff --git a/apps/web/app/(editor)/components/selectors/link-selector.tsx b/apps/web/app/(editor)/components/selectors/link-selector.tsx
deleted file mode 100644
index 3dc28266..00000000
--- a/apps/web/app/(editor)/components/selectors/link-selector.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { Button } from "@repo/ui/shadcn/button";
-import { Popover, PopoverContent, PopoverTrigger } from "@repo/ui/shadcn/popover";
-import { cn } from "@repo/ui/lib/utils";
-import { Check, Trash } from "lucide-react";
-import { useEditor } from "novel";
-import { useEffect, useRef } from "react";
-
-export function isValidUrl(url: string) {
- try {
- new URL(url);
- return true;
- } catch (_e) {
- return false;
- }
-}
-export function getUrlFromString(str: string) {
- if (isValidUrl(str)) return str;
- try {
- if (str.includes(".") && !str.includes(" ")) {
- return new URL(`https://${str}`).toString();
- }
- } catch (_e) {
- return null;
- }
-}
-interface LinkSelectorProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
-}
-
-export const LinkSelector = ({ open, onOpenChange }: LinkSelectorProps) => {
- const inputRef = useRef<HTMLInputElement>(null);
- const { editor } = useEditor();
-
- // Autofocus on input by default
- useEffect(() => {
- inputRef.current?.focus();
- });
- if (!editor) return null;
-
- return (
- <Popover modal={true} open={open} onOpenChange={onOpenChange}>
- <PopoverTrigger asChild>
- <Button size="sm" variant="ghost" className="gap-2 rounded-none border-none">
- <p className="text-base">↗</p>
- <p
- className={cn("underline decoration-stone-400 underline-offset-4", {
- "text-blue-500": editor.isActive("link"),
- })}
- >
- Link
- </p>
- </Button>
- </PopoverTrigger>
- <PopoverContent align="start" className="w-60 p-0" sideOffset={10}>
- <form
- onSubmit={(e) => {
- const target = e.currentTarget as HTMLFormElement;
- e.preventDefault();
- const input = target[0] as HTMLInputElement;
- const url = getUrlFromString(input.value);
- url && editor.chain().focus().setLink({ href: url }).run();
- }}
- className="flex p-1 "
- >
- <input
- ref={inputRef}
- type="text"
- placeholder="Paste a link"
- className="flex-1 bg-background p-1 text-sm outline-none"
- defaultValue={editor.getAttributes("link").href || ""}
- />
- {editor.getAttributes("link").href ? (
- <Button
- size="icon"
- variant="outline"
- type="button"
- className="flex h-8 items-center rounded-sm p-1 text-red-600 transition-all hover:bg-red-100 dark:hover:bg-red-800"
- onClick={() => {
- editor.chain().focus().unsetLink().run();
- inputRef.current.value = "";
- }}
- >
- <Trash className="h-4 w-4" />
- </Button>
- ) : (
- <Button size="icon" className="h-8">
- <Check className="h-4 w-4" />
- </Button>
- )}
- </form>
- </PopoverContent>
- </Popover>
- );
-};
diff --git a/apps/web/app/(editor)/components/selectors/node-selector.tsx b/apps/web/app/(editor)/components/selectors/node-selector.tsx
deleted file mode 100644
index c6092b68..00000000
--- a/apps/web/app/(editor)/components/selectors/node-selector.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import {
- Check,
- CheckSquare,
- ChevronDown,
- Code,
- Heading1,
- Heading2,
- Heading3,
- ListOrdered,
- type LucideIcon,
- TextIcon,
- TextQuote,
-} from "lucide-react";
-import { EditorBubbleItem, useEditor } from "novel";
-
-import { Button } from "@repo/ui/shadcn/button";
-import { Popover, PopoverContent, PopoverTrigger } from "@repo/ui/shadcn/popover";
-
-export type SelectorItem = {
- name: string;
- icon: LucideIcon;
- command: (editor: ReturnType<typeof useEditor>["editor"]) => void;
- isActive: (editor: ReturnType<typeof useEditor>["editor"]) => boolean;
-};
-
-const items: SelectorItem[] = [
- {
- name: "Text",
- icon: TextIcon,
- command: (editor) => editor.chain().focus().clearNodes().run(),
- // I feel like there has to be a more efficient way to do this – feel free to PR if you know how!
- isActive: (editor) =>
- editor.isActive("paragraph") && !editor.isActive("bulletList") && !editor.isActive("orderedList"),
- },
- {
- name: "Heading 1",
- icon: Heading1,
- command: (editor) => editor.chain().focus().clearNodes().toggleHeading({ level: 1 }).run(),
- isActive: (editor) => editor.isActive("heading", { level: 1 }),
- },
- {
- name: "Heading 2",
- icon: Heading2,
- command: (editor) => editor.chain().focus().clearNodes().toggleHeading({ level: 2 }).run(),
- isActive: (editor) => editor.isActive("heading", { level: 2 }),
- },
- {
- name: "Heading 3",
- icon: Heading3,
- command: (editor) => editor.chain().focus().clearNodes().toggleHeading({ level: 3 }).run(),
- isActive: (editor) => editor.isActive("heading", { level: 3 }),
- },
- {
- name: "To-do List",
- icon: CheckSquare,
- command: (editor) => editor.chain().focus().clearNodes().toggleTaskList().run(),
- isActive: (editor) => editor.isActive("taskItem"),
- },
- {
- name: "Bullet List",
- icon: ListOrdered,
- command: (editor) => editor.chain().focus().clearNodes().toggleBulletList().run(),
- isActive: (editor) => editor.isActive("bulletList"),
- },
- {
- name: "Numbered List",
- icon: ListOrdered,
- command: (editor) => editor.chain().focus().clearNodes().toggleOrderedList().run(),
- isActive: (editor) => editor.isActive("orderedList"),
- },
- {
- name: "Quote",
- icon: TextQuote,
- command: (editor) => editor.chain().focus().clearNodes().toggleBlockquote().run(),
- isActive: (editor) => editor.isActive("blockquote"),
- },
- {
- name: "Code",
- icon: Code,
- command: (editor) => editor.chain().focus().clearNodes().toggleCodeBlock().run(),
- isActive: (editor) => editor.isActive("codeBlock"),
- },
-];
-interface NodeSelectorProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
-}
-
-export const NodeSelector = ({ open, onOpenChange }: NodeSelectorProps) => {
- const { editor } = useEditor();
- if (!editor) return null;
- const activeItem = items.filter((item) => item.isActive(editor)).pop() ?? {
- name: "Multiple",
- };
-
- return (
- <Popover modal={true} open={open} onOpenChange={onOpenChange}>
- <PopoverTrigger asChild className="gap-2 rounded-none border-none hover:bg-accent focus:ring-0">
- <Button size="sm" variant="ghost" className="gap-2">
- <span className="whitespace-nowrap text-sm">{activeItem.name}</span>
- <ChevronDown className="h-4 w-4" />
- </Button>
- </PopoverTrigger>
- <PopoverContent sideOffset={5} align="start" className="w-48 p-1 border-none bg-[#1F2428]">
- {items.map((item) => (
- <EditorBubbleItem
- key={item.name}
- onSelect={(editor) => {
- item.command(editor);
- onOpenChange(false);
- }}
- className="flex cursor-pointer items-center justify-between rounded-sm px-2 py-1 text-sm hover:bg-accent"
- >
- <div className="flex items-center space-x-2">
- <div className="rounded-sm p-1">
- <item.icon className="h-3 w-3" />
- </div>
- <span>{item.name}</span>
- </div>
- {activeItem.name === item.name && <Check className="h-4 w-4" />}
- </EditorBubbleItem>
- ))}
- </PopoverContent>
- </Popover>
- );
-};
diff --git a/apps/web/app/(editor)/components/selectors/text-buttons.tsx b/apps/web/app/(editor)/components/selectors/text-buttons.tsx
deleted file mode 100644
index f75d7b3c..00000000
--- a/apps/web/app/(editor)/components/selectors/text-buttons.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { Button } from "@repo/ui/shadcn/button";
-import { Popover, PopoverContent, PopoverTrigger } from "@repo/ui/shadcn/popover";
-import { BoldIcon, CodeIcon, ItalicIcon, StrikethroughIcon, UnderlineIcon } from "lucide-react";
-import { EditorBubbleItem, useEditor } from "novel";
-import type { SelectorItem } from "./node-selector";
-import { cn } from "@repo/ui/lib/utils";
-
-export const TextButtons = () => {
- const { editor } = useEditor();
- if (!editor) return null;
- const items: SelectorItem[] = [
- {
- name: "bold",
- isActive: (editor) => editor.isActive("bold"),
- command: (editor) => editor.chain().focus().toggleBold().run(),
- icon: BoldIcon,
- },
- {
- name: "italic",
- isActive: (editor) => editor.isActive("italic"),
- command: (editor) => editor.chain().focus().toggleItalic().run(),
- icon: ItalicIcon,
- },
- {
- name: "underline",
- isActive: (editor) => editor.isActive("underline"),
- command: (editor) => editor.chain().focus().toggleUnderline().run(),
- icon: UnderlineIcon,
- },
- {
- name: "strike",
- isActive: (editor) => editor.isActive("strike"),
- command: (editor) => editor.chain().focus().toggleStrike().run(),
- icon: StrikethroughIcon,
- },
- {
- name: "code",
- isActive: (editor) => editor.isActive("code"),
- command: (editor) => editor.chain().focus().toggleCode().run(),
- icon: CodeIcon,
- },
- ];
- return (
- <div className="flex">
- {items.map((item) => (
- <EditorBubbleItem
- key={item.name}
- onSelect={(editor) => {
- item.command(editor);
- }}
- >
- <Button size="sm" className="rounded-none" variant="ghost">
- <item.icon
- className={cn("h-4 w-4", {
- "text-blue-500": item.isActive(editor),
- })}
- />
- </Button>
- </EditorBubbleItem>
- ))}
- </div>
- );
-};
diff --git a/apps/web/app/(editor)/components/slash-command.tsx b/apps/web/app/(editor)/components/slash-command.tsx
deleted file mode 100644
index 1bfb1690..00000000
--- a/apps/web/app/(editor)/components/slash-command.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import {
- CheckSquare,
- Code,
- Heading1,
- Heading2,
- Heading3,
- ImageIcon,
- List,
- ListOrdered,
- MessageSquarePlus,
- Text,
- TextQuote,
- Youtube
-} from "lucide-react";
-import { createSuggestionItems } from "novel/extensions";
-import { Command, renderItems } from "novel/extensions";
-import { uploadFn } from "./image-upload";
-
-export const suggestionItems = createSuggestionItems([
- {
- title: "Send Feedback",
- description: "Let us know how we can improve.",
- icon: <MessageSquarePlus stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).run();
- window.open("/feedback", "_blank");
- },
- },
- {
- title: "Text",
- description: "Just start typing with plain text.",
- searchTerms: ["p", "paragraph"],
- icon: <Text stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
- },
- },
- {
- title: "To-do List",
- description: "Track tasks with a to-do list.",
- searchTerms: ["todo", "task", "list", "check", "checkbox"],
- icon: <CheckSquare stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).toggleTaskList().run();
- },
- },
- {
- title: "Heading 1",
- description: "Big section heading.",
- searchTerms: ["title", "big", "large"],
- icon: <Heading1 stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
- },
- },
- {
- title: "Heading 2",
- description: "Medium section heading.",
- searchTerms: ["subtitle", "medium"],
- icon: <Heading2 stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
- },
- },
- {
- title: "Heading 3",
- description: "Small section heading.",
- searchTerms: ["subtitle", "small"],
- icon: <Heading3 stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
- },
- },
- {
- title: "Bullet List",
- description: "Create a simple bullet list.",
- searchTerms: ["unordered", "point"],
- icon: <List stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).toggleBulletList().run();
- },
- },
- {
- title: "Numbered List",
- description: "Create a list with numbering.",
- searchTerms: ["ordered"],
- icon: <ListOrdered stroke="inherit" size={18} />,
- command: ({ editor, range }) => {
- editor.chain().focus().deleteRange(range).toggleOrderedList().run();
- },
- },
- {
- title: "Quote",
- description: "Capture a quote.",
- searchTerms: ["blockquote"],
- icon: <TextQuote stroke="inherit" size={18} />,
- command: ({ editor, range }) =>
- editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
- },
- {
- title: "Code",
- description: "Capture a code snippet.",
- searchTerms: ["codeblock"],
- icon: <Code stroke="inherit" size={18} />,
- command: ({ editor, range }) => editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
- },
- // {
- // title: "Image",
- // description: "Upload an image from your computer.",
- // searchTerms: ["photo", "picture", "media"],
- // icon: <ImageIcon stroke="inherit" size={18} />,
- // command: ({ editor, range }) => {
- // editor.chain().focus().deleteRange(range).run();
- // // upload image
- // const input = document.createElement("input");
- // input.type = "file";
- // input.accept = "image/*";
- // input.onchange = async () => {
- // if (input.files?.length) {
- // const file = input.files[0];
- // const pos = editor.view.state.selection.from;
- // uploadFn(file, editor.view, pos);
- // }
- // };
- // input.click();
- // },
- // },
- // {
- // title: "Youtube",
- // description: "Embed a Youtube video.",
- // searchTerms: ["video", "youtube", "embed"],
- // icon: <Youtube stroke="inherit" size={18} />,
- // command: ({ editor, range }) => {
- // const videoLink = prompt("Please enter Youtube Video Link");
- // //From https://regexr.com/3dj5t
- // const ytregex = new RegExp(
- // /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/,
- // );
-
- // if (ytregex.test(videoLink)) {
- // editor
- // .chain()
- // .focus()
- // .deleteRange(range)
- // .setYoutubeVideo({
- // src: videoLink,
- // })
- // .run();
- // } else {
- // if (videoLink !== null) {
- // alert("Please enter a correct Youtube Video Link");
- // }
- // }
- // },
- // },
-]);
-
-export const slashCommand = Command.configure({
- suggestion: {
- items: () => suggestionItems,
- render: renderItems,
- },
-});
diff --git a/apps/web/app/(editor)/components/topbar.tsx b/apps/web/app/(editor)/components/topbar.tsx
deleted file mode 100644
index 49b5179c..00000000
--- a/apps/web/app/(editor)/components/topbar.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-"use client";
-
-import {
- AnimatePresence,
- useMotionValueEvent,
- useScroll,
- motion,
-} from "framer-motion";
-import React, { useState } from "react";
-
-function Topbar({
- charsCount,
- saveStatus,
-}: {
- charsCount: number | undefined;
- saveStatus: string;
-}) {
- const [visible, setVisible] = useState(true);
-
- const { scrollYProgress } = useScroll();
- useMotionValueEvent(scrollYProgress, "change", (current) => {
- if (typeof current === "number") {
- let direction = current! - scrollYProgress.getPrevious()!;
-
- if (direction < 0 || direction === 1) {
- setVisible(true);
- } else {
- setVisible(false);
- }
- }
- });
- return (
- <div className="fixed left-0 top-0 z-10">
- <AnimatePresence mode="wait">
- <motion.div
- initial={{
- opacity: 1,
- y: -150,
- }}
- animate={{
- y: visible ? 0 : -150,
- opacity: visible ? 1 : 0,
- }}
- transition={{
- duration: 0.2,
- }}
- className="flex flex-col items-center"
- >
- <div className="gap-2 w-screen flex bg-[#171B1F] justify-center items-center pt-6 pb-4">
- <div className="rounded-lg bg-[#21303D] px-2 py-1 text-sm text-muted-foreground">
- Untitled
- </div>
- <div className="rounded-lg bg-[#21303D] px-2 py-1 text-sm text-muted-foreground">
- {saveStatus}
- </div>
- {charsCount && (
- <div className="rounded-lg bg-[#21303D] px-2 py-1 text-sm text-muted-foreground">
- {`${charsCount} words`}
- </div>
- )}
- </div>
- </motion.div>
- </AnimatePresence>
- </div>
- );
-}
-
-export default Topbar;
diff --git a/apps/web/app/(editor)/components/ui/asksvg.tsx b/apps/web/app/(editor)/components/ui/asksvg.tsx
deleted file mode 100644
index aa38fe08..00000000
--- a/apps/web/app/(editor)/components/ui/asksvg.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-
-function Asksvg() {
- return (
- <svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M5.90925 4.63925C6.7875 3.8705 8.2125 3.8705 9.09075 4.63925C9.96975 5.408 9.96975 6.6545 9.09075 7.42325C8.9385 7.5575 8.76825 7.66775 8.58825 7.75475C8.0295 8.0255 7.50075 8.504 7.50075 9.125V9.6875M14.25 8C14.25 8.88642 14.0754 9.76417 13.7362 10.5831C13.397 11.4021 12.8998 12.1462 12.273 12.773C11.6462 13.3998 10.9021 13.897 10.0831 14.2362C9.26417 14.5754 8.38642 14.75 7.5 14.75C6.61358 14.75 5.73583 14.5754 4.91689 14.2362C4.09794 13.897 3.35382 13.3998 2.72703 12.773C2.10023 12.1462 1.60303 11.4021 1.26381 10.5831C0.924594 9.76417 0.75 8.88642 0.75 8C0.75 6.20979 1.46116 4.4929 2.72703 3.22703C3.9929 1.96116 5.70979 1.25 7.5 1.25C9.29021 1.25 11.0071 1.96116 12.273 3.22703C13.5388 4.4929 14.25 6.20979 14.25 8ZM7.5 11.9375H7.506V11.9435H7.5V11.9375Z" stroke="#989EA4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
-
- )
-}
-
-export default Asksvg \ No newline at end of file
diff --git a/apps/web/app/(editor)/components/ui/autocompletesvg.tsx b/apps/web/app/(editor)/components/ui/autocompletesvg.tsx
deleted file mode 100644
index c433fcad..00000000
--- a/apps/web/app/(editor)/components/ui/autocompletesvg.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-
-function Autocompletesvg() {
- return (
- <svg width="15" height="10" viewBox="0 0 15 10" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M1.3125 1.0625H13.6875M1.3125 5H13.6875M1.3125 8.9375H7.5" stroke="#989EA4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
-
- )
-}
-
-export default Autocompletesvg \ No newline at end of file
diff --git a/apps/web/app/(editor)/components/ui/crazy-spinner.tsx b/apps/web/app/(editor)/components/ui/crazy-spinner.tsx
deleted file mode 100644
index 2e95deee..00000000
--- a/apps/web/app/(editor)/components/ui/crazy-spinner.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-const CrazySpinner = () => {
- return (
- <div className="flex justify-center items-center gap-1.5">
- <div className="h-1.5 w-1.5 animate-ping rounded-full bg-[#369DFD] [animation-delay:-0.4s]" />
- <div className="h-1.5 w-1.5 animate-ping rounded-full bg-[#369DFD] [animation-delay:-0.2s]" />
- <div className="h-1.5 w-1.5 animate-ping rounded-full bg-[#369DFD]" />
- </div>
- );
-};
-
-export default CrazySpinner;
diff --git a/apps/web/app/(editor)/components/ui/magic.tsx b/apps/web/app/(editor)/components/ui/magic.tsx
deleted file mode 100644
index 04dce39e..00000000
--- a/apps/web/app/(editor)/components/ui/magic.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function Magic({ className }: { className: string }) {
- return (
-<svg width="18" height="19" className={className} viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M6.49998 3.25C6.63578 3.25003 6.76788 3.29429 6.87629 3.37608C6.98469 3.45788 7.06351 3.57275 7.10081 3.70333L7.77831 6.075C7.92418 6.58576 8.19785 7.05092 8.57345 7.42652C8.94906 7.80213 9.41421 8.07579 9.92498 8.22167L12.2966 8.89917C12.4271 8.93655 12.5419 9.0154 12.6236 9.1238C12.7053 9.2322 12.7495 9.36425 12.7495 9.5C12.7495 9.63574 12.7053 9.7678 12.6236 9.8762C12.5419 9.9846 12.4271 10.0634 12.2966 10.1008L9.92498 10.7783C9.41421 10.9242 8.94906 11.1979 8.57345 11.5735C8.19785 11.9491 7.92418 12.4142 7.77831 12.925L7.10081 15.2967C7.06343 15.4272 6.98458 15.5419 6.87618 15.6236C6.76778 15.7054 6.63572 15.7495 6.49998 15.7495C6.36423 15.7495 6.23218 15.7054 6.12378 15.6236C6.01538 15.5419 5.93653 15.4272 5.89914 15.2967L5.22164 12.925C5.07577 12.4142 4.80211 11.9491 4.4265 11.5735C4.05089 11.1979 3.58574 10.9242 3.07498 10.7783L0.70331 10.1008C0.572814 10.0634 0.458036 9.9846 0.376329 9.8762C0.294622 9.7678 0.250427 9.63574 0.250427 9.5C0.250427 9.36425 0.294622 9.2322 0.376329 9.1238C0.458036 9.0154 0.572814 8.93655 0.70331 8.89917L3.07498 8.22167C3.58574 8.07579 4.05089 7.80213 4.4265 7.42652C4.80211 7.05092 5.07577 6.58576 5.22164 6.075L5.89914 3.70333C5.93644 3.57275 6.01526 3.45788 6.12367 3.37608C6.23208 3.29429 6.36417 3.25003 6.49998 3.25ZM14 0.75C14.1394 0.749922 14.2749 0.79647 14.3848 0.882239C14.4947 0.968007 14.5728 1.08807 14.6066 1.22333L14.8216 2.08667C15.0183 2.87 15.63 3.48167 16.4133 3.67833L17.2766 3.89333C17.4122 3.9269 17.5325 4.00488 17.6186 4.11483C17.7046 4.22479 17.7514 4.36038 17.7514 4.5C17.7514 4.63962 17.7046 4.77521 17.6186 4.88517C17.5325 4.99512 17.4122 5.0731 17.2766 5.10667L16.4133 5.32167C15.63 5.51833 15.0183 6.13 14.8216 6.91333L14.6066 7.77667C14.5731 7.91219 14.4951 8.03257 14.3851 8.11861C14.2752 8.20465 14.1396 8.2514 14 8.2514C13.8604 8.2514 13.7248 8.20465 13.6148 8.11861C13.5049 8.03257 13.4269 7.91219 13.3933 7.77667L13.1783 6.91333C13.0822 6.52869 12.8833 6.17741 12.6029 5.89706C12.3226 5.61671 11.9713 5.41782 11.5866 5.32167L10.7233 5.10667C10.5878 5.0731 10.4674 4.99512 10.3814 4.88517C10.2953 4.77521 10.2486 4.63962 10.2486 4.5C10.2486 4.36038 10.2953 4.22479 10.3814 4.11483C10.4674 4.00488 10.5878 3.9269 10.7233 3.89333L11.5866 3.67833C11.9713 3.58218 12.3226 3.38329 12.6029 3.10294C12.8833 2.82258 13.0822 2.47131 13.1783 2.08667L13.3933 1.22333C13.4271 1.08807 13.5052 0.968007 13.6152 0.882239C13.7251 0.79647 13.8605 0.749922 14 0.75ZM12.75 12C12.8812 11.9999 13.0092 12.0412 13.1157 12.1179C13.2222 12.1946 13.3018 12.303 13.3433 12.4275L13.6716 13.4133C13.7966 13.7858 14.0883 14.0792 14.4616 14.2033L15.4475 14.5325C15.5716 14.5742 15.6795 14.6538 15.756 14.7601C15.8324 14.8664 15.8736 14.9941 15.8736 15.125C15.8736 15.2559 15.8324 15.3836 15.756 15.4899C15.6795 15.5962 15.5716 15.6758 15.4475 15.7175L14.4616 16.0467C14.0891 16.1717 13.7958 16.4633 13.6716 16.8367L13.3425 17.8225C13.3008 17.9466 13.2212 18.0545 13.1149 18.131C13.0086 18.2075 12.8809 18.2486 12.75 18.2486C12.619 18.2486 12.4914 18.2075 12.3851 18.131C12.2788 18.0545 12.1992 17.9466 12.1575 17.8225L11.8283 16.8367C11.7669 16.6527 11.6636 16.4856 11.5265 16.3485C11.3894 16.2114 11.2222 16.1081 11.0383 16.0467L10.0525 15.7175C9.92834 15.6758 9.82043 15.5962 9.74398 15.4899C9.66752 15.3836 9.6264 15.2559 9.6264 15.125C9.6264 14.9941 9.66752 14.8664 9.74398 14.7601C9.82043 14.6538 9.92834 14.5742 10.0525 14.5325L11.0383 14.2033C11.4108 14.0783 11.7041 13.7867 11.8283 13.4133L12.1575 12.4275C12.1989 12.3031 12.2784 12.1949 12.3848 12.1182C12.4911 12.0414 12.6189 12.0001 12.75 12Z" fill="#369DFD"/>
-</svg>
-
- );
-}
diff --git a/apps/web/app/(editor)/components/ui/rewritesvg.tsx b/apps/web/app/(editor)/components/ui/rewritesvg.tsx
deleted file mode 100644
index fad9eb90..00000000
--- a/apps/web/app/(editor)/components/ui/rewritesvg.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-function Rewritesvg() {
- return (
- <svg width="17" height="14" viewBox="0 0 17 14" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M11.5172 5.01108H15.2612L12.8755 2.62383C12.1074 1.85573 11.1506 1.30337 10.1014 1.02228C9.05214 0.74119 7.94738 0.741272 6.89818 1.02252C5.84897 1.30377 4.8923 1.85627 4.12433 2.62448C3.35635 3.39269 2.80415 4.34954 2.52323 5.39883M1.73873 12.7331V8.98908M1.73873 8.98908H5.48273M1.73873 8.98908L4.12373 11.3763C4.89181 12.1444 5.84857 12.6968 6.89782 12.9779C7.94706 13.259 9.05182 13.2589 10.101 12.9776C11.1502 12.6964 12.1069 12.1439 12.8749 11.3757C13.6428 10.6075 14.1951 9.65062 14.476 8.60133M15.2612 1.26708V5.00958" stroke="#989EA4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
- )
-}
-
-export default Rewritesvg \ No newline at end of file
diff --git a/apps/web/app/(editor)/components/ui/translatesvg.tsx b/apps/web/app/(editor)/components/ui/translatesvg.tsx
deleted file mode 100644
index cde82da6..00000000
--- a/apps/web/app/(editor)/components/ui/translatesvg.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-
-function Translatesvg() {
- return (
- <svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M6.375 14.75L10.3125 6.3125L14.25 14.75M7.5 12.5H13.125M0.75 3.21575C2.2428 3.02999 3.74569 2.93706 5.25 2.9375M5.25 2.9375C6.09 2.9375 6.92475 2.966 7.7505 3.023M5.25 2.9375V1.25M7.7505 3.023C6.882 6.9935 4.2675 10.31 0.75 12.1265M7.7505 3.023C8.4225 3.06875 9.08925 3.13325 9.75 3.21575M6.30825 9.587C5.07822 8.33647 4.10335 6.85849 3.438 5.2355" stroke="#989EA4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
-
- )
-}
-
-export default Translatesvg \ No newline at end of file
diff --git a/apps/web/app/(editor)/editor.tsx b/apps/web/app/(editor)/editor.tsx
deleted file mode 100644
index f7f9a098..00000000
--- a/apps/web/app/(editor)/editor.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-"use client";
-import { defaultEditorContent } from "./lib/content";
-import { EditorContent, EditorRoot, type JSONContent } from "novel";
-import { ImageResizer } from "novel/extensions";
-import { useEffect, useState } from "react";
-import { defaultExtensions } from "./components/extensions";
-
-import { slashCommand } from "./components/slash-command";
-import { Updates } from "./lib/debouncedsave";
-import { editorProps } from "./lib/editorprops";
-import EditorCommands from "./components/editorcommands";
-import Aigenerate from "./components/aigenerate";
-import { useMotionValueEvent, useScroll } from "framer-motion";
-import Topbar from "./components/topbar";
-
-const Editor = () => {
- const [initialContent, setInitialContent] = useState<null | JSONContent>(
- null,
- );
- const [saveStatus, setSaveStatus] = useState("Saved");
- const [charsCount, setCharsCount] = useState();
- const [visible, setVisible] = useState(true);
-
- useEffect(() => {
- if (typeof window === "undefined") return;
- const content = window.localStorage.getItem("novel-content");
- if (content) setInitialContent(JSON.parse(content));
- else setInitialContent(defaultEditorContent);
- }, []);
-
- if (!initialContent) return <>Loading...</>;
-
- return (
- <div className="relative w-full max-w-screen-xl">
- <Topbar charsCount={charsCount} saveStatus={saveStatus} />
- <EditorRoot>
- <EditorContent
- initialContent={initialContent}
- extensions={[...defaultExtensions, slashCommand]}
- className="min-h-[55vh] mt-[8vh] w-full max-w-screen-xl bg-[#171B1F] mb-[40vh]"
- editorProps={editorProps}
- onUpdate={({ editor }) => {
- Updates({ editor, setCharsCount, setSaveStatus });
- }}
- slotAfter={<ImageResizer />}
- >
- <EditorCommands />
- <Aigenerate />
- </EditorContent>
- </EditorRoot>
- </div>
- );
-};
-
-export default Editor;
diff --git a/apps/web/app/(editor)/editor/page.tsx b/apps/web/app/(editor)/editor/page.tsx
deleted file mode 100644
index d0298065..00000000
--- a/apps/web/app/(editor)/editor/page.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import TailwindAdvancedEditor from "../editor";
-export default function Page() {
- return (
- <div className="flex min-h-screen flex-col items-center bg-[#171B1F]">
- <TailwindAdvancedEditor />
- </div>
- );
-}
diff --git a/apps/web/app/(editor)/layout.tsx b/apps/web/app/(editor)/layout.tsx
deleted file mode 100644
index 1bf97715..00000000
--- a/apps/web/app/(editor)/layout.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import "./styles/prosemirror.css";
-import "./styles/globals.css"
-import type { ReactNode } from "react";
-
-
-export default function RootLayout({ children }: { children: ReactNode }) {
- return (
- <div className="dark">
- {children}
- </div>
- );
-}
diff --git a/apps/web/app/(editor)/lib/content.ts b/apps/web/app/(editor)/lib/content.ts
deleted file mode 100644
index 6464cfa1..00000000
--- a/apps/web/app/(editor)/lib/content.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-export const defaultEditorContent = {
- type: "doc",
- content: [
- {
- type: "heading",
- attrs: { level: 2 },
- content: [{ type: "text", text: "Introducing Novel" }],
- },
- {
- type: "paragraph",
- content: [
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://github.com/steven-tey/novel",
- target: "_blank",
- },
- },
- ],
- text: "Novel",
- },
- {
- type: "text",
- text: " is a Notion-style WYSIWYG editor with AI-powered autocompletion. Built with ",
- },
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://tiptap.dev/",
- target: "_blank",
- },
- },
- ],
- text: "Tiptap",
- },
- { type: "text", text: " + " },
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://sdk.vercel.ai/docs",
- target: "_blank",
- },
- },
- ],
- text: "Vercel AI SDK",
- },
- { type: "text", text: "." },
- ],
- },
- {
- type: "heading",
- attrs: { level: 3 },
- content: [{ type: "text", text: "Installation" }],
- },
- {
- type: "codeBlock",
- attrs: { language: null },
- content: [{ type: "text", text: "npm i novel" }],
- },
- {
- type: "heading",
- attrs: { level: 3 },
- content: [{ type: "text", text: "Usage" }],
- },
- {
- type: "codeBlock",
- attrs: { language: null },
- content: [
- {
- type: "text",
- text: 'import { Editor } from "novel";\n\nexport default function App() {\n return (\n <Editor />\n )\n}',
- },
- ],
- },
- {
- type: "heading",
- attrs: { level: 3 },
- content: [{ type: "text", text: "Features" }],
- },
- {
- type: "orderedList",
- attrs: { tight: true, start: 1 },
- content: [
- {
- type: "listItem",
- content: [
- {
- type: "paragraph",
- content: [{ type: "text", text: "Slash menu & bubble menu" }],
- },
- ],
- },
- {
- type: "listItem",
- content: [
- {
- type: "paragraph",
- content: [
- { type: "text", text: "AI autocomplete (type " },
- { type: "text", marks: [{ type: "code" }], text: "++" },
- {
- type: "text",
- text: " to activate, or select from slash menu)",
- },
- ],
- },
- ],
- },
- {
- type: "listItem",
- content: [
- {
- type: "paragraph",
- content: [
- {
- type: "text",
- text: "Image uploads (drag & drop / copy & paste, or select from slash menu) ",
- },
- ],
- },
- ],
- },
- ],
- },
- {
- type: "image",
- attrs: {
- src: "https://public.blob.vercel-storage.com/pJrjXbdONOnAeZAZ/banner-2wQk82qTwyVgvlhTW21GIkWgqPGD2C.png",
- alt: "banner.png",
- title: "banner.png",
- width: null,
- height: null,
- },
- },
- { type: "horizontalRule" },
- {
- type: "heading",
- attrs: { level: 3 },
- content: [{ type: "text", text: "Learn more" }],
- },
- {
- type: "taskList",
- content: [
- {
- type: "taskItem",
- attrs: { checked: false },
- content: [
- {
- type: "paragraph",
- content: [
- { type: "text", text: "Star us on " },
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://github.com/steven-tey/novel",
- target: "_blank",
- },
- },
- ],
- text: "GitHub",
- },
- ],
- },
- ],
- },
- {
- type: "taskItem",
- attrs: { checked: false },
- content: [
- {
- type: "paragraph",
- content: [
- { type: "text", text: "Install the " },
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://www.npmjs.com/package/novel",
- target: "_blank",
- },
- },
- ],
- text: "NPM package",
- },
- ],
- },
- ],
- },
- {
- type: "taskItem",
- attrs: { checked: false },
- content: [
- {
- type: "paragraph",
- content: [
- {
- type: "text",
- marks: [
- {
- type: "link",
- attrs: {
- href: "https://vercel.com/templates/next.js/novel",
- target: "_blank",
- },
- },
- ],
- text: "Deploy your own",
- },
- { type: "text", text: " to Vercel" },
- ],
- },
- ],
- },
- ],
- },
- ],
-};
diff --git a/apps/web/app/(editor)/lib/debouncedsave.ts b/apps/web/app/(editor)/lib/debouncedsave.ts
deleted file mode 100644
index 6490c6c4..00000000
--- a/apps/web/app/(editor)/lib/debouncedsave.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import hljs from 'highlight.js'
-import { debounce } from 'tldraw';
-import { useDebouncedCallback } from "use-debounce";
-
-export const Updates = debounce(({editor, setCharsCount, setSaveStatus})=> {
- const json = editor.getJSON();
- setCharsCount(editor.storage.characterCount.words());
- window.localStorage.setItem("html-content", highlightCodeblocks(editor.getHTML()));
- window.localStorage.setItem("novel-content", JSON.stringify(json));
- window.localStorage.setItem("markdown", editor.storage.markdown.getMarkdown());
- setSaveStatus("Saved");
-}, 500)
-
-export const highlightCodeblocks = (content: string) => {
- const doc = new DOMParser().parseFromString(content, 'text/html');
- doc.querySelectorAll('pre code').forEach((el) => {
- hljs.highlightElement(el);
- });
- return new XMLSerializer().serializeToString(doc);
-}; \ No newline at end of file
diff --git a/apps/web/app/(editor)/lib/editorprops.ts b/apps/web/app/(editor)/lib/editorprops.ts
deleted file mode 100644
index 00d89264..00000000
--- a/apps/web/app/(editor)/lib/editorprops.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { handleCommandNavigation } from "novel/extensions";
-import { handleImageDrop, handleImagePaste } from "novel/plugins";
-import { uploadFn } from "../components/image-upload";
-import { EditorView } from "prosemirror-view";
-
-export const editorProps = {
- handleDOMEvents: {
- keydown: (_view: EditorView, event: KeyboardEvent) => handleCommandNavigation(event),
- },
- handlePaste: (view: EditorView, event: ClipboardEvent) => handleImagePaste(view, event, uploadFn),
- handleDrop: (view: EditorView, event: DragEvent, slice, moved:boolean) => handleImageDrop(view, event, moved, uploadFn),
- attributes: {
- class:
- "prose prose-lg dark:prose-invert prose-headings:font-title font-default focus:outline-none max-w-full",
- },
-} \ No newline at end of file
diff --git a/apps/web/app/(editor)/lib/use-local-storage.ts b/apps/web/app/(editor)/lib/use-local-storage.ts
deleted file mode 100644
index 5f2ebeb9..00000000
--- a/apps/web/app/(editor)/lib/use-local-storage.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { useEffect, useState } from "react";
-
-const useLocalStorage = <T>(
- key: string,
- initialValue: T,
- // eslint-disable-next-line no-unused-vars
-): [T, (value: T) => void] => {
- const [storedValue, setStoredValue] = useState(initialValue);
-
- useEffect(() => {
- // Retrieve from localStorage
- const item = window.localStorage.getItem(key);
- if (item) {
- setStoredValue(JSON.parse(item));
- }
- }, [key]);
-
- const setValue = (value: T) => {
- // Save state
- setStoredValue(value);
- // Save to localStorage
- window.localStorage.setItem(key, JSON.stringify(value));
- };
- return [storedValue, setValue];
-};
-
-export default useLocalStorage;
diff --git a/apps/web/app/(editor)/styles/globals.css b/apps/web/app/(editor)/styles/globals.css
deleted file mode 100644
index 336e2dae..00000000
--- a/apps/web/app/(editor)/styles/globals.css
+++ /dev/null
@@ -1,168 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-@layer base {
- :root {
- --background: 0 0% 100%;
- --foreground: 222.2 84% 4.9%;
-
- --card: 0 0% 100%;
- --card-foreground: 222.2 84% 4.9%;
-
- --popover: 0 0% 100%;
- --popover-foreground: 222.2 84% 4.9%;
-
- --primary: 222.2 47.4% 11.2%;
- --primary-foreground: 210 40% 98%;
-
- --secondary: 210 40% 96.1%;
- --secondary-foreground: 222.2 47.4% 11.2%;
-
- --muted: 210 40% 96.1%;
- --muted-foreground: 215.4 16.3% 46.9%;
-
- --accent: 210 40% 96.1%;
- --accent-foreground: 222.2 47.4% 11.2%;
-
- --destructive: 0 84.2% 60.2%;
- --destructive-foreground: 210 40% 98%;
-
- --border: 214.3 31.8% 91.4%;
- --input: 214.3 31.8% 91.4%;
- --ring: 222.2 84% 4.9%;
-
- --radius: 0.5rem;
-
- --novel-highlight-default: #ffffff;
- --novel-highlight-purple: #f6f3f8;
- --novel-highlight-red: #fdebeb;
- --novel-highlight-yellow: #fbf4a2;
- --novel-highlight-blue: #c1ecf9;
- --novel-highlight-green: #acf79f;
- --novel-highlight-orange: #faebdd;
- --novel-highlight-pink: #faf1f5;
- --novel-highlight-gray: #f1f1ef;
- }
-
- .dark {
- --background: #171B1F;
- --foreground: 210 40% 98%;
-
- --card: 222.2 84% 4.9%;
- --card-foreground: 210 40% 98%;
-
- --popover: 222.2 84% 4.9%;
- --popover-foreground: 210 40% 98%;
-
- --primary: 210 40% 98%;
- --primary-foreground: 222.2 47.4% 11.2%;
-
- --secondary: 217.2 32.6% 17.5%;
- --secondary-foreground: 210 40% 98%;
-
- --muted: 217.2 32.6% 17.5%;
- --muted-foreground: 215 20.2% 65.1%;
-
- --accent: 217.2 32.6% 17.5%;
- --accent-foreground: 210 40% 98%;
-
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 210 40% 98%;
-
- --border: 217.2 32.6% 17.5%;
- --input: 217.2 32.6% 17.5%;
- --ring: 212.7 26.8% 83.9%;
-
- --novel-highlight-default: #000000;
- --novel-highlight-purple: #3f2c4b;
- --novel-highlight-red: #5c1a1a;
- --novel-highlight-yellow: #5c4b1a;
- --novel-highlight-blue: #1a3d5c;
- --novel-highlight-green: #1a5c20;
- --novel-highlight-orange: #5c3a1a;
- --novel-highlight-pink: #5c1a3a;
- --novel-highlight-gray: #3a3a3a;
- }
-}
-
-@layer base {
- * {
- @apply border-border;
- }
- body {
- @apply bg-background text-foreground;
- }
-}
-
-
-pre {
- background: #0d0d0d;
- border-radius: 0.5rem;
- color: #fff;
- font-family: "JetBrainsMono", monospace;
- padding: 0.75rem 1rem;
-
- code {
- background: none;
- color: inherit;
- font-size: 0.8rem;
- padding: 0;
- }
-
- .hljs-comment,
- .hljs-quote {
- color: #616161;
- }
-
- .hljs-variable,
- .hljs-template-variable,
- .hljs-attribute,
- .hljs-tag,
- .hljs-name,
- .hljs-regexp,
- .hljs-link,
- .hljs-name,
- .hljs-selector-id,
- .hljs-selector-class {
- color: #f98181;
- }
-
- .hljs-number,
- .hljs-meta,
- .hljs-built_in,
- .hljs-builtin-name,
- .hljs-literal,
- .hljs-type,
- .hljs-params {
- color: #fbbc88;
- }
-
- .hljs-string,
- .hljs-symbol,
- .hljs-bullet {
- color: #b9f18d;
- }
-
- .hljs-title,
- .hljs-section {
- color: #faf594;
- }
-
- .hljs-keyword,
- .hljs-selector-tag {
- color: #70cff8;
- }
-
- .hljs-emphasis {
- font-style: italic;
- }
-
- .hljs-strong {
- font-weight: 700;
- }
-}
-::-webkit-scrollbar{
- width: 0;
-}
-
diff --git a/apps/web/app/(editor)/styles/prosemirror.css b/apps/web/app/(editor)/styles/prosemirror.css
deleted file mode 100644
index 7298c98b..00000000
--- a/apps/web/app/(editor)/styles/prosemirror.css
+++ /dev/null
@@ -1,203 +0,0 @@
-.ProseMirror {
- @apply p-12 px-8 sm:px-12;
-}
-
-.ProseMirror .is-editor-empty:first-child::before {
- content: attr(data-placeholder);
- float: left;
- color: hsl(var(--muted-foreground));
- pointer-events: none;
- height: 0;
-}
-.ProseMirror .is-empty::before {
- content: attr(data-placeholder);
- float: left;
- color: hsl(var(--muted-foreground));
- pointer-events: none;
- height: 0;
-}
-
-/* Custom image styles */
-
-.ProseMirror img {
- transition: filter 0.1s ease-in-out;
-
- &:hover {
- cursor: pointer;
- filter: brightness(90%);
- }
-
- &.ProseMirror-selectednode {
- outline: 3px solid #5abbf7;
- filter: brightness(90%);
- }
-}
-
-.img-placeholder {
- position: relative;
-
- &:before {
- content: "";
- box-sizing: border-box;
- position: absolute;
- top: 50%;
- left: 50%;
- width: 36px;
- height: 36px;
- border-radius: 50%;
- border: 3px solid var(--novel-stone-200);
- border-top-color: var(--novel-stone-800);
- animation: spinning 0.6s linear infinite;
- }
-}
-
-@keyframes spinning {
- to {
- transform: rotate(360deg);
- }
-}
-
-/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */
-
-ul[data-type="taskList"] li > label {
- margin-right: 0.2rem;
- user-select: none;
-}
-
-@media screen and (max-width: 768px) {
- ul[data-type="taskList"] li > label {
- margin-right: 0.5rem;
- }
-}
-
-ul[data-type="taskList"] li > label input[type="checkbox"] {
- -webkit-appearance: none;
- appearance: none;
- background-color: hsl(var(--background));
- margin: 0;
- cursor: pointer;
- width: 1.2em;
- height: 1.2em;
- position: relative;
- top: 5px;
- border: 2px solid hsl(var(--border));
- margin-right: 0.3rem;
- display: grid;
- place-content: center;
-
- &:hover {
- background-color: hsl(var(--accent));
- }
-
- &:active {
- background-color: hsl(var(--accent));
- }
-
- &::before {
- content: "";
- width: 0.65em;
- height: 0.65em;
- transform: scale(0);
- transition: 120ms transform ease-in-out;
- box-shadow: inset 1em 1em;
- transform-origin: center;
- clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
- }
-
- &:checked::before {
- transform: scale(1);
- }
-}
-
-ul[data-type="taskList"] li[data-checked="true"] > div > p {
- color: var(--muted-foreground);
- text-decoration: line-through;
- text-decoration-thickness: 2px;
-}
-
-/* Overwrite tippy-box original max-width */
-
-.tippy-box {
- max-width: 400px !important;
-}
-
-.ProseMirror:not(.dragging) .ProseMirror-selectednode {
- outline: none !important;
- background-color: var(--novel-highlight-blue);
- transition: background-color 0.2s;
- box-shadow: none;
-}
-
-.drag-handle {
- position: fixed;
- opacity: 1;
- transition: opacity ease-in 0.2s;
- border-radius: 0.25rem;
-
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(0, 0, 0, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E");
- background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem);
- background-repeat: no-repeat;
- background-position: center;
- width: 1.2rem;
- height: 1.5rem;
- z-index: 50;
- cursor: grab;
-
- &:hover {
- background-color: var(--novel-stone-100);
- transition: background-color 0.2s;
- }
-
- &:active {
- background-color: var(--novel-stone-200);
- transition: background-color 0.2s;
- cursor: grabbing;
- }
-
- &.hide {
- opacity: 0;
- pointer-events: none;
- }
-
- @media screen and (max-width: 600px) {
- display: none;
- pointer-events: none;
- }
-}
-
-.dark .drag-handle {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(255, 255, 255, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E");
-}
-
-/* Custom Youtube Video CSS */
-iframe {
- border: 8px solid #ffd00027;
- border-radius: 4px;
- min-width: 200px;
- min-height: 200px;
- display: block;
- outline: 0px solid transparent;
-}
-
-div[data-youtube-video] > iframe {
- cursor: move;
- aspect-ratio: 16 / 9;
- width: 100%;
-}
-
-.ProseMirror-selectednode iframe {
- transition: outline 0.15s;
- outline: 6px solid #fbbf24;
-}
-
-@media only screen and (max-width: 480px) {
- div[data-youtube-video] > iframe {
- max-height: 50px;
- }
-}
-
-@media only screen and (max-width: 720px) {
- div[data-youtube-video] > iframe {
- max-height: 100px;
- }
-} \ No newline at end of file
diff --git a/packages/ui/components/canvas/draggableComponent.tsx b/packages/ui/components/canvas/draggableComponent.tsx
new file mode 100644
index 00000000..da3c42c7
--- /dev/null
+++ b/packages/ui/components/canvas/draggableComponent.tsx
@@ -0,0 +1,72 @@
+import Image from "next/image";
+import { useRef, useState } from "react";
+
+interface DraggableComponentsProps {
+ content: string;
+ extraInfo?: string;
+ icon: string;
+ iconAlt: string;
+}
+
+export default function DraggableComponentsContainer({
+ content,
+}: {
+ content: DraggableComponentsProps[];
+}) {
+ return (
+ <div className="flex flex-col gap-10">
+ {content.map((i) => {
+ return (
+ <DraggableComponents
+ content={i.content}
+ icon={i.icon}
+ iconAlt={i.iconAlt}
+ extraInfo={i.extraInfo}
+ />
+ );
+ })}
+ </div>
+ );
+}
+
+function DraggableComponents({
+ content,
+ extraInfo,
+ icon,
+ iconAlt,
+}: DraggableComponentsProps) {
+ const [isDragging, setIsDragging] = useState(false);
+ const containerRef = useRef<HTMLDivElement>(null);
+
+ const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
+ setIsDragging(true);
+ if (containerRef.current) {
+ // Serialize the children as a string for dataTransfer
+ const childrenHtml = containerRef.current.innerHTML;
+ event.dataTransfer.setData("text/html", childrenHtml);
+ }
+ };
+
+ const handleDragEnd = () => {
+ setIsDragging(false);
+ };
+
+
+ return (
+ <div
+ ref={containerRef}
+ onDragEnd={handleDragEnd}
+ onDragStart={handleDragStart}
+ draggable
+ className={`flex gap-4 px-3 text-[#989EA4] border-2 transition ${isDragging ? "border-blue-600": "border-[#1F2428]"}`}
+ >
+ <Image className="select-none" src={icon} alt={iconAlt} />
+ <div className="flex flex-col gap-2">
+ <div>
+ <h1 className="line-clamp-3">{content}</h1>
+ </div>
+ <p className="line-clamp-1 text-[#369DFD]">{extraInfo}</p>
+ </div>
+ </div>
+ );
+}
diff --git a/packages/ui/icons/autocomplete.svg b/packages/ui/icons/autocomplete.svg
new file mode 100644
index 00000000..a4452242
--- /dev/null
+++ b/packages/ui/icons/autocomplete.svg
@@ -0,0 +1,15 @@
+ <svg
+ width="34"
+ height="24"
+ viewBox="0 0 14 10"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M0.8125 1.0625H13.1875M0.8125 5H13.1875M0.8125 8.9375H7"
+ stroke="#989EA4"
+ stroke-width="1.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ />
+ </svg> \ No newline at end of file
diff --git a/packages/ui/icons/block.svg b/packages/ui/icons/block.svg
new file mode 100644
index 00000000..ca4cc20e
--- /dev/null
+++ b/packages/ui/icons/block.svg
@@ -0,0 +1,15 @@
+ <svg
+ width="32"
+ height="36"
+ viewBox="0 0 16 18"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M14.75 5.625L8 1.6875L1.25 5.625M14.75 5.625L8 9.5625M14.75 5.625V12.375L8 16.3125M1.25 5.625L8 9.5625M1.25 5.625V12.375L8 16.3125M8 9.5625V16.3125"
+ stroke="#989EA4"
+ stroke-width="1.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ />
+ </svg> \ No newline at end of file
diff --git a/packages/ui/icons/canvas.svg b/packages/ui/icons/canvas.svg
new file mode 100644
index 00000000..529c75de
--- /dev/null
+++ b/packages/ui/icons/canvas.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="20" viewBox="0 0 22 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.25 0.25C1.05109 0.25 0.860322 0.329018 0.71967 0.46967C0.579018 0.610322 0.5 0.801088 0.5 1C0.5 1.19891 0.579018 1.38968 0.71967 1.53033C0.860322 1.67098 1.05109 1.75 1.25 1.75H2V12.25C2 13.0456 2.31607 13.8087 2.87868 14.3713C3.44129 14.9339 4.20435 15.25 5 15.25H6.21L5.038 18.763C4.97514 18.9518 4.98988 19.1579 5.07896 19.3359C5.16804 19.5138 5.32417 19.6491 5.513 19.712C5.70183 19.7749 5.9079 19.7601 6.08588 19.671C6.26385 19.582 6.39914 19.4258 6.462 19.237L6.791 18.25H15.209L15.539 19.237C15.6073 19.4186 15.7433 19.5666 15.9184 19.6501C16.0935 19.7335 16.2941 19.7459 16.4782 19.6845C16.6622 19.6232 16.8153 19.4929 16.9053 19.3211C16.9954 19.1493 17.0153 18.9492 16.961 18.763L15.791 15.25H17C17.7956 15.25 18.5587 14.9339 19.1213 14.3713C19.6839 13.8087 20 13.0456 20 12.25V1.75H20.75C20.9489 1.75 21.1397 1.67098 21.2803 1.53033C21.421 1.38968 21.5 1.19891 21.5 1C21.5 0.801088 21.421 0.610322 21.2803 0.46967C21.1397 0.329018 20.9489 0.25 20.75 0.25H1.25ZM7.79 15.25H14.21L14.71 16.75H7.29L7.79 15.25ZM15.875 6.255C15.961 6.20611 16.0364 6.1407 16.097 6.06253C16.1577 5.98436 16.2022 5.89497 16.2281 5.79952C16.254 5.70406 16.2608 5.60443 16.2481 5.50634C16.2353 5.40826 16.2033 5.31366 16.1538 5.228C16.1044 5.14235 16.0385 5.06732 15.9599 5.00724C15.8813 4.94715 15.7916 4.90321 15.696 4.87793C15.6004 4.85264 15.5007 4.84653 15.4027 4.85993C15.3047 4.87333 15.2103 4.90598 15.125 4.956C13.7615 5.74523 12.5554 6.7792 11.567 8.006L10.03 6.47C9.88937 6.32955 9.69875 6.25066 9.5 6.25066C9.30125 6.25066 9.11063 6.32955 8.97 6.47L5.97 9.47C5.89631 9.53866 5.83721 9.62146 5.79622 9.71346C5.75523 9.80546 5.73319 9.90477 5.73141 10.0055C5.72963 10.1062 5.74816 10.2062 5.78588 10.2996C5.8236 10.393 5.87974 10.4778 5.95096 10.549C6.02218 10.6203 6.10701 10.6764 6.2004 10.7141C6.29379 10.7518 6.39382 10.7704 6.49452 10.7686C6.59523 10.7668 6.69454 10.7448 6.78654 10.7038C6.87854 10.6628 6.96134 10.6037 7.03 10.53L9.5 8.06L11.117 9.678C11.1946 9.75558 11.2882 9.81519 11.3913 9.85264C11.4945 9.89008 11.6046 9.90445 11.7138 9.89472C11.8231 9.885 11.9289 9.85142 12.0238 9.79635C12.1187 9.74128 12.2003 9.66606 12.263 9.576C13.2095 8.21806 14.4425 7.0844 15.875 6.255Z" fill="#6A737D"/>
+</svg>
diff --git a/apps/web/app/(canvas)/svg.tsx b/packages/ui/icons/drag.svg
index bae4e614..366a4cb0 100644
--- a/apps/web/app/(canvas)/svg.tsx
+++ b/packages/ui/icons/drag.svg
@@ -1,24 +1,3 @@
-export function SettingsSvg() {
- return (
- <svg
- width="16"
- height="18"
- viewBox="0 0 16 18"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- fill-rule="evenodd"
- clip-rule="evenodd"
- d="M7.2321 0.875C6.46793 0.875 5.81627 1.4275 5.69043 2.18083L5.5421 3.07417C5.52543 3.17417 5.44627 3.29083 5.2946 3.36417C5.00906 3.50143 4.73438 3.66022 4.47293 3.83917C4.3346 3.935 4.1946 3.94417 4.09793 3.90833L3.25043 3.59C2.90397 3.4602 2.52268 3.45755 2.17445 3.58253C1.82621 3.70751 1.53362 3.95201 1.34877 4.2725L0.580434 5.60333C0.395508 5.92363 0.330196 6.29915 0.396115 6.66307C0.462034 7.027 0.65491 7.35575 0.940434 7.59083L1.64043 8.1675C1.7196 8.2325 1.7821 8.35833 1.76877 8.52583C1.74502 8.84178 1.74502 9.15906 1.76877 9.475C1.78127 9.64167 1.7196 9.76833 1.64127 9.83333L0.940434 10.41C0.65491 10.6451 0.462034 10.9738 0.396115 11.3378C0.330196 11.7017 0.395508 12.0772 0.580434 12.3975L1.34877 13.7283C1.53376 14.0487 1.8264 14.293 2.17462 14.4178C2.52285 14.5426 2.90406 14.5399 3.25043 14.41L4.0996 14.0917C4.19543 14.0558 4.33543 14.0658 4.4746 14.16C4.7346 14.3383 5.00877 14.4975 5.29543 14.635C5.4471 14.7083 5.52627 14.825 5.54293 14.9267L5.69127 15.8192C5.8171 16.5725 6.46877 17.125 7.23293 17.125H8.7696C9.53293 17.125 10.1854 16.5725 10.3113 15.8192L10.4596 14.9258C10.4763 14.8258 10.5546 14.7092 10.7071 14.635C10.9938 14.4975 11.2679 14.3383 11.5279 14.16C11.6671 14.065 11.8071 14.0558 11.9029 14.0917L12.7529 14.41C13.0992 14.5394 13.4801 14.5418 13.828 14.4168C14.1758 14.2919 14.4681 14.0476 14.6529 13.7275L15.4221 12.3967C15.607 12.0764 15.6723 11.7009 15.6064 11.3369C15.5405 10.973 15.3476 10.6443 15.0621 10.4092L14.3621 9.8325C14.2829 9.7675 14.2204 9.64167 14.2338 9.47417C14.2575 9.15822 14.2575 8.84095 14.2338 8.525C14.2204 8.35833 14.2829 8.23167 14.3613 8.16667L15.0613 7.59C15.6513 7.105 15.8038 6.265 15.4221 5.6025L14.6538 4.27167C14.4688 3.95132 14.1761 3.707 13.8279 3.58218C13.4797 3.45735 13.0985 3.46013 12.7521 3.59L11.9021 3.90833C11.8071 3.94417 11.6671 3.93417 11.5279 3.83917C11.2668 3.66025 10.9924 3.50145 10.7071 3.36417C10.5546 3.29167 10.4763 3.175 10.4596 3.07417L10.3104 2.18083C10.2497 1.81589 10.0614 1.48435 9.77905 1.24522C9.49674 1.0061 9.13874 0.874907 8.76877 0.875H7.23293H7.2321ZM8.00043 12.125C8.82923 12.125 9.62409 11.7958 10.2101 11.2097C10.7962 10.6237 11.1254 9.8288 11.1254 9C11.1254 8.1712 10.7962 7.37634 10.2101 6.79029C9.62409 6.20424 8.82923 5.875 8.00043 5.875C7.17163 5.875 6.37678 6.20424 5.79072 6.79029C5.20467 7.37634 4.87543 8.1712 4.87543 9C4.87543 9.8288 5.20467 10.6237 5.79072 11.2097C6.37678 11.7958 7.17163 12.125 8.00043 12.125Z"
- fill="#989EA4"
- />
- </svg>
- );
-}
-
-export function DragSvg() {
- return (
<svg
width="6"
height="9"
@@ -32,66 +11,4 @@ export function DragSvg() {
d="M4.78829 0.916134C4.78348 0.920945 4.77696 0.923648 4.77015 0.923648C4.76335 0.923648 4.75682 0.920945 4.75201 0.916134C4.7472 0.911322 4.74449 0.904797 4.74449 0.897991C4.74449 0.891186 4.7472 0.884661 4.75201 0.879849C4.75682 0.875038 4.76335 0.872335 4.77015 0.872335C4.77696 0.872335 4.78348 0.875038 4.78829 0.879849C4.79311 0.884661 4.79581 0.891186 4.79581 0.897991C4.79581 0.904797 4.79311 0.911322 4.78829 0.916134ZM4.77015 0C4.53199 0 4.30358 0.0946096 4.13518 0.263016C3.96677 0.431421 3.87216 0.659829 3.87216 0.897991C3.87216 1.13615 3.96677 1.36456 4.13518 1.53297C4.30358 1.70137 4.53199 1.79598 4.77015 1.79598C5.00831 1.79598 5.23672 1.70137 5.40513 1.53297C5.57353 1.36456 5.66814 1.13615 5.66814 0.897991C5.66814 0.659829 5.57353 0.431421 5.40513 0.263016C5.23672 0.0946096 5.00831 0 4.77015 0ZM4.78829 4.40547C4.78348 4.41028 4.77696 4.41299 4.77015 4.41299C4.76335 4.41299 4.75682 4.41028 4.75201 4.40547C4.7472 4.40066 4.74449 4.39414 4.74449 4.38733C4.74449 4.38052 4.7472 4.374 4.75201 4.36919C4.75682 4.36438 4.76335 4.36167 4.77015 4.36167C4.77696 4.36167 4.78348 4.36438 4.78829 4.36919C4.79311 4.374 4.79581 4.38052 4.79581 4.38733C4.79581 4.39414 4.79311 4.40066 4.78829 4.40547ZM4.77015 3.48934C4.53199 3.48934 4.30358 3.58395 4.13518 3.75235C3.96677 3.92076 3.87216 4.14917 3.87216 4.38733C3.87216 4.62549 3.96677 4.8539 4.13518 5.02231C4.30358 5.19071 4.53199 5.28532 4.77015 5.28532C5.00831 5.28532 5.23672 5.19071 5.40513 5.02231C5.57353 4.8539 5.66814 4.62549 5.66814 4.38733C5.66814 4.14917 5.57353 3.92076 5.40513 3.75235C5.23672 3.58395 5.00831 3.48934 4.77015 3.48934ZM4.78829 7.89481C4.78348 7.89962 4.77696 7.90232 4.77015 7.90232C4.76335 7.90232 4.75682 7.89962 4.75201 7.89481C4.7472 7.89 4.74449 7.88347 4.74449 7.87667C4.74449 7.86986 4.7472 7.86334 4.75201 7.85853C4.75682 7.85371 4.76335 7.85101 4.77015 7.85101C4.77696 7.85101 4.78348 7.85371 4.78829 7.85853C4.79311 7.86334 4.79581 7.86986 4.79581 7.87667C4.79581 7.88347 4.79311 7.89 4.78829 7.89481ZM4.77015 6.97868C4.53199 6.97868 4.30358 7.07329 4.13518 7.24169C3.96677 7.4101 3.87216 7.63851 3.87216 7.87667C3.87216 8.11483 3.96677 8.34324 4.13518 8.51164C4.30358 8.68005 4.53199 8.77466 4.77015 8.77466C5.00831 8.77466 5.23672 8.68005 5.40513 8.51164C5.57353 8.34324 5.66814 8.11483 5.66814 7.87667C5.66814 7.63851 5.57353 7.4101 5.40513 7.24169C5.23672 7.07329 5.00831 6.97868 4.77015 6.97868ZM0.916134 0.91702C0.911322 0.921832 0.904796 0.924535 0.897991 0.924535C0.891187 0.924535 0.884661 0.921832 0.879849 0.91702C0.875038 0.912209 0.872335 0.905683 0.872335 0.898878C0.872335 0.892073 0.875038 0.885547 0.879849 0.880736C0.884661 0.875924 0.891187 0.873221 0.897991 0.873221C0.904796 0.873221 0.911322 0.875924 0.916134 0.880736C0.920945 0.885547 0.923648 0.892073 0.923648 0.898878C0.923648 0.905683 0.920945 0.912209 0.916134 0.91702ZM0.897991 0.000886679C0.659829 0.000886679 0.431422 0.0954962 0.263016 0.263902C0.0946102 0.432308 0 0.660715 0 0.898878C0 1.13704 0.0946102 1.36545 0.263016 1.53385C0.431422 1.70226 0.659829 1.79687 0.897991 1.79687C1.13615 1.79687 1.36456 1.70226 1.53297 1.53385C1.70137 1.36545 1.79598 1.13704 1.79598 0.898878C1.79598 0.660715 1.70137 0.432308 1.53297 0.263902C1.36456 0.0954962 1.13615 0.000886679 0.897991 0.000886679ZM0.916134 4.40636C0.911323 4.41117 0.904797 4.41387 0.897991 4.41387C0.891186 4.41387 0.88466 4.41117 0.879849 4.40636C0.875038 4.40155 0.872335 4.39502 0.872335 4.38822C0.872335 4.38141 0.875038 4.37489 0.879849 4.37007C0.88466 4.36526 0.891186 4.36256 0.897991 4.36256C0.904797 4.36256 0.911323 4.36526 0.916134 4.37007C0.920945 4.37489 0.923648 4.38141 0.923648 4.38822C0.923648 4.39502 0.920945 4.40155 0.916134 4.40636ZM0.897991 3.49022C0.659828 3.49022 0.431421 3.58484 0.263016 3.75324C0.0946104 3.92165 0 4.15005 0 4.38822C0 4.62638 0.0946104 4.85479 0.263016 5.02319C0.431421 5.1916 0.659828 5.28621 0.897991 5.28621C1.13615 5.28621 1.36456 5.1916 1.53297 5.02319C1.70137 4.85479 1.79598 4.62638 1.79598 4.38822C1.79598 4.15005 1.70137 3.92165 1.53297 3.75324C1.36456 3.58484 1.13615 3.49022 0.897991 3.49022ZM0.916134 7.8957C0.911322 7.90051 0.904795 7.90321 0.897991 7.90321C0.891187 7.90321 0.884661 7.90051 0.879849 7.8957C0.875038 7.89089 0.872335 7.88436 0.872335 7.87755C0.872335 7.87075 0.875038 7.86422 0.879849 7.85941C0.884661 7.8546 0.891187 7.8519 0.897991 7.8519C0.904795 7.8519 0.911322 7.8546 0.916134 7.85941C0.920945 7.86422 0.923648 7.87075 0.923648 7.87755C0.923648 7.88436 0.920945 7.89089 0.916134 7.8957ZM0.897991 6.97956C0.65983 6.97956 0.431422 7.07417 0.263016 7.24258C0.0946099 7.41098 0 7.63939 0 7.87755C0 8.11572 0.0946099 8.34412 0.263016 8.51253C0.431422 8.68094 0.65983 8.77555 0.897991 8.77555C1.13615 8.77555 1.36456 8.68094 1.53297 8.51253C1.70137 8.34412 1.79598 8.11572 1.79598 7.87755C1.79598 7.63939 1.70137 7.41098 1.53297 7.24258C1.36456 7.07417 1.13615 6.97956 0.897991 6.97956Z"
fill="#989EA4"
/>
- </svg>
- );
-}
-
-export function TextLoadingSvg() {
- return (
- <svg
- width="34"
- height="24"
- viewBox="0 0 14 10"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M0.8125 1.0625H13.1875M0.8125 5H13.1875M0.8125 8.9375H7"
- stroke="#989EA4"
- stroke-width="1.5"
- stroke-linecap="round"
- stroke-linejoin="round"
- />
- </svg>
- );
-}
-
-export function ThreeDBlock() {
- return (
- <svg
- width="32"
- height="36"
- viewBox="0 0 16 18"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M14.75 5.625L8 1.6875L1.25 5.625M14.75 5.625L8 9.5625M14.75 5.625V12.375L8 16.3125M1.25 5.625L8 9.5625M1.25 5.625V12.375L8 16.3125M8 9.5625V16.3125"
- stroke="#989EA4"
- stroke-width="1.5"
- stroke-linecap="round"
- stroke-linejoin="round"
- />
- </svg>
- );
-}
-
-export function LinkSvg() {
- return (
- <svg
- width="36"
- height="36"
- viewBox="0 0 18 18"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M9.89252 6.51602C10.3799 6.74871 10.8043 7.09497 11.1301 7.5257C11.4559 7.95643 11.6736 8.45906 11.7648 8.99136C11.8561 9.52366 11.8183 10.0701 11.6546 10.5848C11.4909 11.0994 11.206 11.5673 10.824 11.949L7.44902 15.324C6.81608 15.957 5.95763 16.3125 5.06252 16.3125C4.16741 16.3125 3.30896 15.957 2.67602 15.324C2.04308 14.6911 1.6875 13.8326 1.6875 12.9375C1.6875 12.0424 2.04308 11.184 2.67602 10.551L3.99377 9.23327M14.0063 8.76677L15.324 7.44902C15.957 6.81608 16.3125 5.95763 16.3125 5.06252C16.3125 4.16741 15.957 3.30896 15.324 2.67602C14.6911 2.04308 13.8326 1.6875 12.9375 1.6875C12.0424 1.6875 11.184 2.04308 10.551 2.67602L7.17602 6.05102C6.794 6.43277 6.50917 6.90063 6.34546 7.41529C6.18175 7.92995 6.14393 8.47638 6.2352 9.00868C6.32646 9.54098 6.54414 10.0436 6.86994 10.4743C7.19574 10.9051 7.62015 11.2513 8.10752 11.484"
- stroke="#989EA4"
- stroke-width="1.5"
- stroke-linecap="round"
- stroke-linejoin="round"
- />
- </svg>
- );
-}
+ </svg> \ No newline at end of file
diff --git a/packages/ui/icons/index.ts b/packages/ui/icons/index.ts
index 7788c20f..88d4ebc0 100644
--- a/packages/ui/icons/index.ts
+++ b/packages/ui/icons/index.ts
@@ -8,6 +8,13 @@ import SelectIcon from "./select.svg";
import SearchIcon from "./search.svg";
import NextIcon from "./nextarrow.svg";
import UrlIcon from "./url.svg";
+import CanvasIcon from "./canvas.svg";
+import blockIcon from "./block.svg";
+import LinkIcon from "./link.svg";
+import AutocompleteIcon from "./autocomplete.svg";
+import BlockIcon from "./block.svg";
+import DragIcon from "./drag.svg";
+import SettingsIcon from "./settings.svg";
export {
AddIcon,
@@ -19,5 +26,12 @@ export {
SelectIcon,
SearchIcon,
NextIcon,
- UrlIcon
+ UrlIcon,
+ CanvasIcon,
+ blockIcon,
+ LinkIcon,
+ AutocompleteIcon,
+ BlockIcon,
+ DragIcon,
+ SettingsIcon
};
diff --git a/packages/ui/icons/link.svg b/packages/ui/icons/link.svg
new file mode 100644
index 00000000..25e2d04e
--- /dev/null
+++ b/packages/ui/icons/link.svg
@@ -0,0 +1,15 @@
+ <svg
+ width="36"
+ height="36"
+ viewBox="0 0 18 18"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M9.89252 6.51602C10.3799 6.74871 10.8043 7.09497 11.1301 7.5257C11.4559 7.95643 11.6736 8.45906 11.7648 8.99136C11.8561 9.52366 11.8183 10.0701 11.6546 10.5848C11.4909 11.0994 11.206 11.5673 10.824 11.949L7.44902 15.324C6.81608 15.957 5.95763 16.3125 5.06252 16.3125C4.16741 16.3125 3.30896 15.957 2.67602 15.324C2.04308 14.6911 1.6875 13.8326 1.6875 12.9375C1.6875 12.0424 2.04308 11.184 2.67602 10.551L3.99377 9.23327M14.0063 8.76677L15.324 7.44902C15.957 6.81608 16.3125 5.95763 16.3125 5.06252C16.3125 4.16741 15.957 3.30896 15.324 2.67602C14.6911 2.04308 13.8326 1.6875 12.9375 1.6875C12.0424 1.6875 11.184 2.04308 10.551 2.67602L7.17602 6.05102C6.794 6.43277 6.50917 6.90063 6.34546 7.41529C6.18175 7.92995 6.14393 8.47638 6.2352 9.00868C6.32646 9.54098 6.54414 10.0436 6.86994 10.4743C7.19574 10.9051 7.62015 11.2513 8.10752 11.484"
+ stroke="#989EA4"
+ stroke-width="1.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ />
+ </svg> \ No newline at end of file
diff --git a/packages/ui/icons/settings.svg b/packages/ui/icons/settings.svg
new file mode 100644
index 00000000..2059b976
--- /dev/null
+++ b/packages/ui/icons/settings.svg
@@ -0,0 +1,14 @@
+ <svg
+ width="16"
+ height="18"
+ viewBox="0 0 16 18"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M7.2321 0.875C6.46793 0.875 5.81627 1.4275 5.69043 2.18083L5.5421 3.07417C5.52543 3.17417 5.44627 3.29083 5.2946 3.36417C5.00906 3.50143 4.73438 3.66022 4.47293 3.83917C4.3346 3.935 4.1946 3.94417 4.09793 3.90833L3.25043 3.59C2.90397 3.4602 2.52268 3.45755 2.17445 3.58253C1.82621 3.70751 1.53362 3.95201 1.34877 4.2725L0.580434 5.60333C0.395508 5.92363 0.330196 6.29915 0.396115 6.66307C0.462034 7.027 0.65491 7.35575 0.940434 7.59083L1.64043 8.1675C1.7196 8.2325 1.7821 8.35833 1.76877 8.52583C1.74502 8.84178 1.74502 9.15906 1.76877 9.475C1.78127 9.64167 1.7196 9.76833 1.64127 9.83333L0.940434 10.41C0.65491 10.6451 0.462034 10.9738 0.396115 11.3378C0.330196 11.7017 0.395508 12.0772 0.580434 12.3975L1.34877 13.7283C1.53376 14.0487 1.8264 14.293 2.17462 14.4178C2.52285 14.5426 2.90406 14.5399 3.25043 14.41L4.0996 14.0917C4.19543 14.0558 4.33543 14.0658 4.4746 14.16C4.7346 14.3383 5.00877 14.4975 5.29543 14.635C5.4471 14.7083 5.52627 14.825 5.54293 14.9267L5.69127 15.8192C5.8171 16.5725 6.46877 17.125 7.23293 17.125H8.7696C9.53293 17.125 10.1854 16.5725 10.3113 15.8192L10.4596 14.9258C10.4763 14.8258 10.5546 14.7092 10.7071 14.635C10.9938 14.4975 11.2679 14.3383 11.5279 14.16C11.6671 14.065 11.8071 14.0558 11.9029 14.0917L12.7529 14.41C13.0992 14.5394 13.4801 14.5418 13.828 14.4168C14.1758 14.2919 14.4681 14.0476 14.6529 13.7275L15.4221 12.3967C15.607 12.0764 15.6723 11.7009 15.6064 11.3369C15.5405 10.973 15.3476 10.6443 15.0621 10.4092L14.3621 9.8325C14.2829 9.7675 14.2204 9.64167 14.2338 9.47417C14.2575 9.15822 14.2575 8.84095 14.2338 8.525C14.2204 8.35833 14.2829 8.23167 14.3613 8.16667L15.0613 7.59C15.6513 7.105 15.8038 6.265 15.4221 5.6025L14.6538 4.27167C14.4688 3.95132 14.1761 3.707 13.8279 3.58218C13.4797 3.45735 13.0985 3.46013 12.7521 3.59L11.9021 3.90833C11.8071 3.94417 11.6671 3.93417 11.5279 3.83917C11.2668 3.66025 10.9924 3.50145 10.7071 3.36417C10.5546 3.29167 10.4763 3.175 10.4596 3.07417L10.3104 2.18083C10.2497 1.81589 10.0614 1.48435 9.77905 1.24522C9.49674 1.0061 9.13874 0.874907 8.76877 0.875H7.23293H7.2321ZM8.00043 12.125C8.82923 12.125 9.62409 11.7958 10.2101 11.2097C10.7962 10.6237 11.1254 9.8288 11.1254 9C11.1254 8.1712 10.7962 7.37634 10.2101 6.79029C9.62409 6.20424 8.82923 5.875 8.00043 5.875C7.17163 5.875 6.37678 6.20424 5.79072 6.79029C5.20467 7.37634 4.87543 8.1712 4.87543 9C4.87543 9.8288 5.20467 10.6237 5.79072 11.2097C6.37678 11.7958 7.17163 12.125 8.00043 12.125Z"
+ fill="#989EA4"
+ />
+ </svg> \ No newline at end of file