This commit is contained in:
cdricms
2025-02-20 19:45:11 +01:00
parent 07c632dafe
commit 5bdfc9ce06
9 changed files with 1554 additions and 3092 deletions

View File

@@ -1,5 +1,4 @@
"use client"; "use client";
import { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import useApiMutation from "@/hooks/use-api"; import useApiMutation from "@/hooks/use-api";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
@@ -16,13 +15,13 @@ export default function BlogEditor() {
isSuccess, isSuccess,
} = useApiMutation("/blog/new", undefined, "POST", false, true); } = useApiMutation("/blog/new", undefined, "POST", false, true);
const content = localStorage.getItem("blog_draft") ?? "";
return ( return (
<section className="m-10"> <section className="m-10">
<div className="flex"> <div className="flex">
<div className="flex-1"> <div className="flex-1">
<Editor <Editor content={content} />
markdown={localStorage.getItem("blog_draft") ?? ""}
/>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,3 @@
@import "../node_modules/@mdxeditor/editor/dist/style.css";
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;

View File

@@ -0,0 +1,630 @@
"use client";
import type { Editor } from "@tiptap/react";
import {
AlignCenter,
AlignJustifyIcon,
AlignLeft,
AlignRight,
Bold,
Code,
Code2,
Heading1,
Heading2,
Heading3,
ImageIcon,
Italic,
LinkIcon,
List,
ListOrdered,
Minus,
Pilcrow,
Quote,
Strikethrough,
Underline,
X,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Level } from "@tiptap/extension-heading";
import { Separator } from "@/components/ui/separator";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { Label } from "./ui/label";
import { Input } from "./ui/input";
import { Switch } from "./ui/switch";
import { useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "./ui/dialog";
interface EditorMenuProps {
editor: Editor | null;
}
export function EditorMenu({ editor }: EditorMenuProps) {
if (!editor) {
return null;
}
return (
<TooltipProvider delayDuration={0}>
<div className="flex flex-wrap gap-2 rounded-t-lg border bg-background p-1">
<div className="flex flex-wrap gap-2">
<ToggleGroup
type="multiple"
size="sm"
className="flex flex-wrap gap-1"
>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="bold"
aria-label="Toggle bold"
aria-selected={editor.isActive("bold")}
onClick={() =>
editor
.chain()
.focus()
.toggleBold()
.run()
}
>
<Bold className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Bold</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="italic"
aria-label="Toggle italic"
aria-selected={editor.isActive("italic")}
onClick={() =>
editor
.chain()
.focus()
.toggleItalic()
.run()
}
>
<Italic className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Italic</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="underline"
aria-label="Toggle underline"
aria-selected={editor.isActive("underline")}
onClick={() =>
editor
.chain()
.focus()
.toggleUnderline()
.run()
}
>
<Underline className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Underline</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="strike"
aria-label="Toggle strikethrough"
aria-selected={editor.isActive("strike")}
onClick={() =>
editor
.chain()
.focus()
.toggleStrike()
.run()
}
>
<Strikethrough className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Strikethrough</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="code"
aria-label="Toggle code"
aria-selected={editor.isActive("code")}
onClick={() =>
editor
.chain()
.focus()
.toggleCode()
.run()
}
>
<Code className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Code</TooltipContent>
</Tooltip>
</ToggleGroup>
<Separator orientation="vertical" className="h-8" />
<Select
value={getActiveHeading(editor)}
onValueChange={(value) => {
if (value === "paragraph") {
editor.chain().focus().setParagraph().run();
} else {
editor
.chain()
.focus()
.toggleHeading({
level: Number.parseInt(value) as Level,
})
.run();
}
}}
>
<SelectTrigger className="h-8 w-[130px]">
<SelectValue placeholder="Paragraph" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="paragraph">
<div className="flex items-center gap-2">
<Pilcrow className="h-4 w-4" />
<span>Paragraph</span>
</div>
</SelectItem>
<SelectItem value="1">
<div className="flex items-center gap-2">
<Heading1 className="h-4 w-4" />
<span>Heading 1</span>
</div>
</SelectItem>
<SelectItem value="2">
<div className="flex items-center gap-2">
<Heading2 className="h-4 w-4" />
<span>Heading 2</span>
</div>
</SelectItem>
<SelectItem value="3">
<div className="flex items-center gap-2">
<Heading3 className="h-4 w-4" />
<span>Heading 3</span>
</div>
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Separator orientation="vertical" className="h-8" />
<ToggleGroup
type="single"
size="sm"
className="flex flex-wrap gap-1"
>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="left"
aria-label="Align left"
aria-selected={editor.isActive({
textAlign: "left",
})}
onClick={() =>
editor
.chain()
.focus()
.setTextAlign("left")
.run()
}
>
<AlignLeft className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Align left</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="center"
aria-label="Align center"
aria-selected={editor.isActive({
textAlign: "center",
})}
onClick={() =>
editor
.chain()
.focus()
.setTextAlign("center")
.run()
}
>
<AlignCenter className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Align center</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="right"
aria-label="Align right"
aria-selected={editor.isActive({
textAlign: "right",
})}
onClick={() =>
editor
.chain()
.focus()
.setTextAlign("right")
.run()
}
>
<AlignRight className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Align right</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="justify"
aria-label="Justify"
aria-selected={editor.isActive({
textAlign: "justify",
})}
onClick={() =>
editor
.chain()
.focus()
.setTextAlign("justify")
.run()
}
>
<AlignJustifyIcon className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Align justify</TooltipContent>
</Tooltip>
</ToggleGroup>
<Separator orientation="vertical" className="h-8" />
<ToggleGroup
type="multiple"
size="sm"
className="flex flex-wrap gap-1"
>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="bulletList"
aria-label="Toggle bullet list"
aria-selected={editor.isActive(
"bulletList",
)}
onClick={() =>
editor
.chain()
.focus()
.toggleBulletList()
.run()
}
>
<List className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Bullet list</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="orderedList"
aria-label="Toggle ordered list"
aria-selected={editor.isActive(
"orderedList",
)}
onClick={() =>
editor
.chain()
.focus()
.toggleOrderedList()
.run()
}
>
<ListOrdered className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Ordered list</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="codeBlock"
aria-label="Toggle code block"
pressed={editor.isActive("codeBlock")}
onPressedChanged={() =>
editor
.chain()
.focus()
.toggleCodeBlock()
.run()
}
>
<Code2 className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Code block</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ToggleGroupItem
value="blockquote"
aria-label="Toggle blockquote"
aria-selected={editor.isActive(
"blockquote",
)}
onClick={() =>
editor
.chain()
.focus()
.toggleBlockquote()
.run()
}
>
<Quote className="h-4 w-4" />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent>Blockquote</TooltipContent>
</Tooltip>
</ToggleGroup>
<Separator orientation="vertical" className="h-8" />
<div className="flex gap-1">
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={() =>
editor
.chain()
.focus()
.setHorizontalRule()
.run()
}
>
<Minus className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Horizontal rule</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={() =>
editor
.chain()
.focus()
.clearNodes()
.unsetAllMarks()
.run()
}
>
<X className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Clear formatting</TooltipContent>
</Tooltip>
<Separator orientation="vertical" className="h-8" />
<Tooltip>
<TooltipTrigger asChild>
<LinkPopover editor={editor} />
</TooltipTrigger>
<TooltipContent>Add link</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<ImageDialog editor={editor} />
</TooltipTrigger>
<TooltipContent>Add image</TooltipContent>
</Tooltip>
</div>
</div>
</div>
</TooltipProvider>
);
}
function getActiveHeading(editor: Editor) {
if (editor.isActive("heading", { level: 1 })) return "1";
if (editor.isActive("heading", { level: 2 })) return "2";
if (editor.isActive("heading", { level: 3 })) return "3";
return "paragraph";
}
const LinkPopover: React.FC<{ editor: Editor }> = ({ editor }) => {
const [linkUrl, setLinkUrl] = useState("");
const [linkNewTab, setLinkNewTab] = useState(false);
const [isLinkOpen, setIsLinkOpen] = useState(false);
const setLink = () => {
if (linkUrl) {
editor
.chain()
.focus()
.setLink({
href: linkUrl,
target: linkNewTab ? "_blank" : null,
})
.run();
} else {
editor.chain().focus().unsetLink().run();
}
setIsLinkOpen(false);
setLinkUrl("");
setLinkNewTab(false);
};
return (
<Popover open={isLinkOpen} onOpenChange={setIsLinkOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
size="sm"
className={editor.isActive("link") ? "bg-accent" : ""}
>
<LinkIcon className="h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-80">
<div className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="link">Link URL</Label>
<Input
id="link"
value={linkUrl}
onChange={(e) => setLinkUrl(e.target.value)}
placeholder="https://example.com"
/>
</div>
<div className="flex items-center space-x-2">
<Switch
id="new-tab"
checked={linkNewTab}
onCheckedChange={setLinkNewTab}
/>
<Label htmlFor="new-tab">Open in new tab</Label>
</div>
<div className="flex gap-2">
<Button onClick={setLink} className="flex-1">
Save
</Button>
{editor.isActive("link") && (
<Button
variant="outline"
onClick={() => {
editor.chain().focus().unsetLink().run();
setIsLinkOpen(false);
}}
>
Remove
</Button>
)}
</div>
</div>
</PopoverContent>
</Popover>
);
};
const ImageDialog: React.FC<{ editor: Editor }> = ({ editor }) => {
const [isImageOpen, setIsImageOpen] = useState(false);
const [imageUrl, setImageUrl] = useState("");
const [imageAlt, setImageAlt] = useState("");
const addImage = () => {
if (imageUrl) {
editor
.chain()
.focus()
.setImage({
src: imageUrl,
alt: imageAlt,
})
.run();
}
setIsImageOpen(false);
setImageUrl("");
setImageAlt("");
};
return (
<Dialog open={isImageOpen} onOpenChange={setIsImageOpen}>
<Button
variant="outline"
size="sm"
onClick={() => setIsImageOpen(true)}
>
<ImageIcon className="h-4 w-4" />
</Button>
<DialogContent>
<DialogHeader>
<DialogTitle>Add image</DialogTitle>
<DialogDescription>
Insert an image by providing its URL and alt text.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid gap-2">
<Label htmlFor="image-url">Image URL</Label>
<Input
id="image-url"
value={imageUrl}
onChange={(e) => setImageUrl(e.target.value)}
placeholder="https://example.com/image.jpg"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="image-alt">Alt text</Label>
<Input
id="image-alt"
value={imageAlt}
onChange={(e) => setImageAlt(e.target.value)}
placeholder="Description of the image"
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setIsImageOpen(false)}
>
Cancel
</Button>
<Button onClick={addImage}>Add image</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

View File

@@ -1,73 +1,65 @@
"use client"; "use client";
import * as React from "react"; import * as React from "react";
import {
MDXEditor,
headingsPlugin,
listsPlugin,
quotePlugin,
thematicBreakPlugin,
markdownShortcutPlugin,
toolbarPlugin,
linkPlugin,
linkDialogPlugin,
type MDXEditorMethods,
KitchenSinkToolbar,
tablePlugin,
imagePlugin,
frontmatterPlugin,
codeBlockPlugin,
directivesPlugin,
AdmonitionDirectiveDescriptor,
} from "@mdxeditor/editor";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Underline from "@tiptap/extension-underline";
import Link from "@tiptap/extension-link";
import TTImage from "@tiptap/extension-image";
import TextAlign from "@tiptap/extension-text-align";
import Youtube from "@tiptap/extension-youtube";
import Dropcursor from "@tiptap/extension-dropcursor";
import { EditorMenu } from "./editor-menu";
interface EditorProps { interface EditorProps {
markdown: string; content: string;
onChange?: (markdown: string) => void; onChange?: (markdown: string) => void;
className?: string; className?: string;
} }
export function Editor({ markdown, onChange, className }: EditorProps) { export function Editor({ content, onChange, className }: EditorProps) {
const ref = React.useRef<MDXEditorMethods>(null); const editor = useEditor({
extensions: [
StarterKit,
Underline,
Link,
Youtube,
Dropcursor,
TTImage.configure({
HTMLAttributes: {
class: "max-w-full w-auto h-auto resize overflow-auto",
},
}),
TextAlign.configure({
alignments: ["left", "center", "right", "justify"],
defaultAlignment: "justify",
types: ["heading", "paragraph"],
}),
],
content,
immediatelyRender: false,
editorProps: {
attributes: {
class: "prose prose-sm sm:prose-base lg:prose-lg xl:prose-2xl m-5 focus:outline-none dark:prose-invert",
},
},
onUpdate: ({ editor }) => {
console.log("Update");
localStorage.setItem("blog_draft", editor.getHTML());
},
});
const onChangeDebounce = (content: string) => { if (!editor) {
localStorage.setItem("blog_draft", content); return null;
}; }
return ( return (
<Card className={cn("border rounded-lg overflow-hidden", className)}> <Card className={cn("border rounded-lg overflow-hidden", className)}>
<MDXEditor <EditorMenu editor={editor} />
ref={ref} <EditorContent editor={editor} />
className="mdx-editor dark-theme dark-editor prose dark:prose-invert p-4"
markdown={markdown}
onChange={onChangeDebounce}
spellCheck
plugins={[
toolbarPlugin({
toolbarContents: () => <KitchenSinkToolbar />,
}),
listsPlugin(),
quotePlugin(),
headingsPlugin(),
linkPlugin(),
linkDialogPlugin(),
// eslint-disable-next-line @typescript-eslint/require-await
imagePlugin({
imageUploadHandler: async () => "/sample-image.png",
}),
tablePlugin(),
thematicBreakPlugin(),
frontmatterPlugin(),
codeBlockPlugin({ defaultCodeBlockLanguage: "txt" }),
directivesPlugin({
directiveDescriptors: [AdmonitionDirectiveDescriptor],
}),
markdownShortcutPlugin(),
]}
/>
</Card> </Card>
); );
} }

View File

@@ -0,0 +1,61 @@
"use client";
import * as React from "react";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import { type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { toggleVariants } from "@/components/ui/toggle";
const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants>
>({
size: "default",
variant: "default",
});
const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center justify-center gap-1", className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
));
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext);
return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
}),
className,
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
);
});
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
export { ToggleGroup, ToggleGroupItem };

