create-bw-app 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +34 -0
  2. package/bin/create-bw-app.mjs +9 -0
  3. package/package.json +27 -0
  4. package/src/cli.mjs +78 -0
  5. package/src/constants.mjs +114 -0
  6. package/src/generator.mjs +821 -0
  7. package/template/base/app/bootstrap/page.tsx +75 -0
  8. package/template/base/app/globals.css +545 -0
  9. package/template/base/app/layout.tsx +16 -0
  10. package/template/base/app/page.tsx +144 -0
  11. package/template/base/app/playground/auth/auth-playground.tsx +112 -0
  12. package/template/base/app/playground/auth/page.tsx +5 -0
  13. package/template/base/app/playground/layout.tsx +41 -0
  14. package/template/base/app/preview/app-shell/page.tsx +11 -0
  15. package/template/base/app/preview/app-shell-preview.tsx +185 -0
  16. package/template/base/config/bootstrap.ts +125 -0
  17. package/template/base/config/brand.ts +21 -0
  18. package/template/base/config/client.ts +18 -0
  19. package/template/base/config/env.ts +64 -0
  20. package/template/base/config/modules.ts +62 -0
  21. package/template/base/next-env.d.ts +6 -0
  22. package/template/base/public/brand/logo-dark.svg +7 -0
  23. package/template/base/public/brand/logo-light.svg +7 -0
  24. package/template/base/public/brand/logo-mark.svg +5 -0
  25. package/template/base/tsconfig.json +36 -0
  26. package/template/modules/admin/app/api/admin/users/roles/route.ts +6 -0
  27. package/template/modules/admin/app/api/admin/users/route.ts +6 -0
  28. package/template/modules/admin/app/playground/admin/page.tsx +102 -0
  29. package/template/modules/crm/app/playground/crm/page.tsx +103 -0
  30. package/template/modules/projects/app/playground/projects/page.tsx +93 -0
  31. package/template/site/base/app/globals.css +68 -0
  32. package/template/site/base/app/layout.tsx +17 -0
  33. package/template/site/base/app/page.tsx +165 -0
  34. package/template/site/base/components/ui/badge.tsx +28 -0
  35. package/template/site/base/components/ui/button.tsx +52 -0
  36. package/template/site/base/components/ui/card.tsx +28 -0
  37. package/template/site/base/components.json +17 -0
  38. package/template/site/base/lib/utils.ts +6 -0
  39. package/template/site/base/next-env.d.ts +6 -0
  40. package/template/site/base/postcss.config.mjs +7 -0
  41. package/template/site/base/tsconfig.json +23 -0
