shadimage
d2
componentai-writing-assistancesource: ok · hit

AI Writing Assistant

AI writing assistant panel with assistant, blog and pro modes and a prompt field.

npx shadcn add "https://ui.d2studio.dev/r/ai-writing-assistance.json"
free

Where it goes

blog-list

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
iconslucide-react

Registry dependencies

buttondropdown-menu

Files1 · source cached 10/15/2026, 7:55:19 AM

registry/default/components/ai-writing-assistance.tsx
"use client"

import { ArrowUp, Command } from "lucide-react"
import {
    IconCircleCopyPlus,
    IconCloudUpload,
    IconFile,
    IconGearKeyhole,
    IconSparkle
} from "nucleo-glass"
import * as React from "react"

import { Button } from "@/components/ui/button"
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

export default function AIWritingAssistance() {
    const [content, setContent] = React.useState("")
    const [selectedAI, setSelectedAI] = React.useState("AI Assistant")
    const [selectedModel, setSelectedModel] = React.useState("Gemini Pro 3.1 (New)")

    const models = [
        { name: "Blog writing - Gemini Pro 3.1 (New)", value: "Gemini Pro 3.1 (New)" },
        { name: "Code writing - Claude Opus (New)", value: "Claude Opus (New)" },
        { name: "Chat gpt - 4.1 2B LLM", value: "GPT-4" },
    ]

    const aiOptions = ["AI Assistant", "AI Pro", "AI Blog"]

    return (
        <div className="flex flex-col items-center justify-center min-h-screen bg-[#0C0B0B] p-4 font-sans" style={{ fontFamily: '"Inter", sans-serif' }}>

            {/* Top Header Section */}
            <div className="flex flex-col items-center text-center gap-4 w-full mb-[60px]">
                <div className="flex items-center gap-3">
                    {/* Sparkle SVG matching the reference */}
                    <IconSparkle className="size-[34px] opacity-90" />
                    <h1 className="text-[40px] font-medium tracking-tight bg-gradient-to-b from-[#E3E3E3] to-[#A3A3A3] bg-clip-text text-transparent pb-1 whitespace-nowrap">
                        AI writing Assistant
                    </h1>
                </div>
                <p className="text-[#848484] text-[18px] font-normal leading-relaxed">
                    Transform your ideas into polish content with AI-powered writing tools.
                </p>
            </div>

            {/* Main Outer Box - Exactly 766px wide matching SVG */}
            <div className="w-full max-w-[766px] bg-[#202020] rounded-[32px] border border-[#343434] p-[8px] flex flex-col shadow-2xl relative">

                {/* Inner Content Area - 751px inner wrapper */}
                <div className="w-full bg-[#161616] rounded-[24px] border border-[#373737] flex flex-col pt-8 px-8 pb-6 relative shadow-inner overflow-hidden" style={{ minHeight: '270px', boxShadow: '0px 2px 2px 0px rgba(0, 0, 0, 0.12)' }}>

                    {/* Background Radial Gradient */}
                    <div
                        className="absolute inset-0 pointer-events-none"
                        style={{ background: 'radial-gradient(ellipse 130% 130% at 15% 0%, rgba(186, 186, 186, 0.15) 0%, rgba(0, 0, 0, 0) 100%)' }}
                    />

                    <div className="relative z-10 flex flex-col h-full">
                        {/* Header text mapped directly from reference */}
                        <div className="flex flex-col gap-1.5 mb-6">
                            <h2 className="text-white text-[22px] font-medium tracking-tight">
                                Structured Content Generator
                            </h2>
                            <p className="text-[#848484] text-[15px] font-normal">
                                Generate specific types of content with clear objectives and structured inputs
                            </p>
                        </div>

                        {/* Interactive Text Area */}
                        <div className="flex-grow flex flex-col bg-[#0C0B0B] rounded-[20px] border border-[#2A2A2A] p-5 focus-within:border-[#3A3A3A] transition-colors shadow-inner">
                            <textarea
                                placeholder="Describe the content you want to generate..."
                                className="bg-transparent border-none focus:ring-0 text-white placeholder:text-[#333333] placeholder:font-normal resize-none w-full min-h-[60px] flex-grow text-[16px] leading-[1.6] outline-none"
                                value={content}
                                onChange={(e) => setContent(e.target.value)}
                            />

                            {/* Control Bar inside the inner box bottom */}
                            <div className="flex items-center justify-between mt-auto pt-4">
                                <div className="flex items-center gap-4">
                                    <DropdownMenu>
                                        <DropdownMenuTrigger asChild>
                                            <button className="hover:scale-110 transition-transform">
                                                <IconCircleCopyPlus className="size-[20px]" />
                                            </button>
                                        </DropdownMenuTrigger>
                                        <DropdownMenuContent className="bg-[#1A1A1A] border-[#343434] text-white">
                                            <DropdownMenuItem className="gap-2 cursor-pointer focus:bg-[#2A2A2A]">
                                                <IconCloudUpload className="size-4" /> upload.md
                                            </DropdownMenuItem>
                                            <DropdownMenuItem className="gap-2 cursor-pointer focus:bg-[#2A2A2A]">
                                                <IconFile className="size-4" /> docs
                                            </DropdownMenuItem>
                                        </DropdownMenuContent>
                                    </DropdownMenu>

                                    <DropdownMenu>
                                        <DropdownMenuTrigger asChild>
                                            <button className="hover:scale-110 transition-transform flex items-center justify-center">
                                                <IconGearKeyhole className="size-[20px]" />
                                            </button>
                                        </DropdownMenuTrigger>
                                        <DropdownMenuContent className="bg-[#1A1A1A] border-[#343434] text-white w-64">
                                            {models.map((m) => (
                                                <DropdownMenuItem
                                                    key={m.value}
                                                    onClick={() => setSelectedModel(m.value)}
                                                    className="cursor-pointer focus:bg-[#2A2A2A]"
                                                >
                                                    {m.name}
                                                </DropdownMenuItem>
                                            ))}
                                        </DropdownMenuContent>
                                    </DropdownMenu>

                                    <DropdownMenu>
                                        <DropdownMenuTrigger asChild>
                                            <button className="flex items-center justify-center gap-2 text-[#A78BFA] font-medium text-[14px] hover:opacity-80 transition-opacity ml-1">
                                                <svg
                                                    width={16}
                                                    height={16}
                                                    viewBox="0 0 16 16"
                                                    fill="none"
                                                    xmlns="http://www.w3.org/2000/svg"
                                                >
                                                    <g clipPath="url(#clip0_2822_1492)">
                                                        <mask
                                                            id="mask0_2822_1492"
                                                            style={{ maskType: "luminance" }}
                                                            maskUnits="userSpaceOnUse"
                                                            x={0}
                                                            y={0}
                                                            width={16}
                                                            height={16}
                                                        >
                                                            <path d="M16 0H0V16H16V0Z" fill="white" />
                                                            <path
                                                                d="M14.6642 1.98558C14.6297 1.59273 14.2781 1.30014 13.8904 1.33641C6.92457 1.94584 3.77546 6.67817 2.38509 10.1493C2.25488 10.4744 2.41259 10.8391 2.73281 10.9808L3.45408 11.3C4.21889 11.6394 4.97035 11.7899 5.01473 11.7975C5.82799 11.946 6.57975 12.0207 7.26923 12.0207C8.7043 12.0207 9.86877 11.6982 10.7449 11.0582C11.0978 10.8 11.6694 10.2835 12.0684 9.40264C9.3723 9.91011 8.6699 7.98717 8.6699 7.98717C10.75 8.51357 13.1154 8.67544 13.749 6.24331C13.8814 5.66043 13.9657 5.09627 14.0466 4.55157L14.0494 4.53315C14.1769 3.68213 14.297 2.88051 14.5702 2.40317C14.6408 2.28076 14.6774 2.13699 14.6642 1.98558Z"
                                                                fill="black"
                                                            />
                                                        </mask>
                                                        <g mask="url(#mask0_2822_1492)">
                                                            <path
                                                                d="M9.2762 4.03112C9.59786 3.9286 9.9516 4.08408 10.0893 4.40026C10.2362 4.73784 10.0812 5.13094 9.7436 5.27786L9.4858 5.3931C6.8392 6.60099 4.85102 8.39239 3.93372 10.2903C3.86962 10.4227 3.76681 10.5237 3.64596 10.5878L3.64271 10.5962C2.97658 12.2426 2.72646 13.6218 2.6694 14.0949L2.65768 14.1627C2.58352 14.4923 2.26987 14.7189 1.92721 14.6776C1.56188 14.6334 1.30115 14.3009 1.34518 13.9354L1.3849 13.6581C1.50507 12.9024 1.83249 11.4193 2.55677 9.73619L2.58737 9.67499C2.65906 9.54626 2.76864 9.44839 2.89596 9.39112C4.07756 7.19792 6.37433 5.2897 9.21173 4.0552L9.2762 4.03112Z"
                                                                fill="url(#paint0_linear_2822_1492)"
                                                            />
                                                        </g>
                                                        <mask
                                                            id="mask1_2822_1492"
                                                            style={{ maskType: "luminance" }}
                                                            maskUnits="userSpaceOnUse"
                                                            x={2}
                                                            y={1}
                                                            width={13}
                                                            height={12}
                                                        >
                                                            <path
                                                                d="M14.6642 1.98558C14.6297 1.59273 14.2781 1.30014 13.8904 1.33641C6.92457 1.94584 3.77546 6.67817 2.38509 10.1493C2.25488 10.4744 2.41259 10.8391 2.73281 10.9808L3.45408 11.3C4.21889 11.6394 4.97035 11.7899 5.01473 11.7975C5.82799 11.946 6.57975 12.0207 7.26923 12.0207C8.7043 12.0207 9.86877 11.6982 10.7449 11.0582C11.0978 10.8 11.6694 10.2835 12.0684 9.40264C9.3723 9.91011 8.6699 7.98717 8.6699 7.98717C10.75 8.51357 13.1154 8.67544 13.749 6.24331C13.8814 5.66043 13.9657 5.09627 14.0466 4.55157L14.0494 4.53315C14.1769 3.68213 14.297 2.88051 14.5702 2.40317C14.6408 2.28076 14.6774 2.13699 14.6642 1.98558Z"
                                                                fill="white"
                                                            />
                                                        </mask>
                                                        <g mask="url(#mask1_2822_1492)">
                                                            <g filter="url(#filter0_f_2822_1492)">
                                                                <path
                                                                    d="M9.2762 4.03112C9.59786 3.9286 9.9516 4.08408 10.0893 4.40026C10.2362 4.73784 10.0812 5.13094 9.7436 5.27786L9.4858 5.3931C6.8392 6.60099 4.85102 8.39239 3.93372 10.2903C3.86962 10.4227 3.76681 10.5237 3.64596 10.5878L3.64271 10.5962C2.97658 12.2426 2.72646 13.6218 2.6694 14.0949L2.65768 14.1627C2.58352 14.4923 2.26987 14.7189 1.92721 14.6776C1.56188 14.6334 1.30115 14.3009 1.34518 13.9354L1.3849 13.6581C1.50507 12.9024 1.83249 11.4193 2.55677 9.73619L2.58737 9.67499C2.65906 9.54626 2.76864 9.44839 2.89596 9.39112C4.07756 7.19792 6.37433 5.2897 9.21173 4.0552L9.2762 4.03112Z"
                                                                    fill="url(#paint1_linear_2822_1492)"
                                                                />
                                                            </g>
                                                        </g>
                                                        <path
                                                            d="M14.6642 1.98558C14.6297 1.59273 14.2781 1.30014 13.8904 1.33641C6.92457 1.94584 3.77546 6.67817 2.38509 10.1493C2.25488 10.4744 2.41259 10.8391 2.73281 10.9808L3.45408 11.3C4.21889 11.6394 4.97035 11.7899 5.01473 11.7975C5.82799 11.946 6.57975 12.0207 7.26923 12.0207C8.7043 12.0207 9.86877 11.6982 10.7449 11.0582C11.0978 10.8 11.6694 10.2835 12.0684 9.40264C9.3723 9.91011 8.6699 7.98717 8.6699 7.98717C10.75 8.51357 13.1154 8.67544 13.749 6.24331C13.8814 5.66043 13.9657 5.09627 14.0466 4.55157L14.0494 4.53315C14.1769 3.68213 14.297 2.88051 14.5702 2.40317C14.6408 2.28076 14.6774 2.13699 14.6642 1.98558Z"
                                                            fill="url(#paint2_linear_2822_1492)"
                                                        />
                                                        <path
                                                            d="M13.8898 1.33654C14.2775 1.30026 14.6294 1.59277 14.6638 1.98562C14.6771 2.13689 14.6406 2.28061 14.5701 2.40294C14.2969 2.88028 14.1768 3.68213 14.0493 4.53315L14.046 4.55138C13.9651 5.09608 13.8808 5.66055 13.7485 6.24344L13.684 6.46349C12.9674 8.66476 10.6848 8.49689 8.6697 7.98696C8.6697 7.98696 9.3721 9.90969 12.0682 9.40229C11.6692 10.283 11.0976 10.7998 10.7446 11.0579L10.5766 11.1744C9.72157 11.7371 8.6139 12.0207 7.2687 12.0208V11.5208C8.6317 11.5207 9.68304 11.2143 10.4497 10.6542C10.6314 10.5214 10.8828 10.3047 11.1326 9.98629C10.1958 9.97096 9.51544 9.65802 9.0421 9.27276C8.73484 9.02262 8.52817 8.75329 8.39757 8.54489C8.33217 8.44042 8.28484 8.35016 8.25304 8.28316C8.23717 8.24962 8.22537 8.22149 8.21657 8.20049C8.21224 8.18996 8.20824 8.18076 8.2055 8.17376C8.20424 8.17042 8.20324 8.16716 8.2023 8.16469C8.20184 8.16349 8.20137 8.16242 8.20097 8.16142L8.2003 8.16009V8.15942C8.20024 8.15916 8.2001 8.15849 8.6697 7.98696L8.1997 8.15882L7.87544 7.27016L8.7921 7.50256C9.81844 7.76229 10.8354 7.90822 11.6476 7.73562C12.0436 7.65149 12.3762 7.49442 12.6404 7.24929C12.9022 7.00636 13.1238 6.65087 13.2622 6.1243C13.3887 5.56538 13.471 5.02181 13.5519 4.47781L13.5545 4.45893C13.6176 4.03768 13.6818 3.6071 13.7661 3.2213C13.8492 2.84082 13.9608 2.46092 14.1359 2.1549L14.1365 2.15359C14.1596 2.11346 14.1694 2.07117 14.1658 2.02924C14.1554 1.91094 14.0466 1.8237 13.9366 1.83393L13.9334 1.83458C7.2319 2.42097 4.20298 6.95436 2.84876 10.3352C2.82326 10.3991 2.84957 10.4857 2.9347 10.5234L3.65605 10.8424L3.6567 10.843C4.01041 11 4.36521 11.1146 4.63912 11.1914C4.77536 11.2296 4.88977 11.2584 4.97181 11.2773L5.09941 11.3046L5.10397 11.3053C5.89332 11.4495 6.61478 11.5208 7.2687 11.5208V12.0208L7.00764 12.0169C6.39065 12.0006 5.7258 11.9275 5.01412 11.7975C4.97328 11.7904 4.39417 11.6743 3.73874 11.4186L3.45358 11.3001L2.73222 10.9804C2.4122 10.8386 2.2544 10.474 2.38457 10.149C3.75323 6.73216 6.82624 2.09324 13.5662 1.36778L13.8898 1.33654Z"
                                                            fill="url(#paint3_linear_2822_1492)"
                                                        />
                                                    </g>
                                                    <defs>
                                                        <filter
                                                            id="filter0_f_2822_1492"
                                                            x={-2.65967}
                                                            y={-0.000244141}
                                                            width={16.8042}
                                                            height={18.6827}
                                                            filterUnits="userSpaceOnUse"
                                                            colorInterpolationFilters="sRGB"
                                                        >
                                                            <feFlood floodOpacity={0} result="BackgroundImageFix" />
                                                            <feBlend
                                                                mode="normal"
                                                                in="SourceGraphic"
                                                                in2="BackgroundImageFix"
                                                                result="shape"
                                                            />
                                                            <feGaussianBlur
                                                                stdDeviation={2}
                                                                result="effect1_foregroundBlur_2822_1492"
                                                            />
                                                        </filter>
                                                        <linearGradient
                                                            id="paint0_linear_2822_1492"
                                                            x1={5.7428}
                                                            y1={3.99999}
                                                            x2={5.7428}
                                                            y2={14.6827}
                                                            gradientUnits="userSpaceOnUse"
                                                        >
                                                            <stop stopColor="#00A8B4" />
                                                            <stop offset={1} stopColor="#04BCAD" />
                                                        </linearGradient>
                                                        <linearGradient
                                                            id="paint1_linear_2822_1492"
                                                            x1={5.7428}
                                                            y1={3.99999}
                                                            x2={5.7428}
                                                            y2={14.6827}
                                                            gradientUnits="userSpaceOnUse"
                                                        >
                                                            <stop stopColor="#575757" />
                                                            <stop offset={1} stopColor="#151515" />
                                                        </linearGradient>
                                                        <linearGradient
                                                            id="paint2_linear_2822_1492"
                                                            x1={8.4155}
                                                            y1={1.33337}
                                                            x2={8.4155}
                                                            y2={12.0207}
                                                            gradientUnits="userSpaceOnUse"
                                                        >
                                                            <stop stopColor="#E9DBFF" stopOpacity={0.6} />
                                                            <stop offset={1} stopColor="#C870FF" stopOpacity={0.6} />
                                                        </linearGradient>
                                                        <linearGradient
                                                            id="paint3_linear_2822_1492"
                                                            x1={8.5025}
                                                            y1={1.33329}
                                                            x2={8.5025}
                                                            y2={7.52262}
                                                            gradientUnits="userSpaceOnUse"
                                                        >
                                                            <stop stopColor="#FF7B8F" />
                                                            <stop offset={1} stopColor="white" stopOpacity={0} />
                                                        </linearGradient>
                                                        <clipPath id="clip0_2822_1492">
                                                            <rect width={16} height={16} fill="white" />
                                                        </clipPath>
                                                    </defs>
                                                </svg>
                                                <span>{selectedAI}</span>
                                            </button>
                                        </DropdownMenuTrigger>
                                        <DropdownMenuContent className="bg-[#1A1A1A] border-[#343434] text-white">
                                            {aiOptions.map((opt) => (
                                                <DropdownMenuItem
                                                    key={opt}
                                                    onClick={() => setSelectedAI(opt)}
                                                    className="cursor-pointer focus:bg-[#2A2A2A]"
                                                >
                                                    {opt}
                                                </DropdownMenuItem>
                                            ))}
                                        </DropdownMenuContent>
                                    </DropdownMenu>
                                </div>

                                <div className="flex items-center gap-3">
                                    <div className="flex items-center gap-1.5 text-[#848484] text-[13px] font-medium opacity-80">
                                        <Command className="size-[13px]" />
                                        <span>+ Enter</span>
                                    </div>
                                    <Button
                                        size="icon"
                                        className="h-[34px] w-[34px] rounded-[10px] bg-gradient-to-b from-[#6366F1] to-[#3B82F6] shadow-[0_0_15px_rgba(59,130,246,0.3)] hover:shadow-[0_0_20px_rgba(59,130,246,0.5)] transition-all flex items-center justify-center p-0"
                                    >
                                        <ArrowUp className="size-[18px] text-white" strokeWidth={2.5} />
                                    </Button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                {/* Footer placed inside the outer box but outside the inner container flow */}
                <div className="flex items-center justify-end gap-3 px-6 py-4">
                    <span className="text-[#848484] text-[12px] font-normal tracking-wider">
                        Upgrade to unlock for Teams
                    </span>
                    <button className="text-[#3B82F6] text-[12px] font-medium hover:underline tracking-wide">
                        Upgrade Plan
                    </button>
                </div>
            </div>

        </div>
    )
}

More from d2

Browse all components in this library →