View File

@@ -0,0 +1,45 @@
"use client";
import * as React from "react";
import * as TogglePrimitive from "@radix-ui/react-toggle";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-2 min-w-9",
sm: "h-8 px-1.5 min-w-8",
lg: "h-10 px-2.5 min-w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
));
Toggle.displayName = TogglePrimitive.Root.displayName;
export { Toggle, toggleVariants };

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,6 @@
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^3.10.0", "@hookform/resolvers": "^3.10.0",
"@mdxeditor/editor": "^3.23.2",
"@radix-ui/react-accordion": "^1.2.2", "@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-checkbox": "^1.1.3",
@@ -27,6 +26,8 @@
"@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-toast": "^1.2.6", "@radix-ui/react-toast": "^1.2.6",
"@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.6", "@radix-ui/react-tooltip": "^1.1.6",
"@schedule-x/drag-and-drop": "^2.15.1", "@schedule-x/drag-and-drop": "^2.15.1",
"@schedule-x/event-modal": "^2.15.1", "@schedule-x/event-modal": "^2.15.1",
@@ -37,6 +38,14 @@
"@schedule-x/theme-default": "^2.14.3", "@schedule-x/theme-default": "^2.14.3",
"@schedule-x/theme-shadcn": "^2.14.3", "@schedule-x/theme-shadcn": "^2.14.3",
"@tailwindcss/typography": "^0.5.16", "@tailwindcss/typography": "^0.5.16",
"@tiptap/extension-image": "^2.11.5",
"@tiptap/extension-link": "^2.11.5",
"@tiptap/extension-text-align": "^2.11.5",
"@tiptap/extension-underline": "^2.11.5",
"@tiptap/extension-youtube": "^2.11.5",
"@tiptap/pm": "^2.11.5",
"@tiptap/react": "^2.11.5",
"@tiptap/starter-kit": "^2.11.5",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cookies-next": "^5.1.0", "cookies-next": "^5.1.0",