@@ -0,0 +1,165 @@
1
+ import { ArrowRight, Layers3, MoveRight, Sparkles, SwatchBook, Waypoints } from "lucide-react";
2
+ import { siteConfig } from "@/config/site";
3
+ import { Badge } from "@/components/ui/badge";
4
+ import { ButtonLink } from "@/components/ui/button";
5
+ import { Card, CardContent, CardDescription, CardTitle } from "@/components/ui/card";
6
+
7
+ const pillars = [
8
+ {
9
+ icon: Sparkles,
10
+ title: "Branded by default",
11
+ description: "Start from an editorial Tailwind baseline with deliberate type, spacing, and color tokens instead of a blank utility sandbox.",
12
+ },
13
+ {
14
+ icon: Layers3,
15
+ title: "Shadcn-compatible local UI",
16
+ description: "The starter ships with local component primitives so the site stays easy to customize without coupling itself to the heavier platform stack.",
17
+ },
18
+ {
19
+ icon: SwatchBook,
20
+ title: "Token-ready structure",
21
+ description: "Global variables, semantic color names, and a clean `config/site.ts` entrypoint make rebranding straightforward from day one.",
22
+ },
23
+ ];
24
+
25
+ const processSteps = [
26
+ "Define the voice in `config/site.ts` and tune the hero copy.",
27
+ "Refine the palette and typography in `app/globals.css`.",
28
+ "Add sections or import new shadcn components as the site grows.",
29
+ ];
30
+
31
+ export default function HomePage() {
32
+ return (
33
+ <main className="relative overflow-hidden">
34
+ <section className="mx-auto flex min-h-screen w-full max-w-7xl flex-col px-6 py-8 sm:px-10 lg:px-12">
35
+ <header className="mb-14 flex items-center justify-between gap-6 border-b border-[color:var(--border)] pb-6">
36
+ <div>
37
+ <p className="font-display text-2xl tracking-[-0.03em]">{siteConfig.name}</p>
38
+ <p className="text-sm text-[color:var(--muted-foreground)]">{siteConfig.eyebrow}</p>
39
+ </div>
40
+ <Badge variant="accent">Next.js + Tailwind</Badge>
41
+ </header>
42
+
43
+ <div className="grid flex-1 gap-10 lg:grid-cols-[minmax(0,1.1fr)_minmax(22rem,0.9fr)] lg:items-center">
44
+ <section className="relative">
45
+ <div className="absolute -left-6 top-4 hidden h-24 w-24 rounded-full border border-[color:var(--border)] bg-white/35 blur-3xl sm:block" />
46
+ <Badge className="mb-5" variant="default">
47
+ Distinctive site scaffold
48
+ </Badge>
49
+ <h1 className="max-w-4xl font-display text-[clamp(3.75rem,10vw,8.5rem)] leading-[0.88] tracking-[-0.06em] text-[color:var(--foreground)]">
50
+ Build the first version with taste, not just tooling.
51
+ </h1>
52
+ <p className="mt-6 max-w-2xl text-lg leading-8 text-[color:var(--muted-foreground)] sm:text-xl">
53
+ {siteConfig.description} The starter is tuned for brand sites, launch pages, and polished marketing surfaces
54
+ that need a strong visual point of view from the start.
55
+ </p>
56
+
57
+ <div className="mt-8 flex flex-wrap gap-3">
58
+ <ButtonLink href={siteConfig.primaryCta.href} size="lg">
59
+ {siteConfig.primaryCta.label}
60
+ <ArrowRight className="size-4" />
61
+ </ButtonLink>
62
+ <ButtonLink href={siteConfig.secondaryCta.href} size="lg" variant="secondary">
63
+ {siteConfig.secondaryCta.label}
64
+ </ButtonLink>
65
+ </div>
66
+
67
+ <div className="mt-12 grid gap-4 border-t border-[color:var(--border)] pt-6 sm:grid-cols-3">
68
+ {[
69
+ ["01", "Type-led landing page"],
70
+ ["02", "Tailwind v4 tokens"],
71
+ ["03", "Ready for local components"],
72
+ ].map(([index, label]) => (
73
+ <div key={index}>
74
+ <p className="text-xs font-semibold uppercase tracking-[0.28em] text-[color:var(--accent)]">{index}</p>
75
+ <p className="mt-2 max-w-[14rem] text-sm leading-6 text-[color:var(--muted-foreground)]">{label}</p>
76
+ </div>
77
+ ))}
78
+ </div>
79
+ </section>
80
+
81
+ <section className="grid gap-4">
82
+ <Card className="rotate-[-1.5deg] bg-[linear-gradient(180deg,rgba(255,255,255,0.84),rgba(247,241,232,0.72))]">
83
+ <CardContent>
84
+ <p className="mb-6 text-xs font-semibold uppercase tracking-[0.28em] text-[color:var(--accent)]">
85
+ Starter composition
86
+ </p>
87
+ <div className="space-y-4">
88
+ <div className="rounded-[24px] border border-[color:var(--border)] bg-white/70 p-4">
89
+ <p className="text-sm text-[color:var(--muted-foreground)]">Hero language</p>
90
+ <p className="mt-2 font-display text-3xl tracking-[-0.04em]">Editorial, warm, and high-contrast.</p>
91
+ </div>
92
+ <div className="grid gap-4 sm:grid-cols-2">
93
+ <div className="rounded-[24px] border border-[color:var(--border)] bg-white/65 p-4">
94
+ <Waypoints className="mb-4 size-5 text-[color:var(--accent)]" />
95
+ <p className="text-sm text-[color:var(--muted-foreground)]">Flexible sections</p>
96
+ </div>
97
+ <div className="rounded-[24px] border border-[color:var(--border)] bg-white/65 p-4">
98
+ <MoveRight className="mb-4 size-5 text-[color:var(--accent)]" />
99
+ <p className="text-sm text-[color:var(--muted-foreground)]">Immediate polish</p>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </CardContent>
104
+ </Card>
105
+
106
+ <Card className="translate-x-4 bg-[rgba(35,32,28,0.94)] text-white">
107
+ <CardContent>
108
+ <p className="text-xs font-semibold uppercase tracking-[0.28em] text-white/55">Why this exists</p>
109
+ <p className="mt-4 font-display text-3xl tracking-[-0.04em]">
110
+ A lighter path than the platform app, without giving up design discipline.
111
+ </p>
112
+ </CardContent>
113
+ </Card>
114
+ </section>
115
+ </div>
116
+ </section>
117
+
118
+ <section className="mx-auto w-full max-w-7xl px-6 pb-10 sm:px-10 lg:px-12">
119
+ <div className="grid gap-5 lg:grid-cols-3">
120
+ {pillars.map((pillar) => {
121
+ const Icon = pillar.icon;
122
+ return (
123
+ <Card key={pillar.title}>
124
+ <CardContent>
125
+ <Icon className="mb-5 size-5 text-[color:var(--accent)]" />
126
+ <CardTitle>{pillar.title}</CardTitle>
127
+ <CardDescription className="mt-3">{pillar.description}</CardDescription>
128
+ </CardContent>
129
+ </Card>
130
+ );
131
+ })}
132
+ </div>
133
+ </section>
134
+
135
+ <section id="process" className="mx-auto w-full max-w-7xl px-6 pb-20 sm:px-10 lg:px-12">
136
+ <div className="grid gap-5 lg:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)]">
137
+ <Card className="bg-[rgba(255,255,255,0.64)]">
138
+ <CardContent>
139
+ <Badge variant="accent">Three quick passes</Badge>
140
+ <CardTitle className="mt-5 text-[clamp(2rem,4vw,3.4rem)]">Tune the voice, then ship.</CardTitle>
141
+ <CardDescription className="mt-4 max-w-xl text-base">
142
+ The starter gives you structure, not bureaucracy. Rename the site, adjust the tone, and keep moving.
143
+ </CardDescription>
144
+ </CardContent>
145
+ </Card>
146
+
147
+ <div className="grid gap-4">
148
+ {processSteps.map((step, index) => (
149
+ <Card key={step} className="bg-white/70">
150
+ <CardContent className="flex gap-4">
151
+ <div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-[color:var(--accent-soft)] font-semibold text-[color:var(--accent)]">
152
+ {index + 1}
153
+ </div>
154
+ <div>
155
+ <CardTitle className="text-xl">{step}</CardTitle>
156
+ </div>
157
+ </CardContent>
158
+ </Card>
159
+ ))}
160
+ </div>
161
+ </div>
162
+ </section>
163
+ </main>
164
+ );
165
+ }
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const badgeVariants = cva(
6
+ "inline-flex items-center rounded-full border px-3 py-1 text-[0.68rem] font-semibold uppercase tracking-[0.24em]",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "border-[color:var(--border)] bg-white/70 text-[color:var(--muted-foreground)]",
11
+ accent: "border-transparent bg-[color:var(--accent-soft)] text-[color:var(--accent)]",
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ variant: "default",
16
+ },
17
+ },
18
+ );
19
+
20
+ function Badge({
21
+ className,
22
+ variant,
23
+ ...props
24
+ }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
25
+ return <span className={cn(badgeVariants({ variant, className }))} {...props} />;
26
+ }
27
+
28
+ export { Badge, badgeVariants };
@@ -0,0 +1,52 @@
1
+ import * as React from "react";
2
+ import Link from "next/link";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ const buttonVariants = cva(
7
+ "inline-flex items-center justify-center gap-2 rounded-full border text-sm font-medium transition duration-200 outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[color:var(--background)] disabled:pointer-events-none disabled:opacity-50",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "border-transparent bg-[color:var(--foreground)] text-[color:var(--background)] shadow-[0_18px_40px_rgba(15,23,42,0.18)] hover:-translate-y-0.5 hover:bg-[color:var(--accent)]",
13
+ secondary:
14
+ "border-[color:var(--border)] bg-[color:var(--panel)] text-[color:var(--foreground)] hover:-translate-y-0.5 hover:border-[color:var(--accent)] hover:bg-white/80",
15
+ ghost:
16
+ "border-transparent bg-transparent text-[color:var(--muted-foreground)] hover:text-[color:var(--foreground)]",
17
+ },
18
+ size: {
19
+ default: "h-11 px-5",
20
+ lg: "h-12 px-6 text-[0.95rem]",
21
+ sm: "h-9 px-4 text-xs uppercase tracking-[0.22em]",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default",
27
+ },
28
+ },
29
+ );
30
+
31
+ type ButtonProps = React.ComponentProps<"button"> &
32
+ VariantProps<typeof buttonVariants>;
33
+
34
+ function Button({ className, variant, size, ...props }: ButtonProps) {
35
+ return <button className={cn(buttonVariants({ variant, size, className }))} {...props} />;
36
+ }
37
+
38
+ function ButtonLink({
39
+ href,
40
+ className,
41
+ variant,
42
+ size,
43
+ children,
44
+ }: React.ComponentProps<typeof Link> & VariantProps<typeof buttonVariants>) {
45
+ return (
46
+ <Link href={href} className={cn(buttonVariants({ variant, size, className }))}>
47
+ {children}
48
+ </Link>
49
+ );
50
+ }
51
+
52
+ export { Button, ButtonLink, buttonVariants };
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ function Card({ className, ...props }: React.ComponentProps<"article">) {
5
+ return (
6
+ <article
7
+ className={cn(
8
+ "rounded-[28px] border border-[color:var(--border)] bg-[color:var(--panel)] shadow-[0_24px_60px_rgba(15,23,42,0.08)] backdrop-blur-sm",
9
+ className,
10
+ )}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+
16
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
17
+ return <div className={cn("p-6 sm:p-7", className)} {...props} />;
18
+ }
19
+
20
+ function CardTitle({ className, ...props }: React.ComponentProps<"h3">) {
21
+ return <h3 className={cn("font-display text-2xl tracking-[-0.03em] text-[color:var(--foreground)]", className)} {...props} />;
22
+ }
23
+
24
+ function CardDescription({ className, ...props }: React.ComponentProps<"p">) {
25
+ return <p className={cn("text-sm leading-7 text-[color:var(--muted-foreground)]", className)} {...props} />;
26
+ }
27
+
28
+ export { Card, CardContent, CardDescription, CardTitle };
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "tsx": true,
5
+ "rsc": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true
11
+ },
12
+ "aliases": {
13
+ "components": "@/components",
14
+ "ui": "@/components/ui",
15
+ "utils": "@/lib/utils"
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,6 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
+
5
+ // NOTE: This file should not be edited
6
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": false,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }],
17
+ "paths": {
18
+ "@/*": ["./*"]
19
+ }
20
+ },
21
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
22
+ "exclude": ["node_modules"]
23
+ }