├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .eslintrc.json ├── src ├── app │ ├── favicon.ico │ ├── api │ │ └── og │ │ │ ├── proxy │ │ │ └── route.ts │ │ │ └── fetch │ │ │ └── route.ts │ └── (main) │ │ ├── page.tsx │ │ └── layout.tsx ├── resources │ ├── icons.ts │ ├── custom.css │ └── once-ui.config.js └── components │ └── Providers.tsx ├── public ├── images │ └── og │ │ └── home.jpg └── trademarks │ ├── icon-dark.svg │ ├── icon-light.svg │ ├── wordmark-dark.svg │ └── wordmark-light.svg ├── next.config.mjs ├── .env.example ├── .gitignore ├── biome.json ├── package.json ├── tsconfig.json ├── LICENSE └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [once-ui-system, lorant-one] 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/once-ui-system/nextjs-starter/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/images/og/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/once-ui-system/nextjs-starter/HEAD/public/images/og/home.jpg -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | sassOptions: { 4 | compiler: "modern", 5 | silenceDeprecations: ["legacy-js-api"], 6 | }, 7 | }; 8 | 9 | export default nextConfig; 10 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # This file is a placeholder for environment variables required to run this project. 2 | # Currently, there are no environment variables needed. 3 | 4 | # Example of what future variables might look like: 5 | # NEXT_PUBLIC_API_KEY=your_api_key_here 6 | # DATABASE_URL=your_database_url_here 7 | # SECRET_KEY=your_secret_key_here -------------------------------------------------------------------------------- /src/resources/icons.ts: -------------------------------------------------------------------------------- 1 | import { IconType } from "react-icons"; 2 | 3 | import { 4 | HiOutlineRocketLaunch, 5 | } from "react-icons/hi2"; 6 | 7 | 8 | export const iconLibrary: Record = { 9 | rocket: HiOutlineRocketLaunch, 10 | }; 11 | 12 | export type IconLibrary = typeof iconLibrary; 13 | export type IconName = keyof IconLibrary; -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Submit a feature request for Once UI 4 | --- 5 | 6 | ### Thank you for taking the time to submit a feature request. We appreciate your contribution. 7 | 8 | **Describe the feature** 9 | 10 | [Tell us about the problem you're trying to solve and the requested feature.] 11 | 12 | 13 | **Affected components** 14 | 15 | [Is the feature request related to an existing component?] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "indentStyle": "space", 15 | "indentWidth": 2, 16 | "lineWidth": 100 17 | }, 18 | "organizeImports": { 19 | "enabled": true 20 | }, 21 | "linter": { 22 | "enabled": true, 23 | "rules": { "recommended": true } 24 | }, 25 | "javascript": { 26 | "formatter": { 27 | "quoteStyle": "double" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug in Once UI 4 | --- 5 | 6 | ### Thank you for taking the time to fill out this bug report. 7 | 8 | **Tell us what happened** 9 | 10 | [A clear and concise description of the bug you've encountered.] 11 | 12 | 13 | **Affected components** 14 | 15 | [Is the feature request related to an existing component?] 16 | 17 | 18 | **How do we reproduce it?** 19 | 20 | [Please share a step-by-step description of how to reproduce the issue.] 21 | 22 | 23 | **Screenshots** 24 | 25 | [If applicable, add screenshots to help explain your problem.] 26 | 27 | 28 | **System information and logs** 29 | 30 | [Add any information that might be relevant.] -------------------------------------------------------------------------------- /public/trademarks/icon-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/trademarks/icon-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@once-ui-system/nextjs-starter", 3 | "version": "1.1.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "export": "next export", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint", 11 | "biome-write": "npx @biomejs/biome format --write ." 12 | }, 13 | "dependencies": { 14 | "@once-ui-system/core": "latest", 15 | "classnames": "^2.5.1", 16 | "next": "16.0.7", 17 | "react": "19.0.0", 18 | "react-dom": "19.0.0", 19 | "react-icons": "^5.2.1", 20 | "sass": "^1.77.6", 21 | "sharp": "^0.33.4" 22 | }, 23 | "devDependencies": { 24 | "@biomejs/biome": "1.9.4", 25 | "@types/node": "20.17.23", 26 | "@types/react": "19.0.1", 27 | "@types/react-dom": "19.0.2", 28 | "typescript": "5.8.2" 29 | }, 30 | "overrides": { 31 | "@types/react": "19.0.1", 32 | "@types/react-dom": "19.0.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "typeRoots": [ 4 | "./types", 5 | "./node_modules/@types" 6 | ], 7 | "lib": [ 8 | "dom", 9 | "dom.iterable", 10 | "esnext" 11 | ], 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "strict": true, 15 | "noEmit": true, 16 | "esModuleInterop": true, 17 | "module": "esnext", 18 | "moduleResolution": "bundler", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "jsx": "react-jsx", 22 | "incremental": true, 23 | "plugins": [ 24 | { 25 | "name": "next" 26 | } 27 | ], 28 | "paths": { 29 | "@/*": [ 30 | "./src/*" 31 | ] 32 | }, 33 | "target": "ES2017" 34 | }, 35 | "include": [ 36 | "next-env.d.ts", 37 | "**/*.ts", 38 | "**/*.tsx", 39 | ".next/types/**/*.ts", 40 | ".next/dev/types/**/*.ts" 41 | ], 42 | "exclude": [ 43 | "node_modules" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-2025 Once UI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/app/api/og/proxy/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | 3 | export async function GET(request: NextRequest) { 4 | try { 5 | // Get the URL parameter 6 | const url = new URL(request.url); 7 | const imageUrl = url.searchParams.get("url"); 8 | 9 | if (!imageUrl) { 10 | return NextResponse.json({ error: "Missing URL parameter" }, { status: 400 }); 11 | } 12 | 13 | // Fetch the image 14 | const response = await fetch(imageUrl, { 15 | headers: { 16 | "User-Agent": "Mozilla/5.0 (compatible; ImageProxy/1.0)", 17 | }, 18 | }); 19 | 20 | if (!response.ok) { 21 | return NextResponse.json( 22 | { error: `Failed to fetch image: ${response.status}` }, 23 | { status: response.status }, 24 | ); 25 | } 26 | 27 | // Get the image data 28 | const contentType = response.headers.get("content-type") || "image/jpeg"; 29 | const imageData = await response.arrayBuffer(); 30 | 31 | // Return the image with appropriate headers 32 | return new NextResponse(imageData, { 33 | headers: { 34 | "Content-Type": contentType, 35 | "Cache-Control": "public, max-age=86400", 36 | }, 37 | }); 38 | } catch (error) { 39 | console.error("Error proxying image:", error); 40 | return NextResponse.json({ error: "Failed to proxy image" }, { status: 500 }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/Providers.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { BorderStyle, ChartMode, ChartVariant, DataThemeProvider, IconProvider, LayoutProvider, NeutralColor, ScalingSize, Schemes, SolidStyle, SolidType, SurfaceStyle, Theme, ThemeProvider, ToastProvider, TransitionStyle } from "@once-ui-system/core"; 4 | import { style, dataStyle } from "../resources/once-ui.config"; 5 | import { iconLibrary } from "../resources/icons"; 6 | 7 | export function Providers({ children }: { children: React.ReactNode }) { 8 | return ( 9 | 10 | 22 | 35 | 36 | 37 | {children} 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | } -------------------------------------------------------------------------------- /src/app/(main)/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { 4 | Heading, 5 | Text, 6 | Button, 7 | Column, 8 | Badge, 9 | Logo, 10 | Line, 11 | LetterFx, 12 | } from "@once-ui-system/core"; 13 | 14 | export default function Home() { 15 | return ( 16 | 17 | 18 | 25 | 26 | 27 | 28 | 29 | An ecosystem, not a UI kit 30 | 31 | 32 | 33 | Presence that doesn't beg for attention 34 | 35 | 41 | Build with clarity, speed, and quiet confidence 42 | 43 | 53 | 54 | 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /src/resources/custom.css: -------------------------------------------------------------------------------- 1 | /* :root { 2 | /* 3 | /* Example setup for custom colors */ 4 | /* Generate at: https://once-ui.com/customize */ 5 | /* 6 | --scheme-brand-100: #08002f; 7 | --scheme-brand-200: #04025c; 8 | --scheme-brand-300: #1f398e; 9 | --scheme-brand-400: #3856ae; 10 | --scheme-brand-500: #5071cc; 11 | --scheme-brand-600: #6f94f1; 12 | --scheme-brand-700: #8db3ff; 13 | --scheme-brand-800: #b2dbff; 14 | --scheme-brand-900: #bfe8ff; 15 | --scheme-brand-1000: #ccf6ff; 16 | --scheme-brand-1100: #d2fcff; 17 | --scheme-brand-1200: #d2fcff; 18 | --scheme-brand-600-10: rgba(111,148,241,0.1); 19 | --scheme-brand-600-30: rgba(111,148,241,0.3); 20 | --scheme-brand-600-50: rgba(111,148,241,0.5); 21 | 22 | --scheme-accent-100: #030b10; 23 | --scheme-accent-200: #0d181d; 24 | --scheme-accent-300: #364248; 25 | --scheme-accent-400: #505d64; 26 | --scheme-accent-500: #69777e; 27 | --scheme-accent-600: #8a989f; 28 | --scheme-accent-700: #a8b7bf; 29 | --scheme-accent-800: #c8d7df; 30 | --scheme-accent-900: #d5e4ec; 31 | --scheme-accent-1000: #e2f1f9; 32 | --scheme-accent-1100: #e9f8ff; 33 | --scheme-accent-1200: #efffff; 34 | --scheme-accent-600-10: rgba(138,152,159,0.1); 35 | --scheme-accent-600-30: rgba(138,152,159,0.3); 36 | --scheme-accent-600-50: rgba(138,152,159,0.5); 37 | 38 | --scheme-neutral-100: #020b10; 39 | --scheme-neutral-200: #0b181d; 40 | --scheme-neutral-300: #344248; 41 | --scheme-neutral-400: #4f5d64; 42 | --scheme-neutral-500: #68777e; 43 | --scheme-neutral-600: #89989f; 44 | --scheme-neutral-700: #a7b7be; 45 | --scheme-neutral-800: #c7d7df; 46 | --scheme-neutral-900: #d4e4ec; 47 | --scheme-neutral-1000: #e1f2f9; 48 | --scheme-neutral-1100: #e7f8ff; 49 | --scheme-neutral-1200: #eeffff; 50 | --scheme-neutral-600-10: rgba(137,152,159,0.1); 51 | --scheme-neutral-600-30: rgba(137,152,159,0.3); 52 | --scheme-neutral-600-50: rgba(137,152,159,0.5); 53 | /* 54 | }*/ -------------------------------------------------------------------------------- /src/app/api/og/fetch/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export const runtime = "edge"; 4 | 5 | function decodeHTMLEntities(text: string): string { 6 | return text.replace(/&(#?[a-zA-Z0-9]+);/g, (match, entity) => { 7 | const entities: { [key: string]: string } = { 8 | amp: "&", 9 | lt: "<", 10 | gt: ">", 11 | quot: '"', 12 | apos: "'", 13 | "#x27": "'", 14 | "#39": "'", 15 | "#x26": "&", 16 | "#38": "&", 17 | }; 18 | 19 | if (entity.startsWith("#")) { 20 | const code = entity.startsWith("#x") 21 | ? parseInt(entity.slice(2), 16) 22 | : parseInt(entity.slice(1), 10); 23 | return String.fromCharCode(code); 24 | } 25 | 26 | return entities[entity] || match; 27 | }); 28 | } 29 | 30 | async function fetchWithTimeout(url: string, timeout = 5000) { 31 | const controller = new AbortController(); 32 | const timeoutId = setTimeout(() => controller.abort(), timeout); 33 | 34 | try { 35 | const response = await fetch(url, { 36 | signal: controller.signal, 37 | headers: { 38 | "User-Agent": "bot", 39 | }, 40 | }); 41 | clearTimeout(timeoutId); 42 | return response; 43 | } catch (error) { 44 | clearTimeout(timeoutId); 45 | throw error; 46 | } 47 | } 48 | 49 | async function extractMetadata(html: string) { 50 | const titleMatch = html.match(/]*>([^<]+)<\/title>/i); 51 | const descMatch = 52 | html.match(/]*name="description"[^>]*content="([^"]+)"[^>]*>/i) || 53 | html.match(/]*content="([^"]+)"[^>]*name="description"[^>]*>/i) || 54 | html.match(/]*property="og:description"[^>]*content="([^"]+)"[^>]*>/i); 55 | const imageMatch = 56 | html.match(/]*property="og:image"[^>]*content="([^"]+)"[^>]*>/i) || 57 | html.match(/]*content="([^"]+)"[^>]*property="og:image"[^>]*>/i); 58 | 59 | const title = titleMatch?.[1]?.trim() || ""; 60 | const description = descMatch?.[1]?.trim() || ""; 61 | const image = imageMatch?.[1]?.trim() || ""; 62 | 63 | return { 64 | title: decodeHTMLEntities(title), 65 | description: decodeHTMLEntities(description), 66 | image: image, 67 | }; 68 | } 69 | 70 | export async function GET(request: Request) { 71 | const { searchParams } = new URL(request.url); 72 | const url = searchParams.get("url"); 73 | 74 | if (!url) { 75 | return NextResponse.json({ error: "URL is required" }, { status: 400 }); 76 | } 77 | 78 | try { 79 | const response = await fetchWithTimeout(url); 80 | 81 | if (!response.ok) { 82 | throw new Error(`Failed to fetch URL: ${response.status}`); 83 | } 84 | 85 | const html = await response.text(); 86 | const metadata = await extractMetadata(html); 87 | 88 | return NextResponse.json({ 89 | ...metadata, 90 | url, 91 | }); 92 | } catch (error) { 93 | console.error( 94 | "Error fetching metadata:", 95 | error instanceof Error ? error.message : String(error), 96 | ); 97 | 98 | return NextResponse.json( 99 | { 100 | error: "Failed to fetch metadata", 101 | message: error instanceof Error ? error.message : "Unknown error occurred", 102 | }, 103 | { status: 500 }, 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/resources/once-ui.config.js: -------------------------------------------------------------------------------- 1 | // IMPORTANT: Replace with your own domain address - it's used for SEO in meta tags and schema 2 | const baseURL = "https://demo.once-ui.com"; 3 | 4 | // Import and set font for each variant 5 | import { Geist } from "next/font/google"; 6 | import { Geist_Mono } from "next/font/google"; 7 | 8 | const heading = Geist({ 9 | variable: "--font-heading", 10 | subsets: ["latin"], 11 | display: "swap", 12 | }); 13 | 14 | const body = Geist({ 15 | variable: "--font-body", 16 | subsets: ["latin"], 17 | display: "swap", 18 | }); 19 | 20 | const label = Geist({ 21 | variable: "--font-label", 22 | subsets: ["latin"], 23 | display: "swap", 24 | }); 25 | 26 | const code = Geist_Mono({ 27 | variable: "--font-code", 28 | subsets: ["latin"], 29 | display: "swap", 30 | }); 31 | 32 | const fonts = { 33 | heading: heading, 34 | body: body, 35 | label: label, 36 | code: code, 37 | }; 38 | 39 | // default customization applied to the HTML in the main layout.tsx 40 | const style = { 41 | theme: "system", // dark | light | system 42 | neutral: "gray", // sand | gray | slate 43 | brand: "blue", // blue | indigo | violet | magenta | pink | red | orange | yellow | moss | green | emerald | aqua | cyan 44 | accent: "indigo", // blue | indigo | violet | magenta | pink | red | orange | yellow | moss | green | emerald | aqua | cyan 45 | solid: "contrast", // color | contrast | inverse 46 | solidStyle: "flat", // flat | plastic 47 | border: "playful", // rounded | playful | conservative 48 | surface: "filled", // filled | translucent 49 | transition: "all", // all | micro | macro 50 | scaling: "100", // 90 | 95 | 100 | 105 | 110 51 | }; 52 | 53 | const dataStyle = { 54 | variant: "gradient", // flat | gradient | outline 55 | mode: "categorical", // categorical | divergent | sequential 56 | height: 24, // default chart height 57 | axis: { 58 | stroke: "var(--neutral-alpha-weak)", 59 | }, 60 | tick: { 61 | fill: "var(--neutral-on-background-weak)", 62 | fontSize: 11, 63 | line: false 64 | }, 65 | }; 66 | 67 | const effects = { 68 | mask: { 69 | cursor: false, 70 | x: 50, 71 | y: 0, 72 | radius: 100, 73 | }, 74 | gradient: { 75 | display: false, 76 | x: 50, 77 | y: 0, 78 | width: 100, 79 | height: 100, 80 | tilt: 0, 81 | colorStart: "brand-background-strong", 82 | colorEnd: "static-transparent", 83 | opacity: 50, 84 | }, 85 | dots: { 86 | display: true, 87 | size: "2", 88 | color: "brand-on-background-weak", 89 | opacity: 40, 90 | }, 91 | lines: { 92 | display: false, 93 | color: "neutral-alpha-weak", 94 | opacity: 100, 95 | thickness: 1, 96 | angle: 45, 97 | size: "8", 98 | }, 99 | grid: { 100 | display: false, 101 | color: "neutral-alpha-weak", 102 | opacity: 100, 103 | width: "2", 104 | height: "2", 105 | }, 106 | }; 107 | 108 | // metadata for pages 109 | const meta = { 110 | home: { 111 | path: "/", 112 | title: "Once UI for Next.js", 113 | description: 114 | "An open-source design system and component library for Next.js that emphasizes easy styling and accessibility in UI development.", 115 | image: "/images/og/home.jpg", 116 | canonical: "https://once-ui.com", 117 | robots: "index,follow", 118 | alternates: [{ href: "https://once-ui.com", hrefLang: "en" }], 119 | }, 120 | // add more routes and reference them in page.tsx 121 | }; 122 | 123 | // default schema data 124 | const schema = { 125 | logo: "", 126 | type: "Organization", 127 | name: "Once UI", 128 | description: meta.home.description, 129 | email: "lorant@once-ui.com", 130 | }; 131 | 132 | // social links 133 | const social = { 134 | twitter: "https://www.twitter.com/_onceui", 135 | linkedin: "https://www.linkedin.com/company/once-ui/", 136 | discord: "https://discord.com/invite/5EyAQ4eNdS", 137 | }; 138 | 139 | export { baseURL, fonts, style, meta, schema, social, effects, dataStyle }; 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Once UI for Next.js 2 | 3 | A design system for indie builders, startups and freelancers. Once UI combines the simplicity of low-code with the power of code: write 70% less code compared to shadcn + Tailwind. Includes 100+ advanced components. 4 | 5 | Check the demo [here](https://demo.once-ui.com). 6 | 7 | ![Once UI](public/images/og/home.jpg) 8 | 9 | ## Features 10 | 11 | A lightweight starter template with the [Once UI Core](https://github.com/once-ui-system/core) package and our recommended setup to move fast and break limits without neglecting quality. 12 | 13 | * **Customization**: Manage design config in a single file. 14 | * **Components**: Access advanced components with simple APIs. 15 | * **Data-viz**: Add responsive charts with a few lines of code. 16 | * **SEO**: Use our SEO components to simplify meta and schema setup. 17 | * **PRO**: Launch ready-made apps with minimal coding with Once UI Pro. 18 | 19 | [Get Once UI Pro](https://once-ui.com/pricing) 20 | 21 | ## Documentation 22 | 23 | Learn how to build with Once UI at [docs.once-ui.com](https://docs.once-ui.com/once-ui/quick-start). 24 | 25 | ## Quick start 26 | 27 | [Magic Portfolio](https://once-ui.com/products/magic-portfolio) (FREE): Portfolio starter used and loved by thousands of creatives. Simple, customizable, responsive. 28 | 29 | [Magic Docs](https://once-ui.com/products/magic-docs) (FREE): Documentation generator. Just add your MDX files and let Magic Docs handle the rest. 30 | 31 | [Magic Bio](https://once-ui.com/products/magic-bio) (FREE): Link-in-bio template that automatically fetches open-graph data. Just add your links and deploy. 32 | 33 | [Magic Convert](https://once-ui.com/products/magic-convert) (PRO): Conversion-optimized landing page and dashboard template. 34 | 35 | [Magic Agent](https://once-ui.com/products/magic-agent) (PRO): Deployment-ready AI agent built with the Vercel AI SDK. 36 | 37 | [Magic Store](https://once-ui.com/products/magic-store) (PRO): Ecommerce storefront that lets you sell digital and physical products. 38 | 39 | [Once UI Blocks](https://once-ui.com/blocks) (PRO): Copy-paste pre-designed blocks and deploy fully-functional sites with lightning speed. 40 | 41 | ## Design 42 | 43 | The design counterpart of the Once UI system is available [here](https://once-ui.com/figma). 44 | 45 | ## Get started 46 | 47 | Clone the starter template from GitHub: 48 | ```bash 49 | git clone https://github.com/once-ui-system/nextjs-starter.git 50 | ``` 51 | 52 | ## Creators 53 | 54 | Connect with us! 55 | 56 | **Lorant One**: [Site](https://lorant.one) / [Threads](https://www.threads.net/@lorant.one) / [LinkedIn](https://www.linkedin.com/in/lorant-one/) 57 | 58 | **Zsofia Komaromi**: [Site](https://zsofia.pro) / [Threads](https://www.threads.net/@zsofia_kom) / [LinkedIn](https://www.linkedin.com/in/zsofiakomaromi/) 59 | 60 | ## Become a Oncer 61 | 62 | ![Design Engineers Club](https://docs.once-ui.com/images/docs/vibe-coding-dark.jpg) 63 | 64 | Join the [Design Engineers Club](https://discord.com/invite/5EyAQ4eNdS) on Discord to connect with us and share your projects. 65 | 66 | Found a bug? Report it [here](https://github.com/once-ui-system/nextjs-starter/issues/new?labels=bug&template=bug_report.md). Got a feature request? Submit it [here](https://github.com/once-ui-system/nextjs-starter/issues/new?labels=feature%20request&template=feature_request.md). 67 | 68 | Please use the Once UI Core [GitHub repository](https://github.com/once-ui-system/core) for design system contributions. 69 | 70 | ## Sponsors 71 | 72 | Once UI is an indie project. [Sponsor us](https://github.com/sponsors/once-ui-system) and get featured on our site! 73 | 74 | ## License 75 | 76 | Distributed under the MIT License. See `LICENSE.txt` for more information. 77 | 78 | ## Deploy to Vercel 79 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fonce-ui-system%2Fnextjs-starter&project-name=nextjs-starter&repository-name=nextjs-starter&redirect-url=https%3A%2F%2Fgithub.com%2Fonce-ui-system%2Fnextjs-starter&demo-title=Next.js%20Starter&demo-description=Showcase%20your%20designers%20or%20developer%20portfolio&demo-url=https%3A%2F%2Fdemo.nextjs-starter.com&demo-image=%2F%2Fraw.githubusercontent.com%2Fonce-ui-system%2Fnextjs-starter%2Fmain%2Fpublic%2Fimages%2Fog%2Fhome.jpg) -------------------------------------------------------------------------------- /public/trademarks/wordmark-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/trademarks/wordmark-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/app/(main)/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@once-ui-system/core/css/styles.css'; 2 | import '@once-ui-system/core/css/tokens.css'; 3 | import '@/resources/custom.css' 4 | 5 | import classNames from "classnames"; 6 | 7 | import { baseURL, meta, fonts, effects, style, dataStyle } from "@/resources/once-ui.config"; 8 | import { Meta, Schema, Column, Flex, opacity, SpacingToken, Background} from "@once-ui-system/core"; 9 | import { Providers } from '@/components/Providers'; 10 | 11 | export async function generateMetadata() { 12 | return Meta.generate({ 13 | title: meta.home.title, 14 | description: meta.home.description, 15 | baseURL: baseURL, 16 | path: meta.home.path, 17 | canonical: meta.home.canonical, 18 | image: meta.home.image, 19 | robots: meta.home.robots, 20 | alternates: meta.home.alternates, 21 | }); 22 | } 23 | 24 | export default function RootLayout({ 25 | children, 26 | }: Readonly<{ 27 | children: React.ReactNode; 28 | }>) { 29 | return ( 30 | 42 | 49 | 50 |