diff --git a/apps/landing/.gitignore b/apps/landing/.gitignore new file mode 100644 index 0000000..06f339f --- /dev/null +++ b/apps/landing/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# devup-ui +/df diff --git a/apps/landing/README.md b/apps/landing/README.md new file mode 100644 index 0000000..95f69cf --- /dev/null +++ b/apps/landing/README.md @@ -0,0 +1,85 @@ +# Devup API Landing Page + +This is the landing page for Devup API, built with **Next.js** and **Devup UI**. + +## Tech Stack + +- **Next.js 15+** - React framework with App Router +- **Devup UI** - Zero-runtime CSS-in-JS styling library +- **TypeScript** - Type safety +- **React 19** - Latest React features + +## Getting Started + +### Install Dependencies + +```bash +npm install +# or +pnpm install +# or +yarn install +``` + +### Run Development Server + +```bash +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) to see the landing page. + +### Build for Production + +```bash +npm run build +``` + +This will generate a static export in the `out/` directory. + +### Preview Production Build + +```bash +npm run start +``` + +## Project Structure + +``` +landing/ +├── public/ # Static assets +├── src/ +│ ├── app/ # Next.js App Router +│ │ ├── layout.tsx +│ │ ├── page.tsx +│ │ ├── Hero.tsx +│ │ ├── Features.tsx +│ │ ├── CodeExamples.tsx +│ │ ├── Packages.tsx +│ │ └── Footer.tsx +│ └── components/ # Reusable components +├── devup.json # Devup UI theme configuration +├── next.config.ts # Next.js configuration +├── tsconfig.json # TypeScript configuration +└── package.json +``` + +## Customization + +### Theme + +Edit `devup.json` to customize colors, typography, spacing, and breakpoints. + +### Content + +- **Hero Section**: `src/app/Hero.tsx` +- **Features**: `src/app/Features.tsx` +- **Code Examples**: `src/app/CodeExamples.tsx` +- **Packages**: `src/app/Packages.tsx` +- **Footer**: `src/app/Footer.tsx` + +## Learn More + +- [Next.js Documentation](https://nextjs.org/docs) +- [Devup UI Documentation](https://github.com/dev-five-git/devup-ui) +- [Devup API Documentation](https://github.com/dev-five-git/devup-api) diff --git a/apps/landing/devup.json b/apps/landing/devup.json new file mode 100644 index 0000000..d2a6e5e --- /dev/null +++ b/apps/landing/devup.json @@ -0,0 +1,140 @@ +{ + "theme": { + "colors": { + "light": { + "primary": "#5A44FF", + "primaryHover": "#4836D9", + "secondary": "#85A5F2", + "accent": "#006BFF", + "text": "#212121", + "textLight": "#7F7F7F", + "textMuted": "#9ca3af", + "title": "#212121", + "bg": "#ffffff", + "bgSecondary": "#F7F7F8", + "bgTertiary": "#f3f4f6", + "border": "#E4E4E4", + "containerBackground": "#FBFBFB", + "success": "#10b981", + "warning": "#f59e0b", + "error": "#ef4444", + "codeBg": "#1E1E1E", + "codeText": "#e5e7eb", + "link": "#006BFF" + }, + "dark": { + "primary": "#9086FF", + "primaryHover": "#7A70E6", + "secondary": "#2A4586", + "accent": "#60a5fa", + "text": "#f3f4f6", + "textLight": "#d1d5db", + "textMuted": "#9ca3af", + "title": "#ffffff", + "bg": "#121212", + "bgSecondary": "#1E1E1E", + "bgTertiary": "#2A2A2A", + "border": "#333333", + "containerBackground": "#1A1A1A", + "success": "#34d399", + "warning": "#fbbf24", + "error": "#f87171", + "codeBg": "#0f172a", + "codeText": "#e2e8f0", + "link": "#60a5fa" + } + }, + "typography": { + "h1": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "32px", + "fontWeight": 800, + "lineHeight": 1.2, + "letterSpacing": "-0.03em" + }, + "h2": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "24px", + "fontWeight": 700, + "lineHeight": 1.3, + "letterSpacing": "-0.03em" + }, + "h3": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "18px", + "fontWeight": 700, + "lineHeight": 1.4, + "letterSpacing": "-0.03em" + }, + "h4": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "20px", + "fontWeight": 700, + "lineHeight": 1.4, + "letterSpacing": "-0.03em" + }, + "h5": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "16px", + "fontWeight": 600, + "lineHeight": 1.4, + "letterSpacing": "-0.03em" + }, + "h6": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "14px", + "fontWeight": 600, + "lineHeight": 1.5, + "letterSpacing": "-0.03em" + }, + "body": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "14px", + "fontWeight": 400, + "lineHeight": 1.6, + "letterSpacing": "-0.03em" + }, + "bodyLarge": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "16px", + "fontWeight": 400, + "lineHeight": 1.6, + "letterSpacing": "-0.03em" + }, + "textL": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "16px", + "fontWeight": 400, + "lineHeight": 1.6, + "letterSpacing": "-0.03em" + }, + "button": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "16px", + "fontWeight": 600, + "lineHeight": 1, + "letterSpacing": "-0.03em" + }, + "buttonM": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "14px", + "fontWeight": 600, + "lineHeight": 1, + "letterSpacing": "-0.03em" + }, + "code": { + "fontFamily": "D2Coding, Monaco, 'Courier New', monospace", + "fontSize": "14px", + "lineHeight": 1.6, + "letterSpacing": "0" + }, + "caption": { + "fontFamily": "Pretendard Variable, -apple-system, BlinkMacSystemFont, system-ui, sans-serif", + "fontSize": "12px", + "fontWeight": 400, + "lineHeight": 1.5, + "letterSpacing": "-0.03em" + } + } + } +} diff --git a/apps/landing/next.config.ts b/apps/landing/next.config.ts new file mode 100644 index 0000000..a027c7c --- /dev/null +++ b/apps/landing/next.config.ts @@ -0,0 +1,10 @@ +import { DevupUI } from '@devup-ui/next-plugin' +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = { + pageExtensions: ['js', 'jsx', 'ts', 'tsx'], + output: 'export', + reactCompiler: true, +} + +export default DevupUI({}, nextConfig) diff --git a/apps/landing/package.json b/apps/landing/package.json new file mode 100644 index 0000000..c5d3b8b --- /dev/null +++ b/apps/landing/package.json @@ -0,0 +1,29 @@ +{ + "name": "devup-api-landing", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@devup-ui/react": "latest", + "@devup-ui/reset-css": "latest", + "clsx": "^2.1.1", + "next": "^16.1.1", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@devup-ui/next-plugin": "latest", + "@types/node": "^25", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "^16.1.1", + "typescript": "^5" + } +} diff --git a/apps/landing/src/app/CodeExamples.tsx b/apps/landing/src/app/CodeExamples.tsx new file mode 100644 index 0000000..6adc2e0 --- /dev/null +++ b/apps/landing/src/app/CodeExamples.tsx @@ -0,0 +1,225 @@ +'use client' + +import { Box, Flex, Grid } from '@devup-ui/react' +import { Container } from '../components/Container' + +const EXAMPLES = [ + { + title: 'Installation & Setup', + icon: '📦', + code: `// Install for your build tool +npm install @devup-api/fetch @devup-api/vite-plugin + +// vite.config.ts +import { defineConfig } from 'vite' +import devupApi from '@devup-api/vite-plugin' + +export default defineConfig({ + plugins: [devupApi()], +})`, + }, + { + title: 'Basic Usage', + icon: '🚀', + code: `import { createApi } from '@devup-api/fetch' + +const api = createApi('https://api.example.com') + +// Use operationId +const users = await api.get('getUsers', {}) + +// Or use the path directly +const user = await api.get('/users/{id}', { + params: { id: '123' }, +})`, + }, + { + title: 'React Query Integration', + icon: '⚛️', + code: `import { createQueryClient } from '@devup-api/react-query' + +const queryClient = createQueryClient(api) + +function UserProfile({ userId }) { + const { data, isLoading } = queryClient.useQuery( + 'get', + '/users/{id}', + { params: { id: userId } } + ) + return
{data?.name}
+}`, + }, + { + title: 'Type References', + icon: '🔷', + code: `import { type DevupObject } from '@devup-api/fetch' + +// Access response types +type User = DevupObject['User'] +type Product = DevupObject['Product'] + +// Request types +type CreateUserRequest = + DevupObject<'request'>['CreateUserBody']`, + }, +] + +function CodeBlock({ + title, + icon, + code, +}: { + title: string + icon: string + code: string +}) { + return ( + + + + {icon} + + {title} + + + + + + + + + + {code} + + + ) +} + +export default function CodeExamples() { + return ( + + {/* Background decoration */} + + + + + {/* Section Header */} + + + Examples + + + Get started in minutes + + + Simple, intuitive APIs that feel natural to use + + + + {/* Code Examples Grid */} + + {EXAMPLES.map((example) => ( + + ))} + + + + + ) +} diff --git a/apps/landing/src/app/Features.tsx b/apps/landing/src/app/Features.tsx new file mode 100644 index 0000000..3f61412 --- /dev/null +++ b/apps/landing/src/app/Features.tsx @@ -0,0 +1,174 @@ +'use client' + +import { Box, Flex, Grid } from '@devup-ui/react' +import { Container } from '../components/Container' + +const FEATURES = [ + { + icon: '🔍', + title: 'OpenAPI-driven Types', + desc: 'Reads openapi.json and transforms every path, method, schema into typed API functions. Parameters, request bodies, headers, responses — all typed automatically.', + gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + }, + { + icon: '🪝', + title: 'Fetch-compatible Design', + desc: 'Feels like using fetch, but with superpowers. Path params automatically replaced, query/body/header types enforced, typed success & error responses.', + gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', + }, + { + icon: '⚡', + title: 'Build Tool Integration', + desc: 'Works seamlessly with Vite, Next.js, Webpack, and Rsbuild. Automatic type generation during build time with zero runtime overhead.', + gradient: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', + }, + { + icon: '🔄', + title: 'React Query Support', + desc: 'First-class integration with TanStack React Query. Use useQuery, useMutation, useInfiniteQuery with full type safety.', + gradient: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)', + }, + { + icon: '🌐', + title: 'Multiple API Servers', + desc: 'Support for multiple OpenAPI schemas. Work with different API servers simultaneously with isolated type generation.', + gradient: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)', + }, + { + icon: '🛡️', + title: 'Complete Type Safety', + desc: 'Cold typing for initial development, bold typing for production. Gradual type enforcement ensures smooth developer experience.', + gradient: 'linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%)', + }, +] + +function FeatureCard({ icon, title, desc, gradient }: (typeof FEATURES)[0]) { + return ( + + {/* Icon with gradient background */} + + {icon} + + + + + {title} + + + {desc} + + + + ) +} + +export default function Features() { + return ( + + + + {/* Section Header */} + + + Features + + + Everything you need for + + type-safe API calls + + + Devup API offers powerful features for building type-safe API + clients with zero configuration. + + + + {/* Features Grid */} + + {FEATURES.map((feature) => ( + + ))} + + + + + ) +} diff --git a/apps/landing/src/app/Packages.tsx b/apps/landing/src/app/Packages.tsx new file mode 100644 index 0000000..93cfd32 --- /dev/null +++ b/apps/landing/src/app/Packages.tsx @@ -0,0 +1,250 @@ +'use client' + +import { Box, Flex, Grid } from '@devup-ui/react' +import Link from 'next/link' +import { Container } from '../components/Container' + +const PACKAGES = [ + { + name: '@devup-api/fetch', + description: 'Type-safe API client with full TypeScript support', + npm: 'https://www.npmjs.com/package/@devup-api/fetch', + icon: '🚀', + featured: true, + }, + { + name: '@devup-api/react-query', + description: 'TanStack React Query integration with type inference', + npm: 'https://www.npmjs.com/package/@devup-api/react-query', + icon: '⚛️', + featured: true, + }, + { + name: '@devup-api/core', + description: 'Core types and interfaces', + npm: 'https://www.npmjs.com/package/@devup-api/core', + icon: '📦', + featured: false, + }, + { + name: '@devup-api/generator', + description: 'TypeScript interface generator from OpenAPI schemas', + npm: 'https://www.npmjs.com/package/@devup-api/generator', + icon: '⚙️', + featured: false, + }, + { + name: '@devup-api/vite-plugin', + description: 'Vite plugin for automatic type generation', + npm: 'https://www.npmjs.com/package/@devup-api/vite-plugin', + icon: '⚡', + featured: false, + }, + { + name: '@devup-api/next-plugin', + description: 'Next.js plugin for automatic type generation', + npm: 'https://www.npmjs.com/package/@devup-api/next-plugin', + icon: '▲', + featured: false, + }, + { + name: '@devup-api/webpack-plugin', + description: 'Webpack plugin for automatic type generation', + npm: 'https://www.npmjs.com/package/@devup-api/webpack-plugin', + icon: '📦', + featured: false, + }, + { + name: '@devup-api/rsbuild-plugin', + description: 'Rsbuild plugin for automatic type generation', + npm: 'https://www.npmjs.com/package/@devup-api/rsbuild-plugin', + icon: '🔧', + featured: false, + }, + { + name: '@devup-api/utils', + description: 'Utility functions for OpenAPI processing', + npm: 'https://www.npmjs.com/package/@devup-api/utils', + icon: '🛠️', + featured: false, + }, +] + +function PackageCard({ + name, + description, + npm, + icon, + featured, +}: (typeof PACKAGES)[0]) { + return ( + + + {featured && ( + + Popular + + )} + + + + {icon} + + + {name} + + + + + {description} + + + + View on npm + + + + + ) +} + +export default function Packages() { + return ( + + + + {/* Section Header */} + + + Packages + + + Modular & flexible + + + Pick only what you need for your project + + + + {/* Packages Grid */} + + {PACKAGES.map((pkg) => ( + + ))} + + + + + ) +} diff --git a/apps/landing/src/app/TopBanner.tsx b/apps/landing/src/app/TopBanner.tsx new file mode 100644 index 0000000..2d4cc93 --- /dev/null +++ b/apps/landing/src/app/TopBanner.tsx @@ -0,0 +1,249 @@ +'use client' + +import { Box, Flex } from '@devup-ui/react' +import Link from 'next/link' +import { Container } from '../components/Container' + +function GetStartedButton() { + return ( + + + Get Started + + → + + + + ) +} + +function GithubButton() { + return ( + + + + + + GitHub + + + ) +} + +function Badge({ + children, + icon, +}: { + children: React.ReactNode + icon: string +}) { + return ( + + {icon} + {children} + + ) +} + +export default function TopBanner() { + return ( + + {/* Background decorations */} + + + + + + {/* Badges */} + + OpenAPI-driven + Fetch-compatible + Zero Generics + + + {/* Title */} + + Type-safe API Client + + Powered by{' '} + + OpenAPI + + + + {/* Description */} + + A fully typed API client generator. Auto-generated types from your + OpenAPI spec, + + zero generics required — just write API calls, the types are already + there. + + + {/* CTA Buttons */} + + + + + + {/* Install command */} + + + $ + + + npm + {' '} + + install + {' '} + + @devup-api/fetch @devup-api/vite-plugin + + + + + + ) +} diff --git a/apps/landing/src/app/layout.tsx b/apps/landing/src/app/layout.tsx new file mode 100644 index 0000000..e782162 --- /dev/null +++ b/apps/landing/src/app/layout.tsx @@ -0,0 +1,67 @@ +import type { Metadata } from 'next' +import '@devup-ui/reset-css' +import { Footer } from '../components/Footer' +import { Header } from '../components/Header' + +export const metadata: Metadata = { + title: 'Devup API - Type-safe API Client Powered by OpenAPI', + description: + 'A fully typed API client generator powered by OpenAPI. Fetch-compatible, auto-generated types, zero generics required.', + keywords: [ + 'API', + 'OpenAPI', + 'TypeScript', + 'Type-safe', + 'Fetch', + 'React', + 'Next.js', + 'React Query', + ], + authors: [{ name: 'DevFive' }], + openGraph: { + title: 'Devup API - Type-safe API Client Powered by OpenAPI', + description: + 'A fully typed API client generator powered by OpenAPI. Fetch-compatible, auto-generated types, zero generics required.', + type: 'website', + }, + alternates: { + canonical: '/', + }, +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + + + + +
+
{children}
+