View File

@@ -1,81 +1,5 @@
import type { Config } from "tailwindcss"; import type { Config } from "tailwindcss";
import { slate, blue, blueDark, slateDark, pink } from "@radix-ui/colors";
const accent = {
base: blue.blue1,
bgSubtle: blue.blue2,
bg: blue.blue3,
bgHover: blue.blue4,
bgActive: blue.blue5,
line: blue.blue6,
border: blue.blue7,
borderHover: blue.blue8,
solid: blue.blue9,
solidHover: blue.blue10,
text: blue.blue11,
textContrast: blue.blue12,
};
const secondary = {
base: pink.pink1,
bgSubtle: pink.pink2,
bg: pink.pink3,
bgHover: pink.pink4,
bgActive: pink.pink5,
line: pink.pink6,
border: pink.pink7,
borderHover: pink.pink8,
solid: pink.pink9,
solidHover: pink.pink10,
text: pink.pink11,
textContrast: pink.pink12,
};
const neutral = {
base: slate.slate1,
bgSubtle: slate.slate2,
bg: slate.slate3,
bgHover: slate.slate4,
bgActive: slate.slate5,
line: slate.slate6,
border: slate.slate7,
borderHover: slate.slate8,
solid: slate.slate9,
solidHover: slate.slate10,
text: slate.slate11,
textContrast: slate.slate12,
};
const darkAccent = {
base: blueDark.blue1,
bgSubtle: blueDark.blue2,
bg: blueDark.blue3,
bgHover: blueDark.blue4,
bgActive: blueDark.blue5,
line: blueDark.blue6,
border: blueDark.blue7,
borderHover: blueDark.blue8,
solid: blueDark.blue9,
solidHover: blueDark.blue10,
text: blueDark.blue11,
textContrast: blueDark.blue12,
};
const darkNeutral = {
base: slateDark.slate1,
bgSubtle: slateDark.slate2,
bg: slateDark.slate3,
bgHover: slateDark.slate4,
bgActive: slateDark.slate5,
line: slateDark.slate6,
border: slateDark.slate7,
borderHover: slateDark.slate8,
solid: slateDark.slate9,
solidHover: slateDark.slate10,
text: slateDark.slate11,
textContrast: slateDark.slate12,
};
export default { export default {
darkMode: ["class"], darkMode: ["class"],
content: [ content: [
@@ -89,9 +13,6 @@ export default {
times: ["Times New Roman", "Times", "serif"], times: ["Times New Roman", "Times", "serif"],
}, },
colors: { colors: {
neutral,
darkAccent,
darkNeutral,
background: "hsl(var(--background))", background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))", foreground: "hsl(var(--foreground))",
card: { card: {
@@ -107,7 +28,6 @@ export default {
foreground: "hsl(var(--primary-foreground))", foreground: "hsl(var(--primary-foreground))",
}, },
secondary: { secondary: {
...secondary,
DEFAULT: "hsl(var(--secondary))", DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))", foreground: "hsl(var(--secondary-foreground))",
}, },
@@ -116,7 +36,6 @@ export default {
foreground: "hsl(var(--muted-foreground))", foreground: "hsl(var(--muted-foreground))",
}, },
accent: { accent: {
...accent,
DEFAULT: "hsl(var(--accent))", DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))", foreground: "hsl(var(--accent-foreground))",
}, },