diff --git a/components/ArticleSearch/SearchBar.tsx b/components/ArticleSearch/SearchBar.tsx deleted file mode 100644 index b042bbff..00000000 --- a/components/ArticleSearch/SearchBar.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, { useState, useEffect } from "react"; - -interface Props { - searchTerm: string; - setSearchTerm: React.Dispatch>; -} - -const SearchBar: React.FC = (props) => { - const { searchTerm, setSearchTerm } = props; - const [input, setInput] = useState(searchTerm); - - useEffect(() => { - const timer = setTimeout(() => { - setSearchTerm(input); - }, 500); // Debounce for 500 milliseconds - - return () => { - clearTimeout(timer); - }; - }, [input, setSearchTerm]); - - const handleInputChange = (e: React.ChangeEvent) => { - setInput(e.target.value); - }; - - return ( -
- - -
- ); -}; - -export default SearchBar; diff --git a/components/EditorHints/EditorHints.tsx b/components/EditorHints/EditorHints.tsx deleted file mode 100644 index 3452f92a..00000000 --- a/components/EditorHints/EditorHints.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Fragment, useState } from "react"; - -const EditorHints = () => { - const [visible, setVisible] = useState(true); - - return ( - - {visible && ( -
-
- -
- -
-

How to use the editor

-

- Your post remains private until you “publish” the article. -

-

- You can edit and format the main content of your article using - Markdown. If you have never used Markdown, you can check out{" "} - - this - {" "} - free guide on{" "} - - markdownguide - - . -

-
-
- )} -
- ); -}; - -export default EditorHints; diff --git a/components/ImageDetailsModal/ImageDetailsModal.tsx b/components/ImageDetailsModal/ImageDetailsModal.tsx deleted file mode 100644 index de6b028b..00000000 --- a/components/ImageDetailsModal/ImageDetailsModal.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import type { Dispatch, SetStateAction } from "react"; -import { useRef } from "react"; -import type { Editor } from "@tiptap/core"; -import { Modal } from "@/components/Modal/Modal"; -import { XIcon } from "lucide-react"; -import { z } from "zod"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { Description, DialogTitle } from "@headlessui/react"; - -const imageDetailsSchema = z.object({ - src: z - .string() - .trim() - .min(1, { message: "A URL is required." }) - .url({ message: "Must be a valid URL" }), - alt: z - .string() - .refine((value) => value !== "", { message: "An alt value is required" }), - title: z - .string() - .refine((value) => value !== "", { message: "A title is required" }), -}); - -type ImageDetailsSchema = z.infer; - -interface Props { - setIsImageDetailsModalOpen: Dispatch>; - isImageDetailsModalOpen: boolean; - editor?: Editor; -} - -export default function ImageDetailsModal(props: Props) { - const { isImageDetailsModalOpen, setIsImageDetailsModalOpen, editor } = props; - - const { - register, - handleSubmit, - formState: { errors, isSubmitting }, - reset, - } = useForm({ - resolver: zodResolver(imageDetailsSchema), - }); - - const onSubmit = (data: ImageDetailsSchema) => { - editor - ?.chain() - .focus() - .setImage({ src: data.src, alt: data.alt, title: data.title }) - .run(); - - reset(); - setIsImageDetailsModalOpen(false); - }; - - return ( - { - reset(); - setIsImageDetailsModalOpen(false); - }} - > - <> - - Image details - - - - Please enter a URL for the image, along with an alt description and a - title. - -
-
- - - {errors && ( -

- {errors.src?.message} -

- )} -
- -
- - - {errors && ( -

- {errors.alt?.message} -

- )} -
- -
- - - {errors && ( -

- {errors.title?.message} -

- )} -
- -
- -
- -
-
-
- -
- ); -} diff --git a/components/editor/editor/RenderPost.tsx b/components/editor/editor/RenderPost.tsx deleted file mode 100644 index c184e660..00000000 --- a/components/editor/editor/RenderPost.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import { TiptapExtensions } from "./extensions"; -import { EditorContent, useEditor } from "@tiptap/react"; -import SlashCommand from "./extensions/slash-command"; - -interface RenderPostProps { - json: string; -} - -const RenderPost = ({ json }: RenderPostProps) => { - const content = JSON.parse(json); - - const editor = useEditor({ - editable: false, - extensions: [...TiptapExtensions, SlashCommand], - content, - }); - - return ; -}; - -export default RenderPost; diff --git a/components/editor/editor/default-content.tsx b/components/editor/editor/default-content.tsx deleted file mode 100644 index d2759b14..00000000 --- a/components/editor/editor/default-content.tsx +++ /dev/null @@ -1,203 +0,0 @@ -const DEFAULT_EDITOR_CONTENT = { - type: "doc", - content: [ - { - type: "heading", - attrs: { level: 2 }, - content: [{ type: "text", text: "Introducing Novel" }], - }, - { - type: "paragraph", - content: [ - { - type: "text", - text: "Novel is a Notion-style WYSIWYG editor with AI-powered autocompletion. Built with ", - }, - { - type: "text", - marks: [ - { - type: "link", - attrs: { - href: "https://tiptap.dev/", - target: "_blank", - class: - "text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer", - }, - }, - ], - text: "Tiptap", - }, - { type: "text", text: " and " }, - { - type: "text", - marks: [ - { - type: "link", - attrs: { - href: "https://sdk.vercel.ai/docs", - target: "_blank", - class: - "text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer", - }, - }, - ], - text: "Vercel AI SDK", - }, - { type: "text", text: "." }, - ], - }, - { - 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", - }, - }, - { 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: "Check out the " }, - { - type: "text", - marks: [ - { - type: "link", - attrs: { - href: "https://twitter.com/steventey/status/1669762868416512000", - target: "_blank", - class: - "text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer", - }, - }, - ], - text: "launch video", - }, - ], - }, - ], - }, - { - 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", - class: - "text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer", - }, - }, - ], - text: "GitHub", - }, - ], - }, - ], - }, - { - 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", - class: - "text-stone-400 underline underline-offset-[3px] hover:text-stone-600 transition-colors cursor-pointer", - }, - }, - ], - text: "Deploy your own", - }, - { type: "text", text: " to Vercel" }, - ], - }, - ], - }, - ], - }, - ], -}; - -export default DEFAULT_EDITOR_CONTENT; diff --git a/components/editor/editor/extensions/update-youtube.ts b/components/editor/editor/extensions/update-youtube.ts deleted file mode 100644 index f8513964..00000000 --- a/components/editor/editor/extensions/update-youtube.ts +++ /dev/null @@ -1,18 +0,0 @@ -import Youtube from "@tiptap/extension-youtube"; - -const UpdatedYoutube = Youtube.extend({ - addAttributes() { - return { - ...this.parent?.(), - width: { - default: null, - }, - height: { - default: null, - }, - enableIFrameApi: "true", - }; - }, -}); - -export default UpdatedYoutube; diff --git a/components/editor/icons/font-default.tsx b/components/editor/icons/font-default.tsx deleted file mode 100644 index ac2a8a80..00000000 --- a/components/editor/icons/font-default.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export default function FontDefault({ className }: { className?: string }) { - return ( - - - - - ); -} diff --git a/components/editor/icons/font-mono.tsx b/components/editor/icons/font-mono.tsx deleted file mode 100644 index dbb0b4d3..00000000 --- a/components/editor/icons/font-mono.tsx +++ /dev/null @@ -1,21 +0,0 @@ -export default function FontMono({ className }: { className?: string }) { - return ( - - - - - ); -} diff --git a/components/editor/icons/font-serif.tsx b/components/editor/icons/font-serif.tsx deleted file mode 100644 index e1f60a4b..00000000 --- a/components/editor/icons/font-serif.tsx +++ /dev/null @@ -1,21 +0,0 @@ -export default function FontSerif({ className }: { className?: string }) { - return ( - - - - - ); -} diff --git a/components/editor/icons/github.tsx b/components/editor/icons/github.tsx deleted file mode 100644 index ff13f393..00000000 --- a/components/editor/icons/github.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export default function Github({ className }: { className?: string }) { - return ( - - - - ); -} diff --git a/components/editor/icons/index.tsx b/components/editor/icons/index.tsx deleted file mode 100644 index 5b284462..00000000 --- a/components/editor/icons/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export { default as FontDefault } from "./font-default"; -export { default as FontSerif } from "./font-serif"; -export { default as FontMono } from "./font-mono"; diff --git a/components/editor/icons/loading-circle.tsx b/components/editor/icons/loading-circle.tsx deleted file mode 100644 index 524d2abd..00000000 --- a/components/editor/icons/loading-circle.tsx +++ /dev/null @@ -1,22 +0,0 @@ -export default function LoadingCircle({ dimensions }: { dimensions?: string }) { - return ( - - ); -} diff --git a/components/editor/icons/magic.tsx b/components/editor/icons/magic.tsx deleted file mode 100644 index b50f7664..00000000 --- a/components/editor/icons/magic.tsx +++ /dev/null @@ -1,30 +0,0 @@ -export default function Magic({ className }: { className: string }) { - return ( - - - - - - ); -} diff --git a/components/editor/primitives/leaflet.tsx b/components/editor/primitives/leaflet.tsx deleted file mode 100644 index 3f58f15f..00000000 --- a/components/editor/primitives/leaflet.tsx +++ /dev/null @@ -1,87 +0,0 @@ -// "use client"; - -// @TODO Remove any with proper types... - -import { useEffect, useRef, useMemo } from "react"; -import type { ReactNode, SetStateAction, Dispatch } from "react"; -import { AnimatePresence, motion, useAnimation } from "framer-motion"; - -export default function Leaflet({ - setOpen, - children, -}: { - setOpen: Dispatch>; - children: ReactNode; -}) { - const leafletRef = useRef(null); - const controls = useAnimation(); - const transitionProps = useMemo(() => { - return { type: "spring", stiffness: 500, damping: 30 }; - }, []); - - useEffect(() => { - controls.start({ - y: 20, - transition: transitionProps, - }); - }, [controls, transitionProps]); - - async function handleDragEnd( - _: unknown, - info: { - offset: { - x: number; - y: number; - }; - velocity: { - x: number; - y: number; - }; - }, - ) { - const offset = info.offset.y; - const velocity = info.velocity.y; - const height = leafletRef.current?.getBoundingClientRect().height || 0; - if (offset > height / 2 || velocity > 800) { - await controls.start({ y: "100%", transition: transitionProps }); - setOpen(false); - } else { - controls.start({ y: 0, transition: transitionProps }); - } - } - - return ( - - -
-
-
-
- {children} - - setOpen(false)} - /> - - ); -} diff --git a/components/editor/primitives/popover.tsx b/components/editor/primitives/popover.tsx deleted file mode 100644 index 1ffafbea..00000000 --- a/components/editor/primitives/popover.tsx +++ /dev/null @@ -1,30 +0,0 @@ -// "use client"; - -import * as React from "react"; -import * as PopoverPrimitive from "@radix-ui/react-popover"; -import { cn } from "@/utils/utils"; - -const Popover = PopoverPrimitive.Root; - -const PopoverTrigger = PopoverPrimitive.Trigger; - -const PopoverContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( - - - -)); -PopoverContent.displayName = PopoverPrimitive.Content.displayName; - -export { Popover, PopoverTrigger, PopoverContent };