From 33c5121405c319896e9b197d14a4b188f4bc89b0 Mon Sep 17 00:00:00 2001 From: Julkar Naen Nahian Date: Sun, 30 Nov 2025 23:34:01 +0600 Subject: [PATCH 1/5] feat: enhance landing page with new visual components, animations, and updated styling. --- web/package-lock.json | 49 ++++ web/package.json | 11 +- web/src/components/landing/CTASection.tsx | 53 ++-- .../components/landing/FeaturesSection.tsx | 55 ++-- web/src/components/landing/HeroSection.tsx | 163 +++++++----- web/src/components/landing/HeroVisual.tsx | 74 ++++++ .../landing/ProblemSolutionSection.tsx | 237 ++++++++++-------- web/src/components/landing/ProblemVisual.tsx | 97 +++++++ .../components/landing/QuickStartSection.tsx | 157 ++++++------ web/src/components/landing/SolutionVisual.tsx | 102 ++++++++ web/src/components/landing/StatsSection.tsx | 67 ++--- web/src/index.css | 36 ++- 12 files changed, 780 insertions(+), 321 deletions(-) create mode 100644 web/src/components/landing/HeroVisual.tsx create mode 100644 web/src/components/landing/ProblemVisual.tsx create mode 100644 web/src/components/landing/SolutionVisual.tsx diff --git a/web/package-lock.json b/web/package-lock.json index 7a37d15..f526cce 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11,6 +11,7 @@ "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", + "framer-motion": "^12.23.24", "lucide-react": "^0.294.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -3178,6 +3179,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", + "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.23", + "motion-utils": "^12.23.6", + "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/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -3922,6 +3950,21 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/motion-dom": { + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5375,6 +5418,12 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/web/package.json b/web/package.json index 7e723a7..ffda638 100644 --- a/web/package.json +++ b/web/package.json @@ -15,19 +15,20 @@ "preview": "vite preview" }, "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.20.1", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", + "framer-motion": "^12.23.24", "lucide-react": "^0.294.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.1", "tailwind-merge": "^2.0.0" }, "devDependencies": { + "@types/express": "^4.17.21", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", - "@types/express": "^4.17.21", "@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/parser": "^6.10.0", "@vitejs/plugin-react": "^4.1.1", @@ -42,4 +43,4 @@ "typescript": "^5.2.2", "vite": "^7.1.11" } -} \ No newline at end of file +} diff --git a/web/src/components/landing/CTASection.tsx b/web/src/components/landing/CTASection.tsx index e3f3bbc..f090b81 100644 --- a/web/src/components/landing/CTASection.tsx +++ b/web/src/components/landing/CTASection.tsx @@ -1,22 +1,41 @@ import { Button } from "@/components/ui/button"; import { Download, Github } from "lucide-react"; -import { AnimatedSection } from "@/components/AnimatedSection"; +import { motion } from "framer-motion"; export function CTASection() { return ( -
-
- -

- Ready to Enhance Your Code? -

-

- Join developers who are already using Code Context Notes to document - and track their code more effectively. -

+
+ {/* Background Pattern */} +
- - - - - - + +
); diff --git a/web/src/components/landing/FeaturesSection.tsx b/web/src/components/landing/FeaturesSection.tsx index e13f994..518a51d 100644 --- a/web/src/components/landing/FeaturesSection.tsx +++ b/web/src/components/landing/FeaturesSection.tsx @@ -13,7 +13,7 @@ import { Users, Layers, } from "lucide-react"; -import { AnimatedSection } from "@/components/AnimatedSection"; +import { motion } from "framer-motion"; export function FeaturesSection() { const features = [ @@ -62,34 +62,47 @@ export function FeaturesSection() { ]; return ( -
-
- -

- Why Choose Code Context Notes? -

-

- Built for developers who need reliable, intelligent code annotation - that scales with their projects. -

-
+
+ {/* Background Pattern */} +
+ +
+
+ +

+ Why Choose Code Context Notes? +

+

+ Built for developers who need reliable, intelligent code annotation + that scales with their projects. +

+
+
{features.map((feature, index) => ( - - + - - {feature.title} - {feature.description} +
+ +
+ {feature.title} + {feature.description}
-
+ ))}
diff --git a/web/src/components/landing/HeroSection.tsx b/web/src/components/landing/HeroSection.tsx index 7efb597..b94b34d 100644 --- a/web/src/components/landing/HeroSection.tsx +++ b/web/src/components/landing/HeroSection.tsx @@ -2,83 +2,114 @@ import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Download, FileText, CheckCircle } from "lucide-react"; import { Link } from "react-router-dom"; +import { motion } from "framer-motion"; +import { HeroVisual } from "./HeroVisual"; export function HeroSection() { return ( -
-
-
-
- Code Context Notes Logo -
+
+ {/* Background Pattern */} +
- - VS Code Extension - + {/* Gradient Blob */} +
+
-

- Code Annotations Without the{" "} - Code Pollution -

+
+
+ {/* Left Column: Content */} +
+ + + + + + + + v1.0 is now live + + + -

- Stop cluttering your source files with comments. Add contextual notes that live alongside your code, - track automatically through refactoring, and maintain complete version history. -

+ + Code Annotations Without the{" "} + + Code Pollution + + -
- + + Stop cluttering your source files with comments. Add contextual notes that live alongside your code, + track automatically through refactoring, and maintain complete version history. + - + + + + + - + +
+ + Free & Open Source +
+
+ + Works with All Languages +
+
+ + Git Integration +
+
-
-
- - Free & Open Source -
-
- - Works with All Languages -
-
- - 88% Test Coverage -
+ {/* Right Column: Visual */} +
+
diff --git a/web/src/components/landing/HeroVisual.tsx b/web/src/components/landing/HeroVisual.tsx new file mode 100644 index 0000000..787aaec --- /dev/null +++ b/web/src/components/landing/HeroVisual.tsx @@ -0,0 +1,74 @@ +import { motion } from "framer-motion"; +import { FileCode, MessageSquarePlus } from "lucide-react"; + +export function HeroVisual() { + return ( +
+ {/* Background Glow */} +
+ + {/* Mock Editor Window */} + + {/* Window Header */} +
+
+
+
+
+
+
+ + utils.ts +
+
+ + {/* Code Content */} +
+
+ 1 + export function calculateTotal(items) {`{`} +
+
+ 2 + return items.reduce((acc, item) => acc + item.price, 0); +
+
+ 3 + {'}'} + + {/* Animated Note */} + +
+ +
+

Refactor needed

+

Add tax calculation logic here before returning the final total.

+
+
+ {/* Connector Line */} +
+
+ +
+
+ 4 +
+
+ 5 + // End of file +
+
+
+
+ ); +} diff --git a/web/src/components/landing/ProblemSolutionSection.tsx b/web/src/components/landing/ProblemSolutionSection.tsx index f85956b..d951046 100644 --- a/web/src/components/landing/ProblemSolutionSection.tsx +++ b/web/src/components/landing/ProblemSolutionSection.tsx @@ -1,7 +1,9 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { X, Check, AlertCircle, Lightbulb } from "lucide-react"; -import { AnimatedSection } from "@/components/AnimatedSection"; +import { motion } from "framer-motion"; +import { ProblemVisual } from "./ProblemVisual"; +import { SolutionVisual } from "./SolutionVisual"; export function ProblemSolutionSection() { const problems = [ @@ -11,8 +13,6 @@ export function ProblemSolutionSection() { "Clutter your source files with non-code content", "Get committed to version control, polluting git history", "Mix documentation with implementation", - "No version history for the comments themselves", - "Can't be easily filtered or searched separately", ], }, { @@ -21,7 +21,6 @@ export function ProblemSolutionSection() { "Quickly becomes outdated as code changes", "Disconnected from the actual code location", "Requires context switching between editor and docs", - "Hard to maintain alignment with code", ], }, ]; @@ -43,14 +42,6 @@ export function ProblemSolutionSection() { title: "Team collaboration", description: "Share notes by committing .code-notes/ or keep them local with .gitignore", }, - { - title: "Native integration", - description: "Uses VSCode's comment UI for a familiar, seamless experience", - }, - { - title: "Zero performance impact", - description: "Efficient caching and content hash tracking", - }, ]; const useCases = [ @@ -62,103 +53,149 @@ export function ProblemSolutionSection() { ]; return ( -
-
- {/* Problem Section */} - - - - The Problem - -

- The Developer's Documentation Dilemma -

-

- Working on complex codebases, developers face a common challenge: where to keep important context? -

-
+
+ {/* Background Elements */} +
+ +
-
- {problems.map((problem, index) => ( - + {/* Left: Text & Cards */} +
+ - - - - - {problem.category} - - - -
    - {problem.issues.map((issue, i) => ( -
  • - - {issue} -
  • - ))} -
-
-
- - ))} + + + The Problem + +

+ The Developer's Documentation Dilemma +

+

+ Working on complex codebases, developers face a common challenge: where to keep important context? Inline comments clutter code, while external docs get outdated. +

+
+ +
+ {problems.map((problem, index) => ( + + + + + + {problem.category} + + + +
    + {problem.issues.map((issue, i) => ( +
  • + + {issue} +
  • + ))} +
+
+
+
+ ))} +
+
+ + {/* Right: Visual */} +
+ +
- -
- + {/* TRANSITION */} + +
+
-

- The result? Important context gets lost, technical debt goes undocumented, -
- and new team members struggle to understand the codebase. +

+ The result? Important context gets lost, technical debt goes undocumented, and new team members struggle.

- +
- {/* Solution Section */} - - - - The Solution - -

- A Third Way: Contextual Annotations -

-

- Code Context Notes provides annotations that live alongside your code without being part of it. -

-
+ {/* SOLUTION SECTION */} +
+ {/* Left: Visual (Desktop) */} +
+ +
-
- {solutions.map((solution, index) => ( - + - - - - - {solution.title} - - - -

{solution.description}

-
-
-
- ))} + + + The Solution + +

+ A Third Way: Contextual Annotations +

+

+ Code Context Notes provides annotations that live alongside your code without being part of it. Keep your source clean while maintaining rich documentation. +

+ + +
+ {solutions.map((solution, index) => ( + + + + + + {solution.title} + + + +

{solution.description}

+
+
+
+ ))} +
+
{/* Use Cases */} - - + + Perfect For @@ -167,16 +204,16 @@ export function ProblemSolutionSection() { {useCases.map((useCase, index) => (
- {useCase} + {useCase}
))}
-
+
); diff --git a/web/src/components/landing/ProblemVisual.tsx b/web/src/components/landing/ProblemVisual.tsx new file mode 100644 index 0000000..65921b7 --- /dev/null +++ b/web/src/components/landing/ProblemVisual.tsx @@ -0,0 +1,97 @@ +import { motion } from "framer-motion"; +import { FileCode, XCircle } from "lucide-react"; + +export function ProblemVisual() { + return ( +
+ {/* Messy File Window */} + + {/* Header */} +
+
+
+
+
+
+
+ + messy_component.ts +
+
+ + {/* Code Content with Clutter */} +
+ {/* Code Line */} +
+ 1 + const data = fetchData(); +
+ + {/* Clutter Comments */} + + 2 + // TODO: Refactor this later, it's causing memory leaks in prod + + + {/* Code Line */} +
+ 3 + if (!data) return null; +
+ + {/* More Clutter */} + + 4 + // FIXME: This check fails if data is 0. Need to check undefined. + + + 5 + // @deprecated: Use new API v2 endpoint instead + + + {/* Code Line */} +
+ 6 + process(data); +
+
+ + {/* Warning Overlay */} + + + Polluted Source + + +
+ ); +} diff --git a/web/src/components/landing/QuickStartSection.tsx b/web/src/components/landing/QuickStartSection.tsx index 5080083..7b80ff1 100644 --- a/web/src/components/landing/QuickStartSection.tsx +++ b/web/src/components/landing/QuickStartSection.tsx @@ -7,7 +7,7 @@ import { CardTitle, } from "@/components/ui/card"; import { CheckCircle } from "lucide-react"; -import { AnimatedSection } from "@/components/AnimatedSection"; +import { motion } from "framer-motion"; export function QuickStartSection() { const steps = [ @@ -17,16 +17,16 @@ export function QuickStartSection() { description: "Highlight the lines of code you want to annotate. Works with any programming language and file type.", content: ( -
+
- + function calculateTotal() {"{"}
- + {" "} return items.reduce... @@ -66,24 +66,24 @@ export function QuickStartSection() { description: "Type your note with full markdown support, then save. Your note is now tracked with complete history.", content: ( -
+
- + **TODO:** Optimize this function
- + Consider using `Map` for O(1) lookup
@@ -95,79 +95,84 @@ export function QuickStartSection() { ]; return ( -
-
- -

- Get Started in Seconds -

-

- Three simple steps to start annotating your code with intelligent - tracking and full history -

-
+
+ {/* Background Pattern */} +
- -
- {/* Connection Lines for Desktop */} -
-
-
-
-
-
+
+
+ +

+ Get Started in Seconds +

+

+ Three simple steps to start annotating your code with intelligent + tracking and full history +

+
+
-
- {steps.map((step, index) => ( - - - -
-
- {step.number} -
-
-
- - {step.title} - - - {step.description} - -
- {step.content} -
-
- ))} +
+ {/* Connection Lines for Desktop */} +
+
+
+
+
- {/* Bottom CTA */} - -
- - - That's it! Your code is now annotated with intelligent - tracking. - -
-
+
+ {steps.map((step, index) => ( + + + +
+
+ {step.number} +
+
+
+ {step.title} + + {step.description} + +
+ {step.content} +
+
+ ))}
- + + {/* Bottom CTA */} + +
+ + + That's it! Your code is now annotated with intelligent tracking. + +
+
+
); diff --git a/web/src/components/landing/SolutionVisual.tsx b/web/src/components/landing/SolutionVisual.tsx new file mode 100644 index 0000000..8d5ff40 --- /dev/null +++ b/web/src/components/landing/SolutionVisual.tsx @@ -0,0 +1,102 @@ +import { motion } from "framer-motion"; +import { FileCode, CheckCircle, ArrowRight } from "lucide-react"; + +export function SolutionVisual() { + return ( +
+
+ + {/* Clean File Window */} + + {/* Header */} +
+
+
+
+
+
+
+ + clean_component.ts +
+
+ + {/* Clean Code Content */} +
+
+ 1 + const data = fetchData(); +
+
+ 2 + if (!data) return null; +
+
+ 3 + process(data); +
+
+ + {/* Success Badge */} + + + Clean + + + + {/* Connector */} + +
+
+ +
+
+ + + {/* External Note Window */} + + {/* Note Header */} +
+
+ Context Note +
+
+ + {/* Note Content */} +
+

Refactor Plan

+

This null check is temporary. We need to update the API client to handle 404s gracefully.

+
+
+ Added by @jnahian • 2h ago +
+
+ +
+
+ ); +} diff --git a/web/src/components/landing/StatsSection.tsx b/web/src/components/landing/StatsSection.tsx index 050c26c..aa22afa 100644 --- a/web/src/components/landing/StatsSection.tsx +++ b/web/src/components/landing/StatsSection.tsx @@ -8,7 +8,7 @@ import { History, FileText, } from "lucide-react"; -import { AnimatedSection } from "@/components/AnimatedSection"; +import { motion } from "framer-motion"; export function StatsSection() { const stats = [ @@ -57,82 +57,89 @@ export function StatsSection() { ]; return ( -
+
{/* Background Pattern */} -
-
-
-
-
-
+
+ + {/* Decorative Blobs */} +
+
- -

+ +

Trusted by Developers Worldwide

-

+

Built with quality, tested thoroughly, and designed for reliability

- +
{stats.map((stat, index) => ( - - +
-
+
{stat.value}
-
+
{stat.label}
-
+
{stat.description}
- + ))}
{/* Additional Trust Indicators */}
{trustIndicators.map((indicator, index) => ( - -
+
-
+
-

+

{indicator.title}

-

+

{indicator.description}

- + ))}
diff --git a/web/src/index.css b/web/src/index.css index 3a80262..6c55714 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -132,11 +132,34 @@ } .shadow-brand-glow { - box-shadow: 0 0 20px rgba(255, 138, 61, 0.25); + box-shadow: 0 0 40px -10px rgba(255, 138, 61, 0.5); } .shadow-brand-drop { - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.20); + box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.2); + } + + /* New Gradients */ + .bg-gradient-brand { + background-image: linear-gradient(135deg, #FF8A3D 0%, #FF4500 100%); + } + + .bg-gradient-dark { + background-image: linear-gradient(135deg, #0B1220 0%, #1a2c4e 100%); + } + + /* Geometric Patterns */ + .bg-grid-pattern { + background-size: 40px 40px; + background-image: linear-gradient(to right, rgba(255, 138, 61, 0.05) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255, 138, 61, 0.05) 1px, transparent 1px); + mask-image: linear-gradient(to bottom, black 40%, transparent 100%); + -webkit-mask-image: linear-gradient(to bottom, black 40%, transparent 100%); + } + + .dark .bg-grid-pattern { + background-image: linear-gradient(to right, rgba(255, 138, 61, 0.03) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255, 138, 61, 0.03) 1px, transparent 1px); } } @@ -189,18 +212,19 @@ .animate-slide-up { animation: slide-up 0.6s ease-out forwards; } - + /* Viewport animation optimizations */ .will-change-transform { will-change: transform; } - + .will-change-opacity { will-change: opacity; } - + /* Reduce motion for accessibility */ @media (prefers-reduced-motion: reduce) { + .animate-in, .animate-float, .animate-pulse-glow, @@ -208,7 +232,7 @@ animation: none !important; transition: none !important; } - + .transition-all, .transition-transform, .transition-opacity { From 2ea036105c4d952e03a5292e9078af6f67f58c47 Mon Sep 17 00:00:00 2001 From: Julkar Naen Nahian Date: Mon, 1 Dec 2025 12:24:30 +0600 Subject: [PATCH 2/5] feat: Rework landing page problem/solution section with a new comparison visual and add UI label and switch components. --- web/components.json | 22 ++ web/package-lock.json | 232 ++++++++++++++++- web/package.json | 8 +- .../components/landing/ComparisonVisual.tsx | 214 ++++++++++++++++ .../landing/ProblemSolutionSection.tsx | 242 +++++------------- web/src/components/ui/label.tsx | 26 ++ web/src/components/ui/switch.tsx | 27 ++ web/src/index.css | 82 +++--- web/src/lib/utils.ts | 4 +- web/tailwind.config.js | 141 +++++----- 10 files changed, 707 insertions(+), 291 deletions(-) create mode 100644 web/components.json create mode 100644 web/src/components/landing/ComparisonVisual.tsx create mode 100644 web/src/components/ui/label.tsx create mode 100644 web/src/components/ui/switch.tsx diff --git a/web/components.json b/web/components.json new file mode 100644 index 0000000..1537d50 --- /dev/null +++ b/web/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/web/package-lock.json b/web/package-lock.json index f526cce..652a252 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,15 +8,17 @@ "name": "code-context-notes-web", "version": "0.0.0", "dependencies": { + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.0.2", - "class-variance-authority": "^0.7.0", - "clsx": "^2.0.0", + "@radix-ui/react-switch": "^1.2.6", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "framer-motion": "^12.23.24", "lucide-react": "^0.294.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.20.1", - "tailwind-merge": "^2.0.0" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/express": "^4.17.21", @@ -1089,6 +1091,12 @@ "node": ">=14" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1104,7 +1112,138 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", @@ -1122,6 +1261,91 @@ } } }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { "version": "1.23.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", @@ -1612,7 +1836,7 @@ "version": "18.3.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^18.0.0" diff --git a/web/package.json b/web/package.json index ffda638..935dbb9 100644 --- a/web/package.json +++ b/web/package.json @@ -15,15 +15,17 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.0.2", - "class-variance-authority": "^0.7.0", - "clsx": "^2.0.0", + "@radix-ui/react-switch": "^1.2.6", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "framer-motion": "^12.23.24", "lucide-react": "^0.294.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.20.1", - "tailwind-merge": "^2.0.0" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/web/src/components/landing/ComparisonVisual.tsx b/web/src/components/landing/ComparisonVisual.tsx new file mode 100644 index 0000000..28b57f3 --- /dev/null +++ b/web/src/components/landing/ComparisonVisual.tsx @@ -0,0 +1,214 @@ +import { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { FileCode, ArrowRight, Check, X } from "lucide-react"; +import { Switch } from "@/components/ui/switch"; +import { cn } from "@/lib/utils"; + +export function ComparisonVisual() { + const [isClean, setIsClean] = useState(false); + + return ( +
+ {/* Controls */} +
+
+
setIsClean(false)} + > + + Legacy Comments +
+ +
setIsClean(true)} + > + + Context Notes +
+
+
+ + {/* Editor Window */} +
+ {/* Window Header */} +
+
+
+
+
+
+
+
+
+ + payment-processor.ts +
+
+
TypeScript
+
+ +
+ {/* Code Area */} +
+
+ {Array.from({ length: 15 }).map((_, i) => ( +
{i + 1}
+ ))} +
+ +
+ + + + +
+ + + + {/* Clutter Comment 1 */} + + {!isClean && ( + +
+ // TODO: This timeout logic is flaky on weekends. Needs fix. +
+
+ )} +
+ + + + + + + {/* Clutter Comment 2 */} + + {!isClean && ( + +
+ // FIXME: Legacy API endpoint. Migration planned for Q4. +
+
+ )} +
+ + + + + + +
+
+ + {/* Context Sidebar */} + +
+
+ Context Notes + 2 Active +
+ +
+ {/* Note 1 */} + +
+
+
+ Line 8 +
+ Just now +
+

+ TODO: This timeout logic is flaky on weekends. Needs fix. +

+
+
+
+
+ +
+ + + {/* Note 2 */} + +
+
+
+ Line 12 +
+ 2d ago +
+

+ FIXME: Legacy API endpoint. Migration planned for Q4. +

+ +
+
+ +
+
+
+ ); +} + +function CodeLine({ line, indent = 0 }: { line: string; indent?: number }) { + // Simple syntax highlighting simulation + const parts = line.split(/(\s+|[{}().,;:'"]|const|async|function|interface|return|throw|new|if|await)/g); + + return ( +
+
+ {parts.map((part, i) => { + if (!part) return null; + let color = "text-slate-300"; + if (["const", "async", "function", "interface", "return", "throw", "new", "if", "await"].includes(part)) color = "text-purple-400"; + else if (["string", "number", "PaymentConfig", "Error"].includes(part)) color = "text-yellow-300"; + else if (part.startsWith("'")) color = "text-green-400"; + else if (["gateway", "timeout", "amount", "status", "data"].includes(part)) color = "text-blue-300"; + + return {part}; + })} +
+
+ ); +} diff --git a/web/src/components/landing/ProblemSolutionSection.tsx b/web/src/components/landing/ProblemSolutionSection.tsx index d951046..53a092d 100644 --- a/web/src/components/landing/ProblemSolutionSection.tsx +++ b/web/src/components/landing/ProblemSolutionSection.tsx @@ -1,55 +1,26 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { X, Check, AlertCircle, Lightbulb } from "lucide-react"; +import { AlertCircle, GitBranch, MessageSquare, Search } from "lucide-react"; import { motion } from "framer-motion"; -import { ProblemVisual } from "./ProblemVisual"; -import { SolutionVisual } from "./SolutionVisual"; +import { ComparisonVisual } from "./ComparisonVisual"; export function ProblemSolutionSection() { - const problems = [ + const benefits = [ { - category: "Code Comments", - issues: [ - "Clutter your source files with non-code content", - "Get committed to version control, polluting git history", - "Mix documentation with implementation", - ], + icon: GitBranch, + title: "Clean Source Control", + description: "Your code stays pure. Notes live in separate files, keeping your git history focused on logic changes, not comments.", }, { - category: "External Documentation", - issues: [ - "Quickly becomes outdated as code changes", - "Disconnected from the actual code location", - "Requires context switching between editor and docs", - ], - }, - ]; - - const solutions = [ - { - title: "Non-invasive", - description: "Notes stored separately in .code-notes/ directory, never touching your source files", + icon: MessageSquare, + title: "Rich Context", + description: "Write full markdown documentation, add links, and have discussions without worrying about cluttering the file.", }, { - title: "Intelligent tracking", - description: "Notes follow your code even when you move, rename, or refactor it", + icon: Search, + title: "Discoverable Knowledge", + description: "Notes are indexed and searchable. Find why a decision was made without hunting through git blame.", }, - { - title: "Complete history", - description: "Every edit preserved with timestamps and authors", - }, - { - title: "Team collaboration", - description: "Share notes by committing .code-notes/ or keep them local with .gitignore", - }, - ]; - - const useCases = [ - "Documenting technical debt and TODOs", - "Onboarding new developers with contextual explanations", - "Recording implementation decisions and trade-offs", - "Leaving breadcrumbs for future refactoring", - "Team knowledge sharing without code pollution", ]; return ( @@ -59,161 +30,66 @@ export function ProblemSolutionSection() {
- {/* PROBLEM SECTION */} -
- {/* Left: Text & Cards */} -
- - - - The Problem - -

- The Developer's Documentation Dilemma -

-

- Working on complex codebases, developers face a common challenge: where to keep important context? Inline comments clutter code, while external docs get outdated. -

-
- -
- {problems.map((problem, index) => ( - - - - - - {problem.category} - - - -
    - {problem.issues.map((issue, i) => ( -
  • - - {issue} -
  • - ))} -
-
-
-
- ))} -
-
- - {/* Right: Visual */} -
- -
+ {/* Header */} +
+ + + + The Documentation Dilemma + +

+ Stop Polluting Your Codebase +

+

+ Inline comments are messy, hard to track, and get outdated.
+ See how Code Context Notes cleans up your workflow. +

+
- {/* TRANSITION */} + {/* Interactive Comparison */} -
- -
-

- The result? Important context gets lost, technical debt goes undocumented, and new team members struggle. -

+
- {/* SOLUTION SECTION */} -
- {/* Left: Visual (Desktop) */} -
- -
- - {/* Right: Text & Cards */} -
+ {/* Benefits Grid */} +
+ {benefits.map((benefit, index) => ( - - - The Solution - -

- A Third Way: Contextual Annotations -

-

- Code Context Notes provides annotations that live alongside your code without being part of it. Keep your source clean while maintaining rich documentation. -

+ + +
+ +
+ {benefit.title} +
+ +

+ {benefit.description} +

+
+
- -
- {solutions.map((solution, index) => ( - - - - - - {solution.title} - - - -

{solution.description}

-
-
-
- ))} -
-
+ ))}
- {/* Use Cases */} - - - - Perfect For - - -
- {useCases.map((useCase, index) => ( -
- - {useCase} -
- ))} -
-
-
-

); diff --git a/web/src/components/ui/label.tsx b/web/src/components/ui/label.tsx new file mode 100644 index 0000000..5341821 --- /dev/null +++ b/web/src/components/ui/label.tsx @@ -0,0 +1,26 @@ +"use client" + +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/web/src/components/ui/switch.tsx b/web/src/components/ui/switch.tsx new file mode 100644 index 0000000..455c23b --- /dev/null +++ b/web/src/components/ui/switch.tsx @@ -0,0 +1,27 @@ +import * as React from "react" +import * as SwitchPrimitives from "@radix-ui/react-switch" + +import { cn } from "@/lib/utils" + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +Switch.displayName = SwitchPrimitives.Root.displayName + +export { Switch } diff --git a/web/src/index.css b/web/src/index.css index 6c55714..12a5107 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -4,82 +4,92 @@ @layer base { :root { - --background: 42 33% 95%; + --background: 0 0% 100%; /* F4F1E9 - Pin & Note base (warm white) */ - --foreground: 215 85% 9%; + --foreground: 0 0% 3.9%; /* 0B1220 - Navy (braces & note lines) */ - --card: 42 33% 95%; + --card: 0 0% 100%; /* F4F1E9 - Pin & Note base (warm white) */ - --card-foreground: 215 85% 9%; + --card-foreground: 0 0% 3.9%; /* 0B1220 - Navy */ - --popover: 42 33% 95%; + --popover: 0 0% 100%; /* F4F1E9 */ - --popover-foreground: 215 85% 9%; + --popover-foreground: 0 0% 3.9%; /* 0B1220 */ - --primary: 22 100% 61%; + --primary: 0 0% 9%; /* FF8A3D - Primary Orange */ - --primary-foreground: 0 0% 100%; + --primary-foreground: 0 0% 98%; /* FFFFFF - Pin highlight */ - --secondary: 215 85% 9%; + --secondary: 0 0% 96.1%; /* 0B1220 - Navy */ - --secondary-foreground: 42 33% 95%; + --secondary-foreground: 0 0% 9%; /* F4F1E9 */ - --muted: 215 43% 13%; + --muted: 0 0% 96.1%; /* 142036 - Navy soft (inner shadow) */ - --muted-foreground: 215 43% 35%; + --muted-foreground: 0 0% 45.1%; /* Lighter navy for better contrast on light backgrounds */ - --accent: 22 100% 70%; + --accent: 0 0% 96.1%; /* FFA766 - Orange highlight */ - --accent-foreground: 215 85% 9%; + --accent-foreground: 0 0% 9%; /* 0B1220 */ --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - --border: 22 100% 70%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; /* FFA766 - Orange highlight */ - --input: 215 43% 13%; + --input: 0 0% 89.8%; /* 142036 */ - --ring: 22 100% 61%; + --ring: 0 0% 3.9%; /* FF8A3D - Primary Orange */ --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; } .dark { - --background: 215 85% 9%; + --background: 0 0% 3.9%; /* 0B1220 - Navy (dark mode background) */ - --foreground: 42 33% 95%; + --foreground: 0 0% 98%; /* F4F1E9 - Pin & Note base (warm white) */ - --card: 215 43% 13%; + --card: 0 0% 3.9%; /* 142036 - Navy soft */ - --card-foreground: 42 33% 95%; + --card-foreground: 0 0% 98%; /* F4F1E9 */ - --popover: 215 43% 13%; + --popover: 0 0% 3.9%; /* 142036 */ - --popover-foreground: 42 33% 95%; + --popover-foreground: 0 0% 98%; /* F4F1E9 */ - --primary: 22 100% 61%; + --primary: 0 0% 98%; /* FF8A3D - Primary Orange */ - --primary-foreground: 0 0% 100%; + --primary-foreground: 0 0% 9%; /* FFFFFF - Pin highlight */ - --secondary: 215 43% 13%; + --secondary: 0 0% 14.9%; /* 142036 - Navy soft */ - --secondary-foreground: 42 33% 95%; + --secondary-foreground: 0 0% 98%; /* F4F1E9 */ - --muted: 215 43% 13%; + --muted: 0 0% 14.9%; /* 142036 - Navy soft */ - --muted-foreground: 42 33% 95%; + --muted-foreground: 0 0% 63.9%; /* F4F1E9 */ - --accent: 22 100% 70%; + --accent: 0 0% 14.9%; /* FFA766 - Orange highlight */ - --accent-foreground: 215 85% 9%; + --accent-foreground: 0 0% 98%; /* 0B1220 */ --destructive: 0 62.8% 30.6%; - --destructive-foreground: 210 40% 98%; - --border: 215 43% 13%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; /* 142036 - Navy soft */ - --input: 215 43% 13%; + --input: 0 0% 14.9%; /* 142036 */ - --ring: 22 100% 61%; + --ring: 0 0% 83.1%; /* FF8A3D - Primary Orange */ + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; } } diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 1a860ee..bd0c391 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { type ClassValue, clsx } from "clsx" +import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) -} \ No newline at end of file +} diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 7cb7e37..dc1ad0e 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -9,69 +9,84 @@ module.exports = { ], prefix: "", theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, - }, - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, - }, + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px' + } + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + keyframes: { + 'accordion-down': { + from: { + height: '0' + }, + to: { + height: 'var(--radix-accordion-content-height)' + } + }, + 'accordion-up': { + from: { + height: 'var(--radix-accordion-content-height)' + }, + to: { + height: '0' + } + } + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out' + } + } }, plugins: [require("tailwindcss-animate")], } \ No newline at end of file From 8a5bd4b8ed21890578c09ee25961e100455a7b46 Mon Sep 17 00:00:00 2001 From: Julkar Naen Nahian Date: Tue, 2 Dec 2025 21:47:21 +0600 Subject: [PATCH 3/5] feat: Redesign the FeaturesSection with a custom animated layout, add new features, and refine existing descriptions. --- .../components/landing/FeaturesSection.tsx | 124 ++++++++++++------ 1 file changed, 83 insertions(+), 41 deletions(-) diff --git a/web/src/components/landing/FeaturesSection.tsx b/web/src/components/landing/FeaturesSection.tsx index 518a51d..3364c42 100644 --- a/web/src/components/landing/FeaturesSection.tsx +++ b/web/src/components/landing/FeaturesSection.tsx @@ -1,9 +1,3 @@ -import { - Card, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; import { History, GitBranch, @@ -12,96 +6,144 @@ import { FileText, Users, Layers, + Search, + Download, } from "lucide-react"; import { motion } from "framer-motion"; export function FeaturesSection() { const features = [ { - icon: Layers, - title: "Multiple Notes Per Line", + icon: Zap, + title: "Intelligent Tracking", description: - "Add unlimited annotations to the same code location with smart navigation between notes", + "Notes follow your code even when line numbers change using content hash tracking.", }, { - icon: Zap, - title: "Intelligent Tracking", + icon: Layers, + title: "Multiple Notes Per Line", description: - "Notes follow your code even when line numbers change using content hash tracking", + "Add unlimited annotations to the same code location with smart navigation.", }, { icon: History, title: "Complete History", description: - "Full audit trail of all note modifications with timestamps and authors", + "Full audit trail of all note modifications with timestamps and authors.", }, { - icon: Code, - title: "Native Integration", + icon: GitBranch, + title: "Git Integration", description: - "Uses VS Code's native comment UI with CodeLens indicators and markdown support", + "Automatic author detection and seamless version control integration.", }, { - icon: GitBranch, - title: "Git Integration", + icon: Code, + title: "Native Integration", description: - "Automatic author detection and seamless version control integration", + "Uses VS Code's native comment UI with CodeLens indicators.", }, { icon: FileText, title: "Human-Readable Storage", description: - "Notes stored as markdown files that are easy to read, search, and version control", + "Notes stored as markdown files that are easy to read and search.", }, { icon: Users, title: "Team Collaboration", description: - "Share notes with your team by committing them to your repository", + "Share notes with your team by committing them to your repository.", + }, + { + icon: Search, + title: "Context-Aware Search", + description: + "Instantly find any note across your entire codebase with powerful search and filtering capabilities.", + }, + { + icon: Download, + title: "Export Options", + description: + "Export your notes to Markdown, PDF, or HTML for easy sharing and documentation generation.", }, ]; return ( -
- {/* Background Pattern */} -
+
+ {/* Geometric Background Shapes - Enhanced Visibility */} +
+ {/* Grid Pattern */} +
+ + {/* Large Circle Top Right */} +
+ + {/* Triangle/Polygon Bottom Left */} +
+ + {/* Floating Shapes - More Opaque */} + + + +
-
+
-

- Why Choose Code Context Notes? +

+ Everything You Need to
+ Master Your Codebase

-

- Built for developers who need reliable, intelligent code annotation - that scales with their projects. +

+ Powerful features designed to help you understand, document, and maintain complex projects.

-
+ {/* Bento Grid Layout */} +
{features.map((feature, index) => ( - - -
- -
- {feature.title} - {feature.description} -
-
+
+ +
+
+ +
+ +

+ {feature.title} +

+ +

+ {feature.description} +

+
))}
From 26b21ed9f4187df42060229e8bcdf846f0d2eb5f Mon Sep 17 00:00:00 2001 From: Julkar Naen Nahian Date: Tue, 2 Dec 2025 22:34:18 +0600 Subject: [PATCH 4/5] feat: Redesign QuickStartSection with updated content, custom mockups, new icons, and a new brand color. --- .../components/landing/QuickStartSection.tsx | 290 ++++++++++-------- web/tailwind.config.js | 183 +++++------ 2 files changed, 256 insertions(+), 217 deletions(-) diff --git a/web/src/components/landing/QuickStartSection.tsx b/web/src/components/landing/QuickStartSection.tsx index 7b80ff1..2e84677 100644 --- a/web/src/components/landing/QuickStartSection.tsx +++ b/web/src/components/landing/QuickStartSection.tsx @@ -1,92 +1,113 @@ -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { CheckCircle } from "lucide-react"; import { motion } from "framer-motion"; +import { ArrowRight, Check, Command, FileText, MousePointer2 } from "lucide-react"; export function QuickStartSection() { const steps = [ { - number: 1, - title: "Select Your Code", - description: - "Highlight the lines of code you want to annotate. Works with any programming language and file type.", + number: "01", + title: "Select Code", + description: "Highlight any snippet in your editor. We support all languages and file types out of the box.", + icon: , content: ( -
-
-
- - function calculateTotal() {"{"} - +
+ {/* Mock IDE Header */} +
+
+
+
+
+
+
utils.ts
-
-
- - {" "} - return items.reduce... - + {/* Mock Code */} +
+
+ 1 + export{" "} + function{" "} + calc() {"{"} +
+
+
+ 2 + return{" "} + items. + map +
+
+ 3 + i ={">"} i * 2 +
+
+ 4 + {"}"} +
), }, { - number: 2, - title: "Press the Shortcut", - description: - "Use the keyboard shortcut to instantly open the note editor right where you need it.", + number: "02", + title: "Trigger Shortcut", + description: "Hit the magic key combo. The note editor appears instantly, right where your focus is.", + icon: , content: ( -
-
- - Ctrl - - + - - Alt - - + - - N - +
+
+
+
+
+ Ctrl +
+
+ + +
+
+
+ Alt +
+
+ + +
+
+
+ N +
+
-

- (Cmd+Alt+N on Mac) +

+ Cmd + Alt + N on macOS

), }, { - number: 3, - title: "Write & Save", - description: - "Type your note with full markdown support, then save. Your note is now tracked with complete history.", + number: "03", + title: "Annotate & Save", + description: "Write your thoughts in Markdown. Your context is saved automatically with the code.", + icon: , content: ( -
-
-
-
- - **TODO:** Optimize this function - +
+
+
+
+
+
+ + New Note + +
+ Just now
-
-
- - Consider using `Map` for O(1) lookup - +
+
+
+
-
- +
+
+ Save Note +
@@ -95,84 +116,97 @@ export function QuickStartSection() { ]; return ( -
- {/* Background Pattern */} -
+
+ {/* Background Elements */} +
+
-
-
+
+ {/* Section Header */} +
-

- Get Started in Seconds +

+ From Code to Context in
+ + Three Simple Steps +

-

- Three simple steps to start annotating your code with intelligent - tracking and full history +

+ Stop context switching. Capture your thoughts exactly where they belong—right next to your code.

-
- {/* Connection Lines for Desktop */} -
-
-
-
-
-
+ {/* Steps Grid */} +
+ {/* Connecting Line (Desktop) */} +
+ + {steps.map((step, index) => ( + +
+ {/* Card Background with Glass Effect */} +
-
- {steps.map((step, index) => ( - - - -
-
- {step.number} +
+ {/* Step Number & Icon */} +
+
+
+
+ {step.icon}
-
- {step.title} - - {step.description} - - - {step.content} - - - ))} -
+ + {step.number} + +
- {/* Bottom CTA */} - -
- - - That's it! Your code is now annotated with intelligent tracking. - -
-
+ {/* Content Preview */} +
+ {step.content} +
+ + {/* Text Content */} +
+

+ {step.title} +

+

+ {step.description} +

+
+
+
+ + ))}
+ + {/* Bottom CTA */} + +
+ + Ready to start? No credit card required. +
+
); diff --git a/web/tailwind.config.js b/web/tailwind.config.js index dc1ad0e..67d0a86 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -1,92 +1,97 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: ["class"], - content: [ - './pages/**/*.{ts,tsx}', - './components/**/*.{ts,tsx}', - './app/**/*.{ts,tsx}', - './src/**/*.{ts,tsx}', - ], - prefix: "", - theme: { - container: { - center: true, - padding: '2rem', - screens: { - '2xl': '1400px' - } - }, - extend: { - colors: { - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' - }, - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - }, - chart: { - '1': 'hsl(var(--chart-1))', - '2': 'hsl(var(--chart-2))', - '3': 'hsl(var(--chart-3))', - '4': 'hsl(var(--chart-4))', - '5': 'hsl(var(--chart-5))' - } - }, - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' - }, - keyframes: { - 'accordion-down': { - from: { - height: '0' - }, - to: { - height: 'var(--radix-accordion-content-height)' - } - }, - 'accordion-up': { - from: { - height: 'var(--radix-accordion-content-height)' - }, - to: { - height: '0' - } - } - }, - animation: { - 'accordion-down': 'accordion-down 0.2s ease-out', - 'accordion-up': 'accordion-up 0.2s ease-out' - } - } - }, - plugins: [require("tailwindcss-animate")], + darkMode: ["class"], + content: [ + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', + ], + prefix: "", + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px' + } + }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + brand: { + orange: '#FF8A3D', + navy: '#0B1220', + warm: '#F4F1E9', + }, + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + keyframes: { + 'accordion-down': { + from: { + height: '0' + }, + to: { + height: 'var(--radix-accordion-content-height)' + } + }, + 'accordion-up': { + from: { + height: 'var(--radix-accordion-content-height)' + }, + to: { + height: '0' + } + } + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out' + } + } + }, + plugins: [require("tailwindcss-animate")], } \ No newline at end of file From bb587a53fba79c8a31259f67d34f88ba1e592541 Mon Sep 17 00:00:00 2001 From: Julkar Naen Nahian Date: Tue, 2 Dec 2025 22:41:30 +0600 Subject: [PATCH 5/5] feat: Add anchor links to landing page sections and update navigation bar for smooth scrolling. --- web/src/components/Navigation.tsx | 66 +++++++++++++------ .../components/landing/FeaturesSection.tsx | 2 +- .../landing/ProblemSolutionSection.tsx | 2 +- .../components/landing/QuickStartSection.tsx | 2 +- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/web/src/components/Navigation.tsx b/web/src/components/Navigation.tsx index ca35238..5d23db7 100644 --- a/web/src/components/Navigation.tsx +++ b/web/src/components/Navigation.tsx @@ -10,36 +10,62 @@ export function Navigation() {
- Code Context Notes Code Context Notes - +
{ + if (location.pathname === '/') { + e.preventDefault(); + document.getElementById('problem')?.scrollIntoView({ behavior: 'smooth' }); + } + }} + className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary" > - Home + Problem + + { + if (location.pathname === '/') { + e.preventDefault(); + document.getElementById('features')?.scrollIntoView({ behavior: 'smooth' }); + } + }} + className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary" + > + Features + + { + if (location.pathname === '/') { + e.preventDefault(); + document.getElementById('how-it-works')?.scrollIntoView({ behavior: 'smooth' }); + } + }} + className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary" + > + How it Works Documentation Changelog @@ -48,9 +74,9 @@ export function Navigation() {
- +