From 8c131c0b927b4b13958934495a6222552470f5eb Mon Sep 17 00:00:00 2001 From: Muhammad-Jay Date: Tue, 2 Dec 2025 16:29:55 +0100 Subject: [PATCH 1/4] feat: Complete redesign of the landing page - Overhaul the design of the landing page, including the Hero, Features, Services, About, and Footer sections. - Remove the temporary "Mono" components and replace them with the redesigned original components. - Implement new animations and a feature reveal section in the Features component. - Update the Navbar with new styles and animations. --- app/page.tsx | 12 +- components/Landing/About.tsx | 97 -------- .../Landing/AutomationIntegrationSection.tsx | 206 ++++++++++++++++ components/Landing/{MonoCTA.tsx => CTA.tsx} | 8 +- components/Landing/Features.tsx | 230 ++++++++++++------ components/Landing/Footer.tsx | 112 ++------- components/Landing/Hero.tsx | 192 +++++++++------ components/Landing/HeroSecondary.tsx | 86 ------- components/Landing/MonoFeatures.tsx | 175 ------------- components/Landing/MonoFooter.tsx | 29 --- components/Landing/MonoHero.tsx | 150 ------------ components/Landing/MonoTestimonials.tsx | 42 ---- components/Landing/Navbar.tsx | 125 ++-------- 13 files changed, 543 insertions(+), 921 deletions(-) delete mode 100644 components/Landing/About.tsx create mode 100644 components/Landing/AutomationIntegrationSection.tsx rename components/Landing/{MonoCTA.tsx => CTA.tsx} (62%) delete mode 100644 components/Landing/HeroSecondary.tsx delete mode 100644 components/Landing/MonoFeatures.tsx delete mode 100644 components/Landing/MonoFooter.tsx delete mode 100644 components/Landing/MonoHero.tsx delete mode 100644 components/Landing/MonoTestimonials.tsx diff --git a/app/page.tsx b/app/page.tsx index 3576bd0..caf3c12 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,8 +1,8 @@ -import MonoHero from '@/components/Landing/MonoHero'; -import MonoFeatures from '@/components/Landing/MonoFeatures'; -import MonoTestimonials from '@/components/Landing/MonoTestimonials'; -import MonoCTA from '@/components/Landing/MonoCTA'; -import MonoFooter from '@/components/Landing/MonoFooter'; +import MonoHero from '@/components/Landing/Hero'; +import MonoFeatures from '@/components/Landing/Features'; +import AutomationIntegrationSection from '@/components/Landing/AutomationIntegrationSection'; +import MonoCTA from '@/components/Landing/CTA'; +import MonoFooter from '@/components/Landing/Footer'; import { Navbar } from '@/components/Landing/Navbar'; import { cn } from '@/lib/utils'; import { Metadata } from 'next'; @@ -65,7 +65,7 @@ export default function LandingPage() { {/* */} - + diff --git a/components/Landing/About.tsx b/components/Landing/About.tsx deleted file mode 100644 index 1f403b6..0000000 --- a/components/Landing/About.tsx +++ /dev/null @@ -1,97 +0,0 @@ -'use client'; - -import { motion } from 'framer-motion'; -import { Sparkles, ArrowRight } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import Link from 'next/link'; - -export const About = () => { - return ( -
-
- - {/* 1. VISUAL & IMPACT COLUMN (Left) - Unchanged */} -
- {/* The Creative Element: Layered, Stylized Text */} -

- TRUST -

- - -

- “Intelligence is the ability to adapt to change. Creation is the ability to drive - it.” -

-
— Our Philosophy
-
-
- - {/* 2. CONTENT & MISSION COLUMN (Right) - UPDATED TEXT */} -
- - The Engine of Productivity - - - - Verified speed meets automated delivery. - - - - Our platform is powered by a **Supabase/Drizzle backend** for reliable scheduling and - data integrity. We prioritize **factual accuracy** by integrating real-time web search - (Tavily/Google) into every generation. This means your content is not only fast and - automated but also grounded in up-to-date, verifiable information, making it genuinely - impactful. - - - - - - - -
-
-
-
- ); -}; diff --git a/components/Landing/AutomationIntegrationSection.tsx b/components/Landing/AutomationIntegrationSection.tsx new file mode 100644 index 0000000..852d390 --- /dev/null +++ b/components/Landing/AutomationIntegrationSection.tsx @@ -0,0 +1,206 @@ +'use client' + +import React from 'react'; +import { motion } from 'framer-motion'; + +const Container = ({ children, className = '' }) => ( +
+ {children} +
+); + + +export const AutomationOrb = () => ( + +
+
+
+ +); + + + +const AnimatedPipelineCore = () => { + + const pathD = "M 50 20 C 50 150, 280 150, 280 250 S 50 350, 50 480"; + + + return ( +
+ {/* SVG Canvas for the path and animation */} + + {/* The main pipeline path (dashed and subtle) */} + + + {/* The flowing Data Packet (animated circle along the path) */} + + {/* Inner pulse for the packet */} + + + + {/* --- Stage Anchors (Fixed points along the path) --- */} + {/* Anchor 1: Stage 1 (Top) */} + + {/* Anchor 2: Stage 2 (Middle Right) */} + + {/* Anchor 3: Stage 3 (Bottom) */} + + + +
+ ); +}; + + +// Static data for the stages +const automationSteps = [ + { + id: 1, + title: "Stage 1: Verified Content Generation", + description: "Content is drafted using the two-stage refinement process. Outputs are verified against compliance and tone guides before processing.", + position: 'top-left', + }, + { + id: 2, + title: "Stage 2: Immutable Quality Assurance", + description: "The draft enters the audit log. Real-time scanning checks for global regulatory adherence and source integrity.", + position: 'center-right', + }, + { + id: 3, + title: "Stage 3: Webhook Delivery & Scale", + description: "A secure webhook payload is sent directly to your CMS (WordPress, Contentful, Custom API). Automate publishing.", + position: 'bottom-left', + } +]; + +// Main section component using the new Animated Pipeline +export default function AutomationIntegrationSection() { + return ( +
+ + {/* The Creative Automation Orb Background Element */} + + + + + Seamless Delivery. Integrated Intelligence. + + + The ThinkInk Automation Pipeline turns generated content into published assets without a single manual intervention. + + + + + {/* This container sets the overall height for absolute children on desktop */} +
+ + {/* Animation Core: Hidden on mobile (hidden), Visible & Centered on desktop (md:block) */} +
+ +
+ + {/* Stage Content: Simple column flow on mobile, Absolute positioning on desktop */} + {/* On mobile, this div stacks all cards with gap-12 */} +
+ {automationSteps.map((step, index) => ( + +

{step.title}

+

{step.description}

+
+ ))} +
+
+ + +

Integrate Your Stack. Scale Your Output.

+

Connect to any modern CMS in minutes and move from draft to publish automatically.

+ +
+ +
+
+ ); +} \ No newline at end of file diff --git a/components/Landing/MonoCTA.tsx b/components/Landing/CTA.tsx similarity index 62% rename from components/Landing/MonoCTA.tsx rename to components/Landing/CTA.tsx index f1847dc..7eb5133 100644 --- a/components/Landing/MonoCTA.tsx +++ b/components/Landing/CTA.tsx @@ -9,15 +9,15 @@ export default function MonoCTA() { return (
- +

Start creating memorable content today.

-

Try ThinkInk for free — no credit card required. Scale your writing workflows with minimal overhead.

+

Try ThinkInk for free no credit card required. Scale your writing workflows with minimal overhead.

- - + +
diff --git a/components/Landing/Features.tsx b/components/Landing/Features.tsx index 3034bcd..2d8916e 100644 --- a/components/Landing/Features.tsx +++ b/components/Landing/Features.tsx @@ -1,85 +1,179 @@ -'use client'; +'use client' -import { motion } from 'framer-motion'; -import { Zap, BrainCircuit, ShieldCheck, TrendingUp, Cpu } from 'lucide-react'; +import React from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import {Button} from '@/components/ui/button'; +import { cn } from '@/lib/utils'; -const features = [ - { - icon: , - title: 'Real-time Generation', - description: - 'Generate high-quality content in real-time, instantly responding to your input and context.', - }, - { - icon: , - title: 'Fact-Grounded AI', - description: - 'Our AI is grounded in real-time, verifiable facts from the web to eliminate hallucinations.', - }, - { - icon: , - title: 'Secure & Reliable', - description: - 'Your projects and data are always safe and securely stored on our reliable platform.', - }, -]; +export default function MonoFeatures() { + const [selectedFeature, setSelectedFeature] = React.useState(null); -const containerVariants = { - hidden: { opacity: 0 }, - visible: { - opacity: 1, - transition: { - staggerChildren: 0.15, // Stagger the appearance of the cards + const features = [ + { + id: 'f1', + title: 'Two-Stage Refinement Pipeline', + desc: 'Precision starts upstream. Refine prompt parameters before execution to ensure superior content grounding.', + fullDescription: 'Our proprietary dual-stage system separates conceptual alignment from final drafting. Stage 1 focuses on filtering and optimizing the prompt payload based on historical performance and compliance metrics. This rigorous upstream vetting results in cleaner, more targeted content output from Stage 2.', + icon: ( + + + + + + ), }, - }, -}; + { + id: 'f2', + title: 'Automated Compliance Checks', + desc: 'Instant, automated checks for tone consistency, citation integrity, length compliance, and SEO alignment.', + fullDescription: 'Every generated document passes through an automated quality gate. This includes real-time validation against predefined metrics for SEO density, brand tone, and legal compliance (e.g., source attribution). Publish with absolute confidence, knowing your content is checked and verified.', + icon: ( + + + + + ), + }, + { + id: 'f3', + title: 'Webhooks & API Integration', + desc: 'Deliver content automatically and securely to your CMS or preferred publishing platform via robust webhooks.', + fullDescription: 'Integrate ThinkInk into your existing content stack via our secure, API-first architecture. Configure custom webhooks to trigger content delivery, approval flows, or archival processes instantly upon generation completion, achieving full operational automation.', + icon: ( + + + + + ), + } + ]; + + const handleCardClick = (feature) => { + setSelectedFeature(selectedFeature?.id === feature.id ? null : feature); + }; -const itemVariants = { - hidden: { opacity: 0, y: 50, scale: 0.95 }, - visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.6 } }, -}; + const featureRevealVariants = { + hidden: { opacity: 0, height: 0, scaleY: 0.95 }, + visible: { + opacity: 1, + height: "auto", + scaleY: 1, + transition: { duration: 0.5, ease: [0.25, 1, 0.5, 1] } + }, + exit: { + opacity: 0, + height: 0, + paddingTop: 0, + paddingBottom: 0, + transition: { duration: 0.3, ease: "easeOut" } + } + }; -export const Features = () => { return ( - // Added a subtle gradient background to enhance the glass effect on cards -
-
- - Unmatched Performance, Unmatched Quality - +
+
+
+ + Power Engineered for Content Mastery. + + + Everything you need to produce polished content quickly reliability without the noise. + +
- - {features.map((feature, index) => ( - + {features.map((f, idx) => ( + handleCardClick(f)} + role="button" + aria-expanded={selectedFeature?.id === f.id} + className={`relative bg-white border group rounded-2xl p-8 cursor-pointer hover:bg-black hover:text-white! transition-all duration-300 transform + ${selectedFeature?.id === f.id ? 'border-black bg-black! shadow-2xl shadow-black/10' : ' hover:border-black/50 shadow-lg hover:shadow-xl hover:shadow-neutral-200'} + `} > - {/* Icon Container with subtle ring */} -
-
- {feature.icon} +
+ {/* Icon Wrapper (Sleek Border) */} +
+ {f.icon}
+ +
{f.title}
+ +

{f.desc}

-

{feature.title}

-

{feature.description}

+
+ {selectedFeature?.id === f.id ? '' : 'Click to reveal →'} +
))} - +
+ + {/* === Full Description Reveal Section === */} + + {selectedFeature && ( + +
+ {/* Reveal Icon and Title */} +
+
+ {selectedFeature.icon} +
+

+ {selectedFeature.title} +

+
+ + {/* Full Description Text */} +

+ {selectedFeature.fullDescription} +

+ + {/* Closing Button */} +
+ +
+
+
+ )} +
); -}; +} \ No newline at end of file diff --git a/components/Landing/Footer.tsx b/components/Landing/Footer.tsx index 65c18a8..ea0666b 100644 --- a/components/Landing/Footer.tsx +++ b/components/Landing/Footer.tsx @@ -1,102 +1,28 @@ -'use client'; +'use client' -import { motion } from 'framer-motion'; -import { Github, Twitter, Linkedin, BookOpen } from 'lucide-react'; -import Link from 'next/link'; +import React from 'react'; -// Dummy Navigation Links to flesh out the footer -const navLinks = [ - { name: 'Privacy Policy', href: '/privacy' }, - { name: 'Terms of Service', href: '/terms' }, - { name: 'Contact', href: '/contact' }, -]; - -export const Footer = () => { +export default function MonoFooter() { return ( - // 1. Dramatic Background Change: Pure Black -
-
- {/* TOP TIER: Branding and Primary Navigation */} -
- {/* Brand/Logo */} - - ThinkInk - - - {/* Navigation Links */} - - {navLinks.map((link, index) => ( - - {link.name} - - ))} - -
+
+
+
+
+
TI
+
+
Think-Ink
+
AI content refined for quality
+
+
- {/* BOTTOM TIER: Copyright and Social Media */} -
- {/* Copyright */} - - © {new Date().getFullYear()} ThinkInk, Inc. All rights reserved. - +
+ Features + {/* Testimonials */} +
- {/* Social Icons (Enhanced Hover) */} - - - - - - - - - - - +
© {new Date().getFullYear()} Think-Ink — All rights reserved
); -}; +} diff --git a/components/Landing/Hero.tsx b/components/Landing/Hero.tsx index c61a7c9..b6224e8 100644 --- a/components/Landing/Hero.tsx +++ b/components/Landing/Hero.tsx @@ -1,80 +1,132 @@ -'use client'; +'use client' +import React from 'react'; import { motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; -import Link from 'next/link'; -import { ArrowRight, Zap, BookOpen } from 'lucide-react'; // Added Zap and BookOpen for visual flair +import SCREENSHOT_URL from '@/assets/hero_image.png'; +import Image from 'next/image'; +import { Navbar } from './Navbar'; -// --- New Component: Dynamic Background Blob (Optional but Recommended) --- -// This adds subtle, animated color that avoids using a heavy image. -const AnimatedBlob = () => ( -
-); -export const Hero = () => { +export default function MonoHero() { return ( -
- {/* 1. Enhanced Background */} -
- {/* Added animated background effect */} -
- {' '} - {/* Increased Z-index for text clarity */} - {/*/!* 2. Enhanced Badge (More Polished) *!/*/} - {/**/} - {/* /!* Added icon *!/*/} - {/* Powered by Vercel Ai SDK*/} - {/**/} - {/* 3. Improved Typography & Visual Impact */} - - ThinkInk - - {/* 4. Refined Tagline */} - - The ultimate **AI-powered content creation platform**. Generate high-quality articles, - blog posts, and more in **seconds**. - - {/* 5. Enhanced CTA Buttons */} - - - - - - + + + {/* FIX: Replaced next/link with standard tag */} + + + + + +
+
+
1
+
+
Trusted by creators
+
Used daily by modern teams
+
+
+ +
+
99%
+
+
Uptime & performance
+
Reliably available
+
+
+
+
+ + {/* Right side visual — Platform Screensho */} +
+ - Learn More - - - + + {/* Image 1: Primary Screenshot (Foreground) */} +
+ Primary Screenshot of the content generator interface + width={1300} + height={650} + className="w-full h-auto object-cover" + /> +
+ + {/* Image 2: Secondary Screenshot (Background/Layered) */} +
+ Secondary layered detail +
+ + {/* Abstract Background Element (Moved further back) */} +
+ +
+
-
+ ); -}; +} \ No newline at end of file diff --git a/components/Landing/HeroSecondary.tsx b/components/Landing/HeroSecondary.tsx deleted file mode 100644 index fbe334f..0000000 --- a/components/Landing/HeroSecondary.tsx +++ /dev/null @@ -1,86 +0,0 @@ -'use client'; -import React from 'react'; -import Image from 'next/image'; -import { motion } from 'framer-motion'; - -const Hero = () => { - return ( -
-
- {/* Left Column: Text Content */} - -

- Unleash Your AI Writer. Create Fact-Based Content, Instantly. -

-

- Generate high-quality blogs, social media posts, and more with our advanced AI. Grounded - in truth, crafted for impact. -

- - Start Generating for Free - -
- - {/* Right Column: Image and Animation */} - -
- AI Content Generator Interface -
- - {/* Background Decoration */} -
- - - - - -
-
-
-
- ); -}; - -export default Hero; diff --git a/components/Landing/MonoFeatures.tsx b/components/Landing/MonoFeatures.tsx deleted file mode 100644 index 8ce1338..0000000 --- a/components/Landing/MonoFeatures.tsx +++ /dev/null @@ -1,175 +0,0 @@ -'use client' - -import React from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import {Button} from '@/components/ui/button'; -import { cn } from '@/lib/utils'; - -export default function MonoFeatures() { - const [selectedFeature, setSelectedFeature] = React.useState(null); - - const features = [ - { - id: 'f1', - title: 'Two-Stage Refinement Pipeline', - desc: 'Precision starts upstream. Refine prompt parameters before execution to ensure superior content grounding.', - fullDescription: 'Our proprietary dual-stage system separates conceptual alignment from final drafting. Stage 1 focuses on filtering and optimizing the prompt payload based on historical performance and compliance metrics. This rigorous upstream vetting results in cleaner, more targeted content output from Stage 2.', - icon: ( - - - - - - ), - }, - { - id: 'f2', - title: 'Automated Compliance Checks', - desc: 'Instant, automated checks for tone consistency, citation integrity, length compliance, and SEO alignment.', - fullDescription: 'Every generated document passes through an automated quality gate. This includes real-time validation against predefined metrics for SEO density, brand tone, and legal compliance (e.g., source attribution). Publish with absolute confidence, knowing your content is checked and verified.', - icon: ( - - - - - ), - }, - { - id: 'f3', - title: 'Webhooks & API Integration', - desc: 'Deliver content automatically and securely to your CMS or preferred publishing platform via robust webhooks.', - fullDescription: 'Integrate ThinkInk into your existing content stack via our secure, API-first architecture. Configure custom webhooks to trigger content delivery, approval flows, or archival processes instantly upon generation completion, achieving full operational automation.', - icon: ( - - - - - ), - } - ]; - - const handleCardClick = (feature) => { - setSelectedFeature(selectedFeature?.id === feature.id ? null : feature); - }; - - const featureRevealVariants = { - hidden: { opacity: 0, height: 0, scaleY: 0.95 }, - visible: { - opacity: 1, - height: "auto", - scaleY: 1, - transition: { duration: 0.5, ease: [0.25, 1, 0.5, 1] } - }, - exit: { - opacity: 0, - height: 0, - paddingTop: 0, - paddingBottom: 0, - transition: { duration: 0.3, ease: "easeOut" } - } - }; - - return ( -
-
-
- - Power Engineered for Content Mastery. - - - Everything you need to produce polished content quickly — reliability without the noise. - -
- - {/* Feature Cards Grid */} -
- {features.map((f, idx) => ( - handleCardClick(f)} - role="button" - aria-expanded={selectedFeature?.id === f.id} - className={`relative bg-white border group rounded-2xl p-8 cursor-pointer transition-all duration-300 transform - ${selectedFeature?.id === f.id ? 'border-black ring-4 ring-black/10 shadow-2xl shadow-black/10' : ' hover:border-black/50 shadow-lg hover:shadow-xl hover:shadow-neutral-200'} - `} - > -
- {/* Icon Wrapper (Sleek Border) */} -
- {f.icon} -
- -
{f.title}
-
- -

{f.desc}

- - - -
- {selectedFeature?.id === f.id ? 'Description revealed ↓' : 'Click to learn more →'} -
-
- ))} -
- - {/* === Full Description Reveal Section === */} - - {selectedFeature && ( - -
- {/* Reveal Icon and Title */} -
-
- {selectedFeature.icon} -
-

- {selectedFeature.title} -

-
- - {/* Full Description Text */} -

- {selectedFeature.fullDescription} -

- - {/* Closing Button */} -
- -
-
-
- )} -
-
-
- ); -} \ No newline at end of file diff --git a/components/Landing/MonoFooter.tsx b/components/Landing/MonoFooter.tsx deleted file mode 100644 index f2b08a5..0000000 --- a/components/Landing/MonoFooter.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' - -import React from 'react'; - -export default function MonoFooter() { - return ( -
-
-
-
-
TI
-
-
ThinkInk
-
AI content refined for quality
-
-
- - - -
© {new Date().getFullYear()} ThinkInk — All rights reserved
-
-
-
- ); -} diff --git a/components/Landing/MonoHero.tsx b/components/Landing/MonoHero.tsx deleted file mode 100644 index e1330de..0000000 --- a/components/Landing/MonoHero.tsx +++ /dev/null @@ -1,150 +0,0 @@ -'use client' - -import React from 'react'; -import { motion } from 'framer-motion'; -import { Button } from '@/components/ui/button'; -import SCREENSHOT_URL from '@/assets/hero_image.png'; -import Image from 'next/image'; - - -export default function MonoHero() { - return ( -
- {/* 1. Subtle Background Texture (Grain/Vignette) */} -
- {/* Soft grain / vignette for tactile depth */} -
-
-
- - {/* Navigation Bar */} - - - {/* Hero Content Grid */} -
-
- {/* Left side: Text Content and CTAs */} -
- - Build better content faster. - - - - A sleek, minimal content generator tuned for clarity and quality. One pipeline - endless possibilities. Grounded by research, refined by AI. - - - - {/* FIX: Replaced next/link with standard tag */} - - - - - {/* FIX: Replaced next/link with standard tag */} - - - - - -
-
-
1
-
-
Trusted by creators
-
Used daily by modern teams
-
-
- -
-
99%
-
-
Uptime & performance
-
Reliably available
-
-
-
-
- - {/* Right side visual — Platform Screensho */} -
- - - {/* Image 1: Primary Screenshot (Foreground) */} -
- Primary Screenshot of the content generator interface - width={1300} - height={650} - className="w-full h-auto object-cover" - /> -
- - {/* Image 2: Secondary Screenshot (Background/Layered) */} -
- Secondary layered detail -
- - {/* Abstract Background Element (Moved further back) */} -
- -
-
-
-
- ); -} \ No newline at end of file diff --git a/components/Landing/MonoTestimonials.tsx b/components/Landing/MonoTestimonials.tsx deleted file mode 100644 index ba5eaad..0000000 --- a/components/Landing/MonoTestimonials.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client' - -import React from 'react'; -import { motion } from 'framer-motion'; - -const quotes = [ - { - id: 'q1', - quote: 'ThinkInk transformed our content workflow — outputs are cleaner and more consistent than ever.', - author: 'Jamal T., Editorial Lead', - }, - { - id: 'q2', - quote: 'The two-step prompt refinement saved us hours per week and improved our SEO metrics.', - author: 'Sara L., Growth Marketer', - }, - { - id: 'q3', - quote: 'Reliable, fast, and the minimal UI keeps our writers focused. A modern tool for modern teams.', - author: 'Alex P., Product Manager', - } -]; - -export default function MonoTestimonials() { - return ( -
-
- Trusted & loved - Hear what early teams say - -
- {quotes.map((q, idx) => ( - -

“{q.quote}”

- {q.author} -
- ))} -
-
-
- ); -} diff --git a/components/Landing/Navbar.tsx b/components/Landing/Navbar.tsx index aca5e3a..c24621d 100644 --- a/components/Landing/Navbar.tsx +++ b/components/Landing/Navbar.tsx @@ -4,117 +4,40 @@ import { motion } from 'framer-motion'; // Assuming '@/components/ui/button' is available and using Link as a standard anchor replacement import { Button } from '@/components/ui/button'; // Replaced import from 'next/link' with a standard variable declaration for Link -const Link = (props) => ; +import Link from 'next/link'; import { Menu, X, BookOpen } from 'lucide-react'; import { useState } from 'react'; export const Navbar = () => { - const [isOpen, setIsOpen] = useState(false); - const navLinks = [ - { href: '#features', label: 'Features' }, - { href: '#services', label: 'Services' }, - { href: '#about', label: 'About' }, - ]; - - // Variants for the mobile menu animation - const menuVariants: any = { - open: { opacity: 1, y: 0, transition: { type: 'spring', stiffness: 300, damping: 30 } }, - closed: { opacity: 0, y: -20, transition: { duration: 0.3 } }, - }; return ( - // --- Enhanced Floating Capsule Container --- - -
- {/* Logo/Brand */} - - - - ThinkInk - - - - {/* Desktop Navigation Links */} -
- {navLinks.map((link) => ( - - {link.label} - {/* Active/Hover Underline Effect */} - - - ))} -
- - {/* Desktop CTA Button */} -
- - - -
- - {/* Mobile Menu Button */} -
- -
-
- - {/* Mobile Menu Dropdown (Animated) */} - -
- {navLinks.map((link) => ( - setIsOpen(false)} - > - {link.label} - - ))} -
- - - -
-
-
-
+
+ ); }; From 3336510650feabc61fd8281da288aced6a1c39b3 Mon Sep 17 00:00:00 2001 From: Muhammad-Jay Date: Wed, 3 Dec 2025 10:49:24 +0100 Subject: [PATCH 2/4] feat: add custom image dialog to mdx editor toolbar, and update the loading state of the editor --- components/Landing/Features.tsx | 19 ++- components/Landing/Navbar.tsx | 123 +++++++++++++----- .../API-Integrations/WebhookManager.tsx | 6 +- .../Generate/Editor/CustomImageDialog.tsx | 84 +++--------- .../Dashboard/Generate/Editor/Editor.tsx | 4 +- .../Generate/Editor/EditorLoader.tsx | 4 - .../Dashboard/Generate/RightSidebarPanel.tsx | 14 +- .../Dashboard/Generate/content/Renderer.tsx | 3 +- components/ui/ContentLoadingSkeleton.tsx | 20 ++- 9 files changed, 159 insertions(+), 118 deletions(-) diff --git a/components/Landing/Features.tsx b/components/Landing/Features.tsx index 2d8916e..4c28563 100644 --- a/components/Landing/Features.tsx +++ b/components/Landing/Features.tsx @@ -1,6 +1,6 @@ 'use client' -import React from 'react'; +import React, { useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import {Button} from '@/components/ui/button'; import { cn } from '@/lib/utils'; @@ -8,6 +8,23 @@ import { cn } from '@/lib/utils'; export default function MonoFeatures() { const [selectedFeature, setSelectedFeature] = React.useState(null); + useEffect(() => { + + let timer = null; + let len = 0; + + while (features.length !== len) { + + timer = setTimeout(() => { + + setSelectedFeature(features[len]); + len++ + if(len === features.length) len = 0 + }, 2000) + } + + }, []) + const features = [ { id: 'f1', diff --git a/components/Landing/Navbar.tsx b/components/Landing/Navbar.tsx index c24621d..eb90668 100644 --- a/components/Landing/Navbar.tsx +++ b/components/Landing/Navbar.tsx @@ -1,43 +1,102 @@ 'use client'; -import { motion } from 'framer-motion'; -// Assuming '@/components/ui/button' is available and using Link as a standard anchor replacement +import { AnimatePresence, motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; -// Replaced import from 'next/link' with a standard variable declaration for Link import Link from 'next/link'; import { Menu, X, BookOpen } from 'lucide-react'; import { useState } from 'react'; export const Navbar = () => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + const toggleMenu = () => { + setIsMenuOpen(!isMenuOpen); + }; - return ( - - - - ); + const navItems = [ + { href: "#features", label: "Features" }, + { href: "#automation", label: "Automation" }, + ]; + + return ( + + + + {/* Mobile Menu Content (Animated Overlay) */} + + {isMenuOpen && ( + +
+ {navItems.map(item => ( + + {item.label} + + ))} + +
+ + + +
+
+
+ )} +
+
+ ); }; diff --git a/components/Layout/Dashboard/API-Integrations/WebhookManager.tsx b/components/Layout/Dashboard/API-Integrations/WebhookManager.tsx index 6fdc6d0..09b0c43 100644 --- a/components/Layout/Dashboard/API-Integrations/WebhookManager.tsx +++ b/components/Layout/Dashboard/API-Integrations/WebhookManager.tsx @@ -40,7 +40,7 @@ const mockDecrypt = (data) => data.startsWith('ENC:') ? atob(data.slice(4)) : da const defaultWebhook = { url: '', trigger_event: 'content.complete', - secret_key: crypto.randomUUID(), // Auto-generate a strong initial secret + secret_key: "", // Auto-generate a strong initial secret is_active: true, }; @@ -508,12 +508,12 @@ export const WebhookManager = () => { {/* Details */}

Destination URL

- + {hook.url}
-
+
Trigger: {hook.trigger_event} Secured by Secret Key
diff --git a/components/Layout/Dashboard/Generate/Editor/CustomImageDialog.tsx b/components/Layout/Dashboard/Generate/Editor/CustomImageDialog.tsx index abc2f14..f1d3748 100644 --- a/components/Layout/Dashboard/Generate/Editor/CustomImageDialog.tsx +++ b/components/Layout/Dashboard/Generate/Editor/CustomImageDialog.tsx @@ -2,6 +2,10 @@ import React, { useState } from 'react'; import { Button } from '@/components/ui/button'; // Assuming you use a UI library import { Input } from '@/components/ui/input'; import { SaveImageParameters } from '@mdxeditor/editor'; // The type for submitting data +import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'; +import { cn } from '@/lib/utils'; +import { Images } from '../RightSidebarPanel'; +import { ImagePlus } from 'lucide-react'; // Define the shape of the props the MDX editor will pass to your component interface CustomImageDialogProps { @@ -13,7 +17,7 @@ interface CustomImageDialogProps { // state: EditingImageDialogState | NewImageDialogState; } -const CustomImageDialog: React.FC = ({ onImageUpload, onClose }) => { +const CustomImageDialog = () => { const [url, setUrl] = useState(''); const [altText, setAltText] = useState(''); const [file, setFile] = useState(null); @@ -25,12 +29,7 @@ const CustomImageDialog: React.FC = ({ onImageUpload, on // CASE 1: Image URL provided if (url.trim()) { - onImageUpload({ - src: url.trim(), - altText: altText.trim(), - // width and height are optional, but good practice if known - }); - onClose(); + return; } @@ -42,13 +41,7 @@ const CustomImageDialog: React.FC = ({ onImageUpload, on // You would call your private API route here (e.g., /api/upload-image) const uploadedUrl = await uploadImageToServer(file); - // --- STEP B: Submit the final URL to the MDX Editor --- - onImageUpload({ - src: uploadedUrl, - altText: altText.trim() || file.name, - // You could fetch dimensions from the server response here if needed - }); - onClose(); + } catch (error) { console.error('Image upload failed:', error); alert('Failed to upload image. Check console for details.'); @@ -80,59 +73,18 @@ const CustomImageDialog: React.FC = ({ onImageUpload, on }; return ( -
-

Insert Image

- - {/* File Upload Section */} -
- - { - setFile(e.target.files?.[0] || null); - // Clear URL when file is selected - setUrl(''); - }} - /> -

or enter a URL below

-
- - {/* URL Input Section */} -
- - { - setUrl(e.target.value); - // Clear file when URL is manually entered - setFile(null); - }} - /> -
- - {/* Alt Text Input */} -
- - setAltText(e.target.value)} - /> -
- - {/* Actions */} -
- - -
-
+ + + + + + ); }; diff --git a/components/Layout/Dashboard/Generate/Editor/Editor.tsx b/components/Layout/Dashboard/Generate/Editor/Editor.tsx index b06b19f..99b9260 100644 --- a/components/Layout/Dashboard/Generate/Editor/Editor.tsx +++ b/components/Layout/Dashboard/Generate/Editor/Editor.tsx @@ -61,7 +61,7 @@ export default function Editor() { - + {/* You can add more buttons here */} @@ -92,7 +92,7 @@ export default function Editor() { tablePlugin(), ]} contentEditableClassName={cn( - 'container-full !h-full p-2 overflow-y-auto prose markdown markdown-content-area', + 'container-full !h-full p-2 pt-10! overflow-y-auto prose markdown markdown-content-area', )} className={cn('container-full overflow-hidden rounded-md bg-white')} /> diff --git a/components/Layout/Dashboard/Generate/Editor/EditorLoader.tsx b/components/Layout/Dashboard/Generate/Editor/EditorLoader.tsx index f8f5a61..b70fc2f 100644 --- a/components/Layout/Dashboard/Generate/Editor/EditorLoader.tsx +++ b/components/Layout/Dashboard/Generate/Editor/EditorLoader.tsx @@ -18,10 +18,6 @@ export default function EditorLoader({ className }: CodeEditorLoaderProps) { className, // Allows setting height/width from the dynamic import )} > -
- Loading: Initializing Markdown Interface... -
- {/* Simulated Code/Content Lines */} {Array.from({ length: LINE_COUNT }).map((_, index) => { // Line width varies to mimic code structure diff --git a/components/Layout/Dashboard/Generate/RightSidebarPanel.tsx b/components/Layout/Dashboard/Generate/RightSidebarPanel.tsx index 0b355c5..8292470 100644 --- a/components/Layout/Dashboard/Generate/RightSidebarPanel.tsx +++ b/components/Layout/Dashboard/Generate/RightSidebarPanel.tsx @@ -15,7 +15,7 @@ import { ChatHistoryRenderer } from '@/components/Layout/Dashboard/Generate/Chat import { ScrollArea } from '@/components/ui/scroll-area'; import { toast } from 'sonner'; import { Button } from '@mdxeditor/editor'; -import { Upload, X } from 'lucide-react'; +import { TrashIcon, Upload, X } from 'lucide-react'; import { motion } from 'framer-motion'; import MobileSheetWrapper from '@/components/Layout/Dashboard/Generate/MobileSheetWrapper'; import { SystemPromptSelector } from '@/components/Layout/Dashboard/Generate/AISystemConfig'; @@ -136,7 +136,7 @@ export const Source = () => { ); }; -const Images = () => { +export const Images = ({ width = 400}) => { const { generatedContent, setGeneratedContent, localImages, setLocalImages } = useContent(); // MAINTAINED LOGIC: Extract images from Markdown @@ -202,7 +202,7 @@ const Images = () => { return (

@@ -239,11 +239,11 @@ const Images = () => {

{/* Action Buttons Overlay */} -
+
{/* Insert Button (Primary Action) */}
handleInsertImage(url)} - className="mb-1 w-full bg-indigo-600 text-xs font-semibold text-white hover:bg-indigo-700" + className="mb-1 w-full bg-indigo-600 cursor-pointer text-xs rounded-md p-2.5 transition-300 font-semibold text-white hover:bg-indigo-700" > Insert into Editor
@@ -252,9 +252,9 @@ const Images = () => { {isLocalImage(url) && (
handleRemoveLocalImage(url)} - className="w-full border border-black/20 bg-white text-xs font-semibold text-black hover:bg-black hover:text-white" + className="container-fit bg-white border border-black/20 rounded-md p-2.5 transition-300 text-xs font-semibold text-black" > - Remove +
)}
diff --git a/components/Layout/Dashboard/Generate/content/Renderer.tsx b/components/Layout/Dashboard/Generate/content/Renderer.tsx index 03f2f01..38f745d 100644 --- a/components/Layout/Dashboard/Generate/content/Renderer.tsx +++ b/components/Layout/Dashboard/Generate/content/Renderer.tsx @@ -12,11 +12,12 @@ import { Source } from '../RightSidebarPanel'; import EditorLoader from '@/components/Layout/Dashboard/Generate/Editor/EditorLoader'; import { FileText, PenLine, Link as LinkIcon, Code } from 'lucide-react'; import { PromptSelector } from '@/components/Layout/Dashboard/Generate/PromptSelector'; +import { ContentLoadingSkeleton } from '@/components/ui/ContentLoadingSkeleton'; const Editor = dynamic(() => import('../Editor/Editor'), { // Make sure we turn SSR off ssr: false, - loading: () => , + loading: () => , }); export default function Renderer() { diff --git a/components/ui/ContentLoadingSkeleton.tsx b/components/ui/ContentLoadingSkeleton.tsx index abad60d..8f78204 100644 --- a/components/ui/ContentLoadingSkeleton.tsx +++ b/components/ui/ContentLoadingSkeleton.tsx @@ -4,11 +4,12 @@ import { cn } from '@/lib/utils'; import { Skeleton } from '@/components/ui/skeleton'; import { Loader } from 'lucide-react'; -export const ContentLoadingSkeleton = () => { +export const ContentLoadingSkeleton = ({isGenerating = true}) => { return (
{/* 1. Header and Loader */} -
@@ -16,6 +17,16 @@ export const ContentLoadingSkeleton = () => { Generating Content. Please wait...

+ ) : ( +
+ +

+ Loading editor... +

+
+ )} {/* 2. Main Title/Heading Skeleton */}
@@ -47,6 +58,11 @@ export const ContentLoadingSkeleton = () => {
+ {!isGenerating && ( +
+ +
+ )}
); From 0c28214e8a1c9fa5bff68553e4a8baabf296ab24 Mon Sep 17 00:00:00 2001 From: Muhammad-Jay Date: Wed, 3 Dec 2025 10:52:30 +0100 Subject: [PATCH 3/4] refactor: fix performance issue --- components/Landing/Features.tsx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/Landing/Features.tsx b/components/Landing/Features.tsx index 4c28563..6d4856b 100644 --- a/components/Landing/Features.tsx +++ b/components/Landing/Features.tsx @@ -8,22 +8,22 @@ import { cn } from '@/lib/utils'; export default function MonoFeatures() { const [selectedFeature, setSelectedFeature] = React.useState(null); - useEffect(() => { + // useEffect(() => { - let timer = null; - let len = 0; + // let timer = null; + // let len = 0; - while (features.length !== len) { + // while (features.length !== len) { - timer = setTimeout(() => { + // timer = setTimeout(() => { - setSelectedFeature(features[len]); - len++ - if(len === features.length) len = 0 - }, 2000) - } + // setSelectedFeature(features[len]); + // len++ + // if(len === features.length) len = 0 + // }, 2000) + // } - }, []) + // }, []) const features = [ { From 18e453b5258981d5651d3159343f9b6061bb37be Mon Sep 17 00:00:00 2001 From: Muhammad-Jay Date: Wed, 3 Dec 2025 11:55:14 +0100 Subject: [PATCH 4/4] refactor: Optimize landing page components and styling - Replaced direct component imports with memoized versions for performance. - Updated styling in and for scrollbar hiding. - Adjusted component usage in to reflect memoized imports. - Applied to , , , , , and components. - Modified styling in and for visual consistency. - Removed commented-out code in component. --- app/globals.css | 1 + app/layout.tsx | 2 +- app/page.tsx | 17 +++--- .../Landing/AutomationIntegrationSection.tsx | 15 +++-- components/Landing/CTA.tsx | 16 ++--- components/Landing/Features.tsx | 61 ++++++++++--------- components/Landing/Footer.tsx | 6 +- components/Landing/Hero.tsx | 14 +++-- components/Landing/Navbar.tsx | 6 +- 9 files changed, 76 insertions(+), 62 deletions(-) diff --git a/app/globals.css b/app/globals.css index f015b93..797294c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -160,6 +160,7 @@ } } + #hide-scrollbar { /* For Internet Explorer and Edge */ -ms-overflow-style: none; diff --git a/app/layout.tsx b/app/layout.tsx index d3645b0..afd533e 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -28,7 +28,7 @@ export default function RootLayout({ }>) { return ( - + {children} diff --git a/app/page.tsx b/app/page.tsx index caf3c12..4f4fd63 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,9 +1,8 @@ -import MonoHero from '@/components/Landing/Hero'; -import MonoFeatures from '@/components/Landing/Features'; +import Hero from '@/components/Landing/Hero'; +import Features from '@/components/Landing/Features'; import AutomationIntegrationSection from '@/components/Landing/AutomationIntegrationSection'; -import MonoCTA from '@/components/Landing/CTA'; -import MonoFooter from '@/components/Landing/Footer'; -import { Navbar } from '@/components/Landing/Navbar'; +import CTA from '@/components/Landing/CTA'; +import Footer from '@/components/Landing/Footer'; import { cn } from '@/lib/utils'; import { Metadata } from 'next'; @@ -63,11 +62,11 @@ export default function LandingPage() { id={'hide-scrollbar'} > {/* */} - - + + - - + +
); diff --git a/components/Landing/AutomationIntegrationSection.tsx b/components/Landing/AutomationIntegrationSection.tsx index 852d390..831d0e6 100644 --- a/components/Landing/AutomationIntegrationSection.tsx +++ b/components/Landing/AutomationIntegrationSection.tsx @@ -1,6 +1,6 @@ 'use client' -import React from 'react'; +import React, { memo } from 'react'; import { motion } from 'framer-motion'; const Container = ({ children, className = '' }) => ( @@ -50,9 +50,12 @@ const AnimatedPipelineCore = () => { {/* The main pipeline path (dashed and subtle) */} @@ -118,7 +121,7 @@ const automationSteps = [ ]; // Main section component using the new Animated Pipeline -export default function AutomationIntegrationSection() { +function AutomationIntegrationSection() { return (
@@ -168,7 +171,7 @@ export default function AutomationIntegrationSection() { whileHover={{ scale: 1.02 }} className={` - p-6 rounded-lg bg-white/90 backdrop-blur-sm border shadow-neutral-300 border-neutral-100 shadow-xl + p-6 rounded-lg bg-white/90 backdrop-blur-sm border shadow-neutral-400 border-neutral-100 shadow-xl mx-auto max-w-lg w-full text-left @@ -203,4 +206,6 @@ export default function AutomationIntegrationSection() {
); -} \ No newline at end of file +} + +export default memo(AutomationIntegrationSection); \ No newline at end of file diff --git a/components/Landing/CTA.tsx b/components/Landing/CTA.tsx index 7eb5133..8c693aa 100644 --- a/components/Landing/CTA.tsx +++ b/components/Landing/CTA.tsx @@ -1,26 +1,28 @@ 'use client' -import React from 'react'; +import React, { memo } from 'react'; import { Button } from '@/components/ui/button'; import Link from 'next/link'; import { motion } from 'framer-motion'; -export default function MonoCTA() { +function CTA() { return (
- +
-

Start creating memorable content today.

-

Try ThinkInk for free no credit card required. Scale your writing workflows with minimal overhead.

+

Start creating memorable content today.

+

Try Think-Ink for free no credit card required. Scale your writing workflows with minimal overhead.

- - + +
); } + +export default memo(CTA); \ No newline at end of file diff --git a/components/Landing/Features.tsx b/components/Landing/Features.tsx index 6d4856b..05e4911 100644 --- a/components/Landing/Features.tsx +++ b/components/Landing/Features.tsx @@ -1,31 +1,12 @@ 'use client' -import React, { useEffect } from 'react'; +import React, { memo, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import {Button} from '@/components/ui/button'; import { cn } from '@/lib/utils'; -export default function MonoFeatures() { - const [selectedFeature, setSelectedFeature] = React.useState(null); - // useEffect(() => { - - // let timer = null; - // let len = 0; - - // while (features.length !== len) { - - // timer = setTimeout(() => { - - // setSelectedFeature(features[len]); - // len++ - // if(len === features.length) len = 0 - // }, 2000) - // } - - // }, []) - - const features = [ +const features = [ { id: 'f1', title: 'Two-Stage Refinement Pipeline', @@ -65,6 +46,11 @@ export default function MonoFeatures() { } ]; +function Features() { + const [selectedFeature, setSelectedFeature] = React.useState(features[0]); + + + const handleCardClick = (feature) => { setSelectedFeature(selectedFeature?.id === feature.id ? null : feature); }; @@ -95,7 +81,7 @@ export default function MonoFeatures() { whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true, amount: 0.5 }} transition={{ duration: 0.6 }} - className="text-5xl md:text-6xl font-extrabold text-black tracking-tighter" + className="text-5xl md:text-6xl center font-extrabold text-black tracking-tighter" > Power Engineered for Content Mastery. @@ -104,7 +90,7 @@ export default function MonoFeatures() { whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true, amount: 0.5 }} transition={{ duration: 0.6, delay: 0.1 }} - className="mt-4 max-w-xl text-xl text-neutral-700" + className="mt-4 max-w-xl center text-xl text-neutral-700" > Everything you need to produce polished content quickly reliability without the noise. @@ -161,21 +147,33 @@ export default function MonoFeatures() { exit="exit" className="mt-16 overflow-hidden origin-top" > -
- {/* Reveal Icon and Title */} +
+
{selectedFeature.icon}
-

+

{selectedFeature.title}

- {/* Full Description Text */} -

+ {selectedFeature.fullDescription} -

+ + + + + {/* Closing Button */}
@@ -193,4 +191,7 @@ export default function MonoFeatures() {
); -} \ No newline at end of file +} + + +export default memo(Features) \ No newline at end of file diff --git a/components/Landing/Footer.tsx b/components/Landing/Footer.tsx index ea0666b..d3da2e2 100644 --- a/components/Landing/Footer.tsx +++ b/components/Landing/Footer.tsx @@ -1,8 +1,8 @@ 'use client' -import React from 'react'; +import React, { memo } from 'react'; -export default function MonoFooter() { +function Footer() { return (
@@ -26,3 +26,5 @@ export default function MonoFooter() {
); } + +export default memo(Footer); diff --git a/components/Landing/Hero.tsx b/components/Landing/Hero.tsx index b6224e8..2a4e9a0 100644 --- a/components/Landing/Hero.tsx +++ b/components/Landing/Hero.tsx @@ -1,14 +1,13 @@ 'use client' -import React from 'react'; +import React, { memo } from 'react'; import { motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; import SCREENSHOT_URL from '@/assets/hero_image.png'; import Image from 'next/image'; -import { Navbar } from './Navbar'; +import Navbar from './Navbar'; - -export default function MonoHero() { +function Hero() { return (
{/* 1. Subtle Background Texture (Grain/Vignette) */} @@ -83,7 +82,7 @@ export default function MonoHero() { {/* Right side visual — Platform Screensho */}
+ className="md:col-span-5 flex items-center justify-center md:justify-end mt-12 md:mr-12 md:mt-0">
); -} \ No newline at end of file +} + + +export default memo(Hero); \ No newline at end of file diff --git a/components/Landing/Navbar.tsx b/components/Landing/Navbar.tsx index eb90668..8381ad9 100644 --- a/components/Landing/Navbar.tsx +++ b/components/Landing/Navbar.tsx @@ -4,9 +4,9 @@ import { AnimatePresence, motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; import Link from 'next/link'; import { Menu, X, BookOpen } from 'lucide-react'; -import { useState } from 'react'; +import { memo, useState } from 'react'; -export const Navbar = () => { +const Navbar = () => { const [isMenuOpen, setIsMenuOpen] = useState(false); const toggleMenu = () => { @@ -100,3 +100,5 @@ export const Navbar = () => { ); }; + +export default memo(Navbar);