From 85d9557bbe4ae1a1d2a8cc9457d9c4e6530af929 Mon Sep 17 00:00:00 2001 From: spivakov83 Date: Mon, 29 Sep 2025 21:11:53 +0300 Subject: [PATCH] feat: add animated background and hero components; create existing and new project pages with improved UI and functionality --- app/existing/page.tsx | 21 +++++ app/new/page.tsx | 123 +++++++++++++++++++++++++ app/page.tsx | 145 +++++++----------------------- app/sitemap.ts | 22 +++-- components/AnimatedBackground.tsx | 59 ++++++++++++ components/Hero.tsx | 69 ++++++++++++++ package-lock.json | 43 +++++++++ package.json | 1 + 8 files changed, 360 insertions(+), 123 deletions(-) create mode 100644 app/existing/page.tsx create mode 100644 app/new/page.tsx create mode 100644 components/AnimatedBackground.tsx create mode 100644 components/Hero.tsx diff --git a/app/existing/page.tsx b/app/existing/page.tsx new file mode 100644 index 0000000..9f33e09 --- /dev/null +++ b/app/existing/page.tsx @@ -0,0 +1,21 @@ +import Link from "next/link" + +import { Button } from "@/components/ui/button" + +export default function ExistingProjectPage() { + return ( +
+
+
+

Existing projects are coming soon

+

+ We're crafting guided flows to ingest your current instructions, audit gaps, and align new guidance with your repository. Leave your email in the wizard and we'll reach out the moment it's live. +

+
+ +
+
+ ) +} diff --git a/app/new/page.tsx b/app/new/page.tsx new file mode 100644 index 0000000..a6a814f --- /dev/null +++ b/app/new/page.tsx @@ -0,0 +1,123 @@ +"use client" + +import { useMemo, useState } from "react" + +import { Button } from "@/components/ui/button" +import { InstructionsWizard } from "@/components/instructions-wizard" +import { getHomeMainClasses } from "@/lib/utils" +import { getFormatLabel } from "@/lib/wizard-utils" +import { ANALYTICS_EVENTS } from "@/lib/analytics-events" +import { track } from "@/lib/mixpanel" +import type { FileOutputConfig } from "@/types/wizard" +import { Github } from "lucide-react" +import Link from "next/link" + +import Logo from "@/components/Logo" +import filesData from "@/data/files.json" + +export default function NewInstructionsPage() { + const [showWizard, setShowWizard] = useState(false) + const [selectedFileId, setSelectedFileId] = useState(null) + + const fileOptions = useMemo(() => { + return (filesData as FileOutputConfig[]).filter((file) => file.enabled !== false) + }, []) + + const handleFileCtaClick = (file: FileOutputConfig) => { + setSelectedFileId(file.id) + setShowWizard(true) + track(ANALYTICS_EVENTS.CREATE_INSTRUCTIONS_FILE, { + fileId: file.id, + fileLabel: file.label, + }) + } + + const handleWizardClose = () => { + setShowWizard(false) + setSelectedFileId(null) + } + + return ( +
+ {/* Top utility bar */} +
+ + + +
+ + {/* Hero Section */} +
+ {showWizard && selectedFileId ? ( + + ) : ( + <> +
+ {/* Logo/Title */} + + + {/* Headline */} +

+ Assemble Tailored AI Coding Playbooks With a Guided Wizard +

+ + {/* Subheadline */} +

+ Move from curated best practices to sharable files like Copilot instructions, Cursor rules, and agents.md playbooks in just a few guided steps. +

+ +

+ Use the wizard to generate Copilot instruction files, agents files, comprehensive instruction sets, and Cursor rules without starting from a blank page. +

+ + {/* File type CTAs */} +
+
+ {fileOptions.map((file) => { + const formatLabel = getFormatLabel(file.format) + return ( + + ) + })} +
+
+
+ + )} +
+ +
+ ) +} diff --git a/app/page.tsx b/app/page.tsx index 82d35c7..7c99617 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,123 +1,40 @@ -"use client" - -import { useMemo, useState } from "react" +import Link from "next/link" +import { AnimatedBackground } from "@/components/AnimatedBackground" +import { Hero } from "@/components/Hero" import { Button } from "@/components/ui/button" -import { InstructionsWizard } from "@/components/instructions-wizard" -import { getHomeMainClasses } from "@/lib/utils" -import { getFormatLabel } from "@/lib/wizard-utils" -import { ANALYTICS_EVENTS } from "@/lib/analytics-events" -import { track } from "@/lib/mixpanel" -import type { FileOutputConfig } from "@/types/wizard" import { Github } from "lucide-react" -import Link from "next/link" - -import Logo from "./../components/Logo" -import filesData from "@/data/files.json" - -export default function Home() { - const [showWizard, setShowWizard] = useState(false) - const [selectedFileId, setSelectedFileId] = useState(null) - - const fileOptions = useMemo(() => { - return (filesData as FileOutputConfig[]).filter((file) => file.enabled !== false) - }, []) - - const handleFileCtaClick = (file: FileOutputConfig) => { - setSelectedFileId(file.id) - setShowWizard(true) - track(ANALYTICS_EVENTS.CREATE_INSTRUCTIONS_FILE, { - fileId: file.id, - fileLabel: file.label, - }) - } - - const handleWizardClose = () => { - setShowWizard(false) - setSelectedFileId(null) - } +export default function LandingPage() { return ( -
- {/* Top utility bar */} -
- - - +
+ +
+
+ + DevContext + +
+ + +
+
+ +
+ +
+ +
+ Open-source and community built — keep shipping with more context than commits. +
- - {/* Hero Section */} -
- {showWizard && selectedFileId ? ( - - ) : ( - <> -
- {/* Logo/Title */} - - - {/* Headline */} -

- Assemble Tailored AI Coding Playbooks With a Guided Wizard -

- - {/* Subheadline */} -

- Move from curated best practices to sharable files like Copilot instructions, Cursor rules, and agents.md playbooks in just a few guided steps. -

- -

- Use the wizard to generate Copilot instruction files, agents files, comprehensive instruction sets, and Cursor rules without starting from a blank page. -

- - {/* File type CTAs */} -
-
- {fileOptions.map((file) => { - const formatLabel = getFormatLabel(file.format) - return ( - - ) - })} -
-
-
- - )} -
-
) } diff --git a/app/sitemap.ts b/app/sitemap.ts index 60ee8fa..9023ea7 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -3,14 +3,18 @@ import type { MetadataRoute } from "next"; const baseUrl = "https://devcontext.com"; export default function sitemap(): MetadataRoute.Sitemap { - const lastModified = new Date(); + const lastModified = new Date() - return [ - { - url: baseUrl, - lastModified, - changeFrequency: "weekly", - priority: 1, - }, - ]; + const entries: Array<{ path: string; priority: number; changeFrequency: MetadataRoute.Sitemap[number]["changeFrequency"] }> = [ + { path: "", priority: 1, changeFrequency: "weekly" }, + { path: "/new", priority: 0.9, changeFrequency: "weekly" }, + { path: "/existing", priority: 0.6, changeFrequency: "monthly" }, + ] + + return entries.map(({ path, priority, changeFrequency }) => ({ + url: `${baseUrl}${path}`, + priority, + changeFrequency, + lastModified, + })) } diff --git a/components/AnimatedBackground.tsx b/components/AnimatedBackground.tsx new file mode 100644 index 0000000..d2f12dd --- /dev/null +++ b/components/AnimatedBackground.tsx @@ -0,0 +1,59 @@ +"use client" + +import { motion } from "framer-motion" + +const particles = [ + { left: "8%", top: "18%", size: "h-1.5 w-1.5", delay: 0 }, + { left: "20%", top: "70%", size: "h-2 w-2", delay: 0.6 }, + { left: "32%", top: "40%", size: "h-1 w-1", delay: 0.3 }, + { left: "48%", top: "14%", size: "h-2 w-2", delay: 0.9 }, + { left: "60%", top: "78%", size: "h-1.5 w-1.5", delay: 0.2 }, + { left: "76%", top: "32%", size: "h-1 w-1", delay: 0.75 }, + { left: "88%", top: "58%", size: "h-2 w-2", delay: 0.4 }, + { left: "15%", top: "88%", size: "h-1.5 w-1.5", delay: 1.1 }, + { left: "68%", top: "12%", size: "h-1.5 w-1.5", delay: 1.3 }, + { left: "84%", top: "24%", size: "h-1 w-1", delay: 1.6 }, +] + +export function AnimatedBackground() { + return ( +
+ + + + + + + + + {particles.map((particle, index) => ( + + ))} + +
+
+ ) +} diff --git a/components/Hero.tsx b/components/Hero.tsx new file mode 100644 index 0000000..d37a7ee --- /dev/null +++ b/components/Hero.tsx @@ -0,0 +1,69 @@ +"use client" + +import { motion } from "framer-motion" +import { ArrowRight } from "lucide-react" +import Link from "next/link" + +import { Button } from "@/components/ui/button" + +const containerVariants = { + hidden: { opacity: 0 }, + show: { + opacity: 1, + transition: { staggerChildren: 0.15, delayChildren: 0.2 }, + }, +} + +const itemVariants = { + hidden: { opacity: 0, y: 28 }, + show: { opacity: 1, y: 0, transition: { ease: "easeOut", duration: 0.7 } }, +} + +export function Hero() { + return ( + + + + + Crafted for engineering teams shipping with AI + + + DevContext — AI Coding Guidelines & Context Generator + + + Generate AI config files like Copilot instructions, Cursor rules, and prompts — consistent, fast, and IDE-ready. Bring product context, architecture, and workflow nuance into every coding session. + + + + + + + + ) +} diff --git a/package-lock.json b/package-lock.json index a3a52fd..5871d48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@radix-ui/react-slot": "^1.2.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "framer-motion": "^11.18.2", "lucide-react": "^0.544.0", "mixpanel-browser": "^2.70.0", "next": "15.5.3", @@ -5404,6 +5405,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -6901,6 +6929,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 9d11d79..244c49d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@radix-ui/react-slot": "^1.2.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "framer-motion": "^11.18.2", "lucide-react": "^0.544.0", "mixpanel-browser": "^2.70.0", "next": "15.5.3",