monoframe 0.0.1-beta.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.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +417 -0
- package/package.json +49 -0
- package/templates/packages/config-biome/biome.json +33 -0
- package/templates/packages/config-eslint/express.js +19 -0
- package/templates/packages/config-eslint/next.js +27 -0
- package/templates/packages/config-typescript/base.json +15 -0
- package/templates/packages/config-typescript/express.json +9 -0
- package/templates/packages/config-typescript/nextjs.json +12 -0
- package/templates/turbo/pnpm-workspace.yaml +3 -0
- package/templates/turbo/turbo.json +18 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import{Command as Pt}from"commander";import Se from"prompts";import J from"picocolors";var b=class extends Error{constructor(){super("Operation cancelled."),this.name="PromptCancelledError"}};import ve from"conf";import L from"picocolors";import Pe from"ora";var w={error:e=>console.error(L.red(e)),success:e=>console.log(L.green(e)),info:e=>console.log(L.cyan(e)),warn:e=>console.log(L.yellow(e))};function A(e){return Pe({text:e,color:"cyan"}).start()}var Ce={codeQuality:{type:"string",enum:["eslint-prettier","biome"]},shadcnEnabled:{type:"boolean"},shadcnBase:{type:"string"},shadcnPreset:{type:"string"},shadcnCustomPresetCode:{type:"string"},animations:{type:"array",items:{type:"string"}},featureHusky:{type:"boolean"},featurePlaywright:{type:"boolean"},featureGithubActions:{type:"boolean"}},ke={codeQuality:"eslint-prettier",shadcnEnabled:!0,shadcnBase:"radix",shadcnPreset:"nova",shadcnCustomPresetCode:"",animations:[],featureHusky:!1,featurePlaywright:!1,featureGithubActions:!1},_=new ve({projectName:"monoframe",schema:Ce,defaults:ke});function P(e){try{return _.get(e)}catch{return}}function H(e){try{_.set({codeQuality:e.codeQuality,shadcnEnabled:e.shadcn.enabled,shadcnBase:e.shadcn.base,shadcnPreset:e.shadcn.preset,shadcnCustomPresetCode:e.shadcn.customPresetCode??"",animations:e.animations,featureHusky:e.features.husky,featurePlaywright:e.features.playwright,featureGithubActions:e.features.githubActions})}catch{w.warn("Could not save preferences. Your choices will not be remembered next time.")}}function U(){try{return _.clear(),!0}catch{return w.warn("Could not clear preferences. Try manually deleting the config file."),!1}}var z=[{title:"ESLint + Prettier",value:"eslint-prettier"},{title:"Biome (faster alternative)",value:"biome"}];async function W(){let e=P("codeQuality"),t=Math.max(0,z.findIndex(n=>n.value===e));return await Se([{type:"text",name:"projectName",message:"What is your project name?",initial:"my-saas",validate:n=>/^[a-z0-9-]+$/.test(n)?!0:"Project name must be lowercase alphanumeric and hyphens"},{type:"select",name:"monorepoTool",message:"Which monorepo tool?",choices:[{title:"Turborepo (recommended)",value:"turborepo"},{title:J.gray("Nx (coming in v1.1)"),value:"nx",disabled:!0}]},{type:"select",name:"framework",message:"Which frontend framework?",choices:[{title:"Next.js",value:"nextjs"},{title:J.gray("React (coming soon)"),value:"react",disabled:!0}]},{type:"select",name:"codeQuality",message:"Code quality tooling?",choices:z,initial:t}],{onCancel:()=>{throw new b}})}import V from"prompts";async function Y(){let{count:e}=await V({type:"number",name:"count",message:"How many apps do you want to create? (1-5)",initial:2,min:1,max:5},{onCancel:()=>{throw new b}}),t=[];for(let o=1;o<=e;o++){let n=o===1?"web":o===2?"api":`app-${o}`,s=await V([{type:"text",name:"name",message:`App ${o} \u2014 Name:`,initial:n,validate:i=>/^[a-z0-9-]+$/.test(i)?t.some(l=>l.name===i)?"App name must be unique":!0:"App name must be lowercase alphanumeric and hyphens"},{type:"select",name:"type",message:`App ${o} \u2014 Type:`,choices:[{title:"Frontend",value:"frontend"},{title:"Backend (Node.js + Express)",value:"backend"}]}],{onCancel:()=>{throw new b}});t.push(s)}return t}import $ from"prompts";var q={enabled:!1,base:"radix",preset:"nova"},K=[{title:"Radix (most popular)",value:"radix"},{title:"Base UI (alternative)",value:"base"}],X=[{title:"Nova (Lucide / Geist)",value:"nova"},{title:"Vega (Lucide / Inter)",value:"vega"},{title:"Maia (Hugeicons / Figtree)",value:"maia"},{title:"Lyra (Phosphor / JetBrains Mono)",value:"lyra"},{title:"Mira (Hugeicons / Inter)",value:"mira"},{title:"Custom (from ui.shadcn.com/create)",value:"custom"}];async function Z(e){if(!e.some(k=>k.type==="frontend"))return q;let o=P("shadcnEnabled"),{enabled:n}=await $({type:"confirm",name:"enabled",message:"Include shadcn/ui components? (applied to all frontend apps)",initial:o??!0},{onCancel:()=>{throw new b}});if(!n)return q;let s=P("shadcnBase"),i=P("shadcnPreset"),l=Math.max(0,K.findIndex(k=>k.value===s)),m=Math.max(0,X.findIndex(k=>k.value===i)),a=await $([{type:"select",name:"base",message:"Component library base?",choices:K,initial:l},{type:"select",name:"preset",message:"shadcn design preset?",choices:X,initial:m}],{onCancel:()=>{throw new b}}),d=P("shadcnCustomPresetCode"),E;if(a.preset==="custom"){let{code:k}=await $({type:"text",name:"code",message:"Enter your shadcn preset code (from ui.shadcn.com/create):",initial:d??"",validate:R=>R.trim().length>0?!0:"Preset code cannot be empty"},{onCancel:()=>{throw new b}});E=k}return{enabled:!0,base:a.base,preset:a.preset,customPresetCode:E}}import Ee from"prompts";async function ee(){let e=P("animations")??[],t=P("featureHusky")??!1,o=P("featurePlaywright")??!1,n=P("featureGithubActions")??!1,s=await Ee([{type:"multiselect",name:"animations",message:"Animation libraries (press Space to select, Enter to skip):",instructions:!1,choices:[{title:"Framer Motion",value:"framer-motion",selected:e.includes("framer-motion")},{title:"Lenis (smooth scroll)",value:"lenis",selected:e.includes("lenis")},{title:"GSAP",value:"gsap",selected:e.includes("gsap")}]},{type:"multiselect",name:"featuresRaw",message:"Extra features (press Space to select, Enter to skip):",instructions:!1,choices:[{title:"Husky + lint-staged (git hooks)",value:"husky",selected:t},{title:"Playwright (e2e testing)",value:"playwright",selected:o},{title:"GitHub Actions CI",value:"githubActions",selected:n}]}],{onCancel:()=>{throw new b}}),i=s.featuresRaw||[];return{animations:s.animations||[],features:{husky:i.includes("husky"),playwright:i.includes("playwright"),githubActions:i.includes("githubActions")}}}var te={projectName:"my-saas",monorepoTool:"turborepo",framework:"nextjs",codeQuality:"eslint-prettier",apps:[{name:"web",type:"frontend"},{name:"api",type:"backend"}],shadcn:{enabled:!0,base:"radix",preset:"nova",customPresetCode:void 0},animations:[],features:{husky:!1,playwright:!1,githubActions:!1}};import{z as f}from"zod";var Ae=f.object({name:f.string().min(1).regex(/^[a-z0-9-]+$/,"App name must be lowercase alphanumeric and hyphens"),type:f.enum(["frontend","backend"])}),Te=f.object({enabled:f.boolean(),base:f.enum(["radix","base"]),preset:f.enum(["nova","vega","maia","lyra","mira","custom"]),customPresetCode:f.string().optional()}),oe=f.object({projectName:f.string().min(1).regex(/^[a-z0-9-]+$/,"Project name must be lowercase alphanumeric and hyphens"),monorepoTool:f.literal("turborepo"),framework:f.literal("nextjs"),codeQuality:f.enum(["eslint-prettier","biome"]),apps:f.array(Ae).min(1).max(5),shadcn:Te,animations:f.array(f.enum(["framer-motion","lenis","gsap"])),features:f.object({husky:f.boolean(),playwright:f.boolean(),githubActions:f.boolean()})});import T from"fs-extra";import I from"path";import{fileURLToPath as Ie}from"url";var De=Ie(import.meta.url),Re=I.dirname(De);function Le(){let e=Re;for(;!T.existsSync(I.join(e,"package.json"));)if(e=I.dirname(e),e==="/"||e==="."||e.match(/^[A-Z]:\\$/))throw new Error("Could not find package root");return I.join(e,"templates")}async function v(e,t){let o=Le(),n=I.join(o,e);if(!T.existsSync(n))throw new Error(`Template not found: ${n}`);await T.copy(n,t)}async function h(e,t){await T.outputJson(e,t,{spaces:2})}async function c(e,t){await T.outputFile(e,t)}async function u(e){await T.ensureDir(e)}import N from"fs-extra";import xt from"path";import F from"path";var ne={turbo:"^2.0.0"},r={next:"latest",react:"latest","react-dom":"latest",typescript:"latest",tailwindcss:"latest",eslint:"^9",prettier:"latest","@biomejs/biome":"latest","framer-motion":"latest",lenis:"latest",gsap:"latest","@playwright/test":"latest",husky:"latest","lint-staged":"latest",express:"latest",cors:"latest",tsx:"latest","@types/express":"latest","@types/cors":"latest","@types/node":"latest","@types/react":"latest","@types/react-dom":"latest"};async function ie(e,t){let o={name:e.projectName,private:!0,scripts:{build:"turbo build",dev:"turbo dev",lint:"turbo lint","ui:add":"pnpm dlx shadcn@latest add -c packages/ui",format:e.codeQuality==="biome"?"biome format --write .":'prettier --write "**/*.{ts,tsx,md}"',prepare:e.features.husky?"husky":void 0},devDependencies:{turbo:ne.turbo,typescript:r.typescript,...e.features.husky?{husky:r.husky,"lint-staged":r["lint-staged"]}:{}},packageManager:"pnpm@9.15.0"};e.codeQuality==="eslint-prettier"?o.devDependencies={...o.devDependencies,prettier:r.prettier}:e.codeQuality==="biome"&&(o.devDependencies={...o.devDependencies,"@biomejs/biome":r["@biomejs/biome"]}),Object.keys(o.scripts).forEach(n=>{o.scripts[n]===void 0&&delete o.scripts[n]}),await h(F.join(t,"package.json"),o),await v("turbo/turbo.json",F.join(t,"turbo.json")),await v("turbo/pnpm-workspace.yaml",F.join(t,"pnpm-workspace.yaml"))}import x from"path";async function se(e,t){let o=x.join(t,"packages");await u(o);let n=x.join(o,"config-typescript");if(await u(n),await h(x.join(n,"package.json"),{name:"@repo/typescript-config",version:"0.0.0",private:!0,license:"MIT"}),await v("packages/config-typescript/base.json",x.join(n,"base.json")),await v("packages/config-typescript/nextjs.json",x.join(n,"nextjs.json")),await v("packages/config-typescript/express.json",x.join(n,"express.json")),e.codeQuality==="eslint-prettier"){let s=x.join(o,"config-eslint");await u(s),await h(x.join(s,"package.json"),{name:"@repo/eslint-config",version:"0.0.0",private:!0,type:"module",license:"MIT",dependencies:{eslint:r.eslint,"@eslint/js":"^9","@eslint/eslintrc":"^3","typescript-eslint":"^8","eslint-config-next":"^15","eslint-config-prettier":"^9","eslint-plugin-react":"^7"}}),await v("packages/config-eslint/next.js",x.join(s,"next.js")),await v("packages/config-eslint/express.js",x.join(s,"express.js"))}else if(e.codeQuality==="biome"){let s=x.join(o,"config-biome");await u(s),await h(x.join(s,"package.json"),{name:"@repo/biome-config",version:"0.0.0",private:!0,license:"MIT"}),await v("packages/config-biome/biome.json",x.join(s,"biome.json"))}}import C from"path";var Ne=`import type { Metadata } from 'next';
|
|
4
|
+
import { Inter } from 'next/font/google';
|
|
5
|
+
import './globals.css';
|
|
6
|
+
|
|
7
|
+
const inter = Inter({ subsets: ['latin'] });
|
|
8
|
+
|
|
9
|
+
export const metadata: Metadata = {
|
|
10
|
+
title: 'APP_DISPLAY_NAME',
|
|
11
|
+
description: 'Generated by Monoframe',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function RootLayout({
|
|
15
|
+
children,
|
|
16
|
+
}: Readonly<{
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}>) {
|
|
19
|
+
return (
|
|
20
|
+
<html lang="en">
|
|
21
|
+
<body className={inter.className}>{children}</body>
|
|
22
|
+
</html>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
`,_e=`export default function Home() {
|
|
26
|
+
return (
|
|
27
|
+
<main className="flex min-h-screen flex-col items-center justify-center p-24">
|
|
28
|
+
<h1 className="text-4xl font-bold">APP_DISPLAY_NAME</h1>
|
|
29
|
+
<p className="mt-4 text-lg text-gray-500">
|
|
30
|
+
Edit <code className="font-mono font-bold">app/page.tsx</code> to get started.
|
|
31
|
+
</p>
|
|
32
|
+
</main>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
`,$e=`@import 'tailwindcss';
|
|
36
|
+
`,Fe=`import type { NextConfig } from 'next';
|
|
37
|
+
|
|
38
|
+
const nextConfig: NextConfig = {
|
|
39
|
+
transpilePackages: ['@repo/ui'],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default nextConfig;
|
|
43
|
+
`;function Oe(){return`import type { Config } from 'tailwindcss';
|
|
44
|
+
|
|
45
|
+
const config: Config = {
|
|
46
|
+
content: [
|
|
47
|
+
'./app/**/*.{ts,tsx}',
|
|
48
|
+
'./components/**/*.{ts,tsx}',
|
|
49
|
+
'../../packages/ui/src/**/*.{ts,tsx}',
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default config;
|
|
54
|
+
`}function Me(){return{extends:"@repo/typescript-config/nextjs.json",compilerOptions:{plugins:[{name:"next"}],paths:{"@/*":["./*"]}},include:["next-env.d.ts","**/*.ts","**/*.tsx",".next/types/**/*.ts"],exclude:["node_modules"]}}function Ge(e,t){let o={next:r.next,react:r.react,"react-dom":r["react-dom"]},n={"@repo/typescript-config":"workspace:*","@types/node":r["@types/node"],"@types/react":r["@types/react"],"@types/react-dom":r["@types/react-dom"],tailwindcss:r.tailwindcss};return t.codeQuality==="eslint-prettier"?(n["@repo/eslint-config"]="workspace:*",n.eslint=r.eslint):t.codeQuality==="biome"&&(n["@biomejs/biome"]=r["@biomejs/biome"]),{name:e.name,version:"0.0.0",private:!0,scripts:{dev:"next dev --turbopack",build:"next build",start:"next start",lint:t.codeQuality==="biome"?"biome check .":"next lint"},dependencies:o,devDependencies:n}}async function re(e,t){let o=e.apps.filter(n=>n.type==="frontend");for(let n of o){let s=C.join(t,"apps",n.name),i=C.join(s,"app");await u(i);let l=n.name.split("-").map(m=>m.charAt(0).toUpperCase()+m.slice(1)).join(" ");await h(C.join(s,"package.json"),Ge(n,e)),await h(C.join(s,"tsconfig.json"),Me()),await c(C.join(s,"next.config.ts"),Fe),await c(C.join(s,"tailwind.config.ts"),Oe()),await c(C.join(i,"layout.tsx"),Ne.replaceAll("APP_DISPLAY_NAME",l)),await c(C.join(i,"page.tsx"),_e.replaceAll("APP_DISPLAY_NAME",l)),await c(C.join(i,"globals.css"),$e)}}import S from"path";var Qe=4e3;function Be(e){return`import { Router } from 'express';
|
|
55
|
+
|
|
56
|
+
const router = Router();
|
|
57
|
+
|
|
58
|
+
router.get('/', (_req, res) => {
|
|
59
|
+
res.json({ status: 'ok', service: '${e}' });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export default router;
|
|
63
|
+
`}function He(e,t){return`import express from 'express';
|
|
64
|
+
import cors from 'cors';
|
|
65
|
+
import healthRouter from './routes/health.js';
|
|
66
|
+
|
|
67
|
+
const app = express();
|
|
68
|
+
const PORT = process.env.PORT || ${t};
|
|
69
|
+
|
|
70
|
+
app.use(cors());
|
|
71
|
+
app.use(express.json());
|
|
72
|
+
|
|
73
|
+
app.use('/health', healthRouter);
|
|
74
|
+
|
|
75
|
+
app.listen(PORT, () => {
|
|
76
|
+
console.log(\`[${e}] Server running on http://localhost:\${PORT}\`);
|
|
77
|
+
});
|
|
78
|
+
`}function Ue(e,t){let o={"@repo/typescript-config":"workspace:*","@types/express":r["@types/express"],"@types/cors":r["@types/cors"],"@types/node":r["@types/node"],tsx:r.tsx};return t.codeQuality==="eslint-prettier"?(o["@repo/eslint-config"]="workspace:*",o.eslint=r.eslint):t.codeQuality==="biome"&&(o["@biomejs/biome"]=r["@biomejs/biome"]),{name:e.name,version:"0.0.0",private:!0,type:"module",scripts:{dev:"tsx watch src/index.ts",build:"tsc",start:"node dist/index.js",lint:t.codeQuality==="biome"?"biome check .":'eslint "src/**/*.ts"'},dependencies:{express:r.express,cors:r.cors},devDependencies:o}}function Je(){return{extends:"@repo/typescript-config/express.json",compilerOptions:{rootDir:"src"},include:["src"],exclude:["node_modules","dist"]}}async function ae(e,t){let o=e.apps.filter(n=>n.type==="backend");for(let n=0;n<o.length;n++){let s=o[n],i=S.join(t,"apps",s.name),l=S.join(i,"src"),m=S.join(l,"routes"),a=Qe+n;await u(m),await h(S.join(i,"package.json"),Ue(s,e)),await h(S.join(i,"tsconfig.json"),Je()),await c(S.join(l,"index.ts"),He(s.name,a)),await c(S.join(m,"health.ts"),Be(s.name))}}import p from"path";import{execa as ze}from"execa";import g from"fs-extra";var We={nova:"nova",vega:"vega",maia:"maia",lyra:"lyra",mira:"mira"},Ve=`import { type ClassValue, clsx } from 'clsx';
|
|
79
|
+
import { twMerge } from 'tailwind-merge';
|
|
80
|
+
|
|
81
|
+
export function cn(...inputs: ClassValue[]) {
|
|
82
|
+
return twMerge(clsx(inputs));
|
|
83
|
+
}
|
|
84
|
+
`;function Ye(){return{name:"@repo/ui",version:"0.0.0",private:!0,type:"module",exports:{".":"./src/index.ts","./src/*":"./src/*","./lib/*":"./lib/*","./hooks/*":"./hooks/*"},dependencies:{clsx:"latest","tailwind-merge":"latest","tw-animate-css":"latest"},devDependencies:{"@repo/typescript-config":"workspace:*"},peerDependencies:{react:">=18","react-dom":">=18"}}}function qe(){return{extends:"@repo/typescript-config/nextjs.json",compilerOptions:{outDir:"dist"},include:["src","lib","hooks"],exclude:["node_modules","dist"]}}async function Ke(e,t){let o;t.shadcn.preset==="custom"?(t.shadcn.customPresetCode||w.warn('Custom preset selected but no code provided; falling back to "nova".'),o=t.shadcn.customPresetCode??"nova"):o=We[t.shadcn.preset]??"nova";let n=A("Running shadcn init...");try{return await ze("npx",["shadcn@latest","init","--yes","--preset",o,"--base",t.shadcn.base],{cwd:e,stdio:"pipe"}),n.succeed("shadcn/ui initialized"),!0}catch{return n.fail("shadcn init failed \u2014 skipping. You can run it manually later."),!1}}function pe(e){let t=e.preset==="custom"?"nova":e.preset;return`${e.base}-${t}`}async function Xe(e,t){let o={style:pe(t),iconLibrary:"lucide",baseColor:"neutral"};if(!await g.pathExists(e))return o;try{let n=await g.readJson(e);return{style:n.style??o.style,iconLibrary:n.iconLibrary??o.iconLibrary,baseColor:n.tailwind?.baseColor??o.baseColor}}catch{return o}}async function Ze(e,t){let o=p.join(e,"components","ui"),n=p.join(t,"src","components");if(await g.pathExists(o)){let d=await g.readdir(o);for(let R of d)await g.move(p.join(o,R),p.join(n,R),{overwrite:!0});await g.remove(o);let E=p.join(e,"components");(await g.readdir(E).catch(()=>[])).length===0&&await g.remove(E)}let s=p.join(e,"lib","utils.ts"),i=p.join(t,"lib","utils.ts");if(await g.pathExists(s)){await g.move(s,i,{overwrite:!0});let d=p.join(e,"lib");(await g.readdir(d).catch(()=>[])).length===0&&await g.remove(d)}let l=p.join(e,"app","globals.css"),m=p.join(t,"src","styles","globals.css");await g.pathExists(l)&&await g.move(l,m,{overwrite:!0});let a=p.join(e,"components.json");await g.pathExists(a)&&await g.remove(a)}async function et(e,t){for(let o of t){let n=`/*
|
|
85
|
+
* Shared design tokens from @repo/ui (colors, radius, fonts, etc.)
|
|
86
|
+
* All frontend apps import this \u2014 changes here affect every app.
|
|
87
|
+
* Source: packages/ui/src/styles/globals.css
|
|
88
|
+
*/
|
|
89
|
+
@import '@repo/ui/src/styles/globals.css';
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* App-specific overrides for "${o.name}"
|
|
93
|
+
*
|
|
94
|
+
* Want different colors for this app? Override CSS variables below.
|
|
95
|
+
* Only the variables you set here will change \u2014 everything else
|
|
96
|
+
* stays from the shared design tokens above.
|
|
97
|
+
*
|
|
98
|
+
* Example \u2014 give this app a custom primary color:
|
|
99
|
+
*
|
|
100
|
+
* :root {
|
|
101
|
+
* --primary: oklch(0.6 0.2 150);
|
|
102
|
+
* --primary-foreground: oklch(0.985 0 0);
|
|
103
|
+
* }
|
|
104
|
+
*
|
|
105
|
+
* .dark {
|
|
106
|
+
* --primary: oklch(0.7 0.15 150);
|
|
107
|
+
* }
|
|
108
|
+
*
|
|
109
|
+
* Browse themes: https://ui.shadcn.com/themes
|
|
110
|
+
*/
|
|
111
|
+
`,s=p.join(e,"apps",o.name,"app","globals.css");await c(s,n)}}function ce(e){return{$schema:"https://ui.shadcn.com/schema.json",style:e.style,rsc:!0,tsx:!0,tailwind:{config:"",css:"src/styles/globals.css",baseColor:e.baseColor,cssVariables:!0},iconLibrary:e.iconLibrary,aliases:{ui:"./src/components",components:"./src/blocks",hooks:"./hooks",lib:"./lib",utils:"./lib/utils"}}}async function le(e,t){if(!e.shadcn.enabled)return;let o=e.apps.filter(m=>m.type==="frontend");if(o.length===0)return;let n=o[0],s=p.join(t,"apps",n.name),i=p.join(t,"packages","ui");if(await u(p.join(i,"src","components")),await u(p.join(i,"src","blocks")),await u(p.join(i,"src","providers")),await u(p.join(i,"src","styles")),await u(p.join(i,"hooks")),await u(p.join(i,"lib")),await h(p.join(i,"package.json"),Ye()),await h(p.join(i,"tsconfig.json"),qe()),await c(p.join(i,"src","index.ts"),`// Export your UI components here
|
|
112
|
+
`),await Ke(s,e)){let m=p.join(s,"components.json"),a=await Xe(m,e.shadcn);await Ze(s,i);let d=p.join(i,"src","styles","globals.css");await g.pathExists(d)||await c(d,`@import 'tailwindcss';
|
|
113
|
+
@import 'tw-animate-css';
|
|
114
|
+
`),await h(p.join(i,"components.json"),ce(a))}else await c(p.join(i,"lib","utils.ts"),Ve),await c(p.join(i,"src","styles","globals.css"),`@import 'tailwindcss';
|
|
115
|
+
@import 'tw-animate-css';
|
|
116
|
+
`),await h(p.join(i,"components.json"),ce({style:pe(e.shadcn),iconLibrary:"lucide",baseColor:"neutral"}));await et(t,o);for(let m of o){let a=p.join(t,"apps",m.name,"package.json");if(await g.pathExists(a)){let d=await g.readJson(a);d.dependencies={...d.dependencies,"@repo/ui":"workspace:*"},await h(a,d)}}}import j from"path";import y from"fs-extra";var tt=`'use client';
|
|
117
|
+
|
|
118
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
119
|
+
import { usePathname } from 'next/navigation';
|
|
120
|
+
|
|
121
|
+
interface MotionWrapperProps {
|
|
122
|
+
children: React.ReactNode;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function MotionWrapper({ children }: MotionWrapperProps) {
|
|
126
|
+
const pathname = usePathname();
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<AnimatePresence mode="wait">
|
|
130
|
+
<motion.div
|
|
131
|
+
key={pathname}
|
|
132
|
+
initial={{ opacity: 0, y: 20 }}
|
|
133
|
+
animate={{ opacity: 1, y: 0 }}
|
|
134
|
+
exit={{ opacity: 0, y: -20 }}
|
|
135
|
+
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
|
136
|
+
>
|
|
137
|
+
{children}
|
|
138
|
+
</motion.div>
|
|
139
|
+
</AnimatePresence>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
`,ot=`'use client';
|
|
143
|
+
|
|
144
|
+
import { ReactLenis } from 'lenis/react';
|
|
145
|
+
|
|
146
|
+
interface SmoothScrollProviderProps {
|
|
147
|
+
children: React.ReactNode;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function SmoothScrollProvider({ children }: SmoothScrollProviderProps) {
|
|
151
|
+
return (
|
|
152
|
+
<ReactLenis root options={{ lerp: 0.1, duration: 1.2, smoothWheel: true }}>
|
|
153
|
+
{children}
|
|
154
|
+
</ReactLenis>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
`,nt=`'use client';
|
|
158
|
+
|
|
159
|
+
import { gsap } from 'gsap';
|
|
160
|
+
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
161
|
+
|
|
162
|
+
// Register GSAP plugins once \u2014 imported in root layout
|
|
163
|
+
gsap.registerPlugin(ScrollTrigger);
|
|
164
|
+
|
|
165
|
+
export { gsap, ScrollTrigger };
|
|
166
|
+
`,it=`import { MotionWrapper } from '@repo/ui';
|
|
167
|
+
|
|
168
|
+
export default function Template({ children }: { children: React.ReactNode }) {
|
|
169
|
+
return <MotionWrapper>{children}</MotionWrapper>;
|
|
170
|
+
}
|
|
171
|
+
`;async function st(e,t){e.animations.includes("framer-motion")&&await c(j.join(t,"motion-wrapper.tsx"),tt),e.animations.includes("lenis")&&await c(j.join(t,"smooth-scroll-provider.tsx"),ot)}async function rt(e,t){e.animations.includes("gsap")&&await c(j.join(t,"gsap-register.ts"),nt)}async function at(e,t){let o=e.apps.filter(l=>l.type==="frontend"),n=e.animations.includes("framer-motion"),s=e.animations.includes("lenis"),i=e.animations.includes("gsap");for(let l of o){let m=j.join(t,"apps",l.name),a=j.join(m,"app");n&&await c(j.join(a,"template.tsx"),it),(s||i)&&await ct(j.join(a,"layout.tsx"),{hasLenis:s,hasGsap:i}),await pt(j.join(m,"package.json"),e)}}async function ct(e,t){if(!await y.pathExists(e))return;let o=await y.readFile(e,"utf-8"),n=[];if(t.hasGsap){let s="import '@repo/ui/lib/gsap-register';";o.includes(s)||n.push(s)}if(t.hasLenis){let s="import { SmoothScrollProvider } from '@repo/ui';";o.includes(s)||n.push(s)}if(n.length>0){let s=o.lastIndexOf("import "),i=o.indexOf(`
|
|
172
|
+
`,s);o=o.slice(0,i+1)+n.join(`
|
|
173
|
+
`)+`
|
|
174
|
+
`+o.slice(i+1)}if(t.hasLenis&&!o.includes("<SmoothScrollProvider>{children}</SmoothScrollProvider>")){let i=/<body className=\{inter\.className\}>\s*\{children\}\s*<\/body>/m,l=o.replace(i,"<body className={inter.className}><SmoothScrollProvider>{children}</SmoothScrollProvider></body>");if(l===o)throw new Error(`Unable to inject SmoothScrollProvider in ${e}. Expected pattern: <body className={inter.className}>{children}</body>`);o=l}await y.writeFile(e,o)}async function pt(e,t){if(!await y.pathExists(e))return;let o=await y.readJson(e),n={};t.animations.length>0&&(n["@repo/ui"]="workspace:*"),t.animations.includes("framer-motion")&&(n["framer-motion"]=r["framer-motion"]),t.animations.includes("lenis")&&(n.lenis=r.lenis),t.animations.includes("gsap")&&(n.gsap=r.gsap),Object.keys(n).length>0&&(o.dependencies={...o.dependencies,...n},await y.writeJson(e,o,{spaces:2}))}async function lt(e,t){if(!await y.pathExists(e))return;let o=await y.readJson(e),n={};t.animations.includes("framer-motion")&&(n["framer-motion"]=">=10"),t.animations.includes("lenis")&&(n.lenis=">=1"),t.animations.includes("gsap")&&(n.gsap=">=3"),Object.keys(n).length>0&&(o.peerDependencies={...o.peerDependencies,...n},await y.writeJson(e,o,{spaces:2}))}async function mt(e,t){let o=j.join(t,"index.ts");await y.pathExists(o)||await y.writeFile(o,"");let n=await y.readFile(o,"utf-8"),s=[];if(e.animations.includes("framer-motion")){let i="export { MotionWrapper } from './motion-wrapper';";n.includes(i)||s.push(i)}if(e.animations.includes("lenis")){let i="export { SmoothScrollProvider } from './smooth-scroll-provider';";n.includes(i)||s.push(i)}s.length>0&&(n+=`
|
|
175
|
+
`+s.join(`
|
|
176
|
+
`)+`
|
|
177
|
+
`,await y.writeFile(o,n))}async function me(e,t){if(e.animations.length===0||e.apps.filter(a=>a.type==="frontend").length===0)return;let n=j.join(t,"packages","ui","src","providers"),s=j.join(t,"packages","ui","lib");await u(n),await u(s),await st(e,n),await rt(e,s),await mt(e,n);let i=j.join(t,"packages","ui","src","index.ts");await y.pathExists(i)||(await u(j.dirname(i)),await y.writeFile(i,`// Export your UI components here
|
|
178
|
+
`));let l=await y.readFile(i,"utf-8"),m="export * from './providers/index.js';";l.includes(m)||await y.writeFile(i,l.trimEnd()+`
|
|
179
|
+
`+m+`
|
|
180
|
+
`),await lt(j.join(t,"packages","ui","package.json"),e),await at(e,t)}import O from"path";import D from"fs-extra";import{execa as dt}from"execa";function ut(e){return e==="biome"?{"*.{ts,tsx,js,jsx,json,css}":["biome check --write"]}:{"*.{ts,tsx,js,jsx}":["eslint --fix"],"*.{ts,tsx,js,jsx,json,css,md}":["prettier --write"]}}var de=`#!/bin/sh
|
|
181
|
+
npx --no-install lint-staged
|
|
182
|
+
`;async function ft(e){let t=A("Initializing Husky...");try{return await dt("npx",["husky","init"],{cwd:e,stdio:"pipe"}),t.succeed("Husky initialized"),!0}catch{return t.fail("Husky init failed \u2014 skipping. You can run `npx husky init` manually later."),!1}}async function ue(e,t){if(!e.features.husky)return;let o=O.join(t,"package.json");if(await D.pathExists(o)){let i=await D.readJson(o);i.devDependencies={...i.devDependencies,husky:r.husky,"lint-staged":r["lint-staged"]},i.scripts={...i.scripts,prepare:"husky"},i["lint-staged"]=ut(e.codeQuality),await D.writeJson(o,i,{spaces:2})}let n=await ft(t),s=O.join(t,".husky","pre-commit");if(n)await c(s,de);else{let i=O.join(t,".husky");await D.ensureDir(i),await c(s,de)}await D.chmod(s,493)}import M from"path";import G from"fs-extra";function gt(e){return`import { defineConfig, devices } from '@playwright/test';
|
|
183
|
+
|
|
184
|
+
export default defineConfig({
|
|
185
|
+
testDir: './tests',
|
|
186
|
+
fullyParallel: true,
|
|
187
|
+
|
|
188
|
+
// Fail the build on CI if you accidentally left test.only in the source code.
|
|
189
|
+
forbidOnly: !!process.env.CI,
|
|
190
|
+
|
|
191
|
+
// Retry on CI only.
|
|
192
|
+
retries: process.env.CI ? 2 : 0,
|
|
193
|
+
|
|
194
|
+
// Single worker on CI for stability; use all available locally.
|
|
195
|
+
workers: process.env.CI ? 1 : undefined,
|
|
196
|
+
|
|
197
|
+
reporter: 'html',
|
|
198
|
+
|
|
199
|
+
use: {
|
|
200
|
+
baseURL: 'http://localhost:3000',
|
|
201
|
+
trace: 'on-first-retry',
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
projects: [
|
|
205
|
+
{
|
|
206
|
+
name: 'chromium',
|
|
207
|
+
use: { ...devices['Desktop Chrome'] },
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
|
|
211
|
+
// Auto-start the dev server before running tests.
|
|
212
|
+
webServer: {
|
|
213
|
+
command: 'pnpm dev --filter=${e}',
|
|
214
|
+
url: 'http://localhost:3000',
|
|
215
|
+
reuseExistingServer: !process.env.CI,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
`}var ht=`import { test, expect } from '@playwright/test';
|
|
219
|
+
|
|
220
|
+
test('homepage has correct title', async ({ page }) => {
|
|
221
|
+
await page.goto('/');
|
|
222
|
+
await expect(page).toHaveTitle(/./);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('homepage renders successfully', async ({ page }) => {
|
|
226
|
+
await page.goto('/');
|
|
227
|
+
|
|
228
|
+
// Verify the page loaded with visible content
|
|
229
|
+
const body = page.locator('body');
|
|
230
|
+
await expect(body).toBeVisible();
|
|
231
|
+
});
|
|
232
|
+
`;async function fe(e,t){if(!e.features.playwright)return;let o=e.apps.filter(i=>i.type==="frontend");if(o.length===0){w.warn("Playwright enabled but no frontend apps found; skipping Playwright setup.");return}let n=o[0].name;await c(M.join(t,"playwright.config.ts"),gt(n)),await c(M.join(t,"tests","example.spec.ts"),ht);let s=M.join(t,"package.json");if(await G.pathExists(s)){let i=await G.readJson(s);i.devDependencies={...i.devDependencies,"@playwright/test":r["@playwright/test"]},i.scripts={...i.scripts,"test:e2e":"playwright test"},await G.writeJson(s,i,{spaces:2})}}import ge from"path";function yt(e){return`name: CI
|
|
233
|
+
|
|
234
|
+
on:
|
|
235
|
+
push:
|
|
236
|
+
branches: ['main']
|
|
237
|
+
pull_request:
|
|
238
|
+
types: [opened, synchronize]
|
|
239
|
+
|
|
240
|
+
jobs:
|
|
241
|
+
ci:
|
|
242
|
+
name: Build and Lint
|
|
243
|
+
timeout-minutes: 15
|
|
244
|
+
runs-on: ubuntu-latest
|
|
245
|
+
|
|
246
|
+
steps:
|
|
247
|
+
- name: Checkout code
|
|
248
|
+
uses: actions/checkout@v4
|
|
249
|
+
with:
|
|
250
|
+
fetch-depth: 2
|
|
251
|
+
|
|
252
|
+
- name: Setup pnpm
|
|
253
|
+
uses: pnpm/action-setup@v4
|
|
254
|
+
with:
|
|
255
|
+
version: 9
|
|
256
|
+
|
|
257
|
+
- name: Setup Node.js
|
|
258
|
+
uses: actions/setup-node@v4
|
|
259
|
+
with:
|
|
260
|
+
node-version: 20
|
|
261
|
+
cache: 'pnpm'
|
|
262
|
+
|
|
263
|
+
- name: Install dependencies
|
|
264
|
+
run: pnpm install --frozen-lockfile
|
|
265
|
+
|
|
266
|
+
- name: Lint
|
|
267
|
+
run: pnpm turbo run lint
|
|
268
|
+
|
|
269
|
+
- name: Build
|
|
270
|
+
run: pnpm turbo run build${e.features.playwright?`
|
|
271
|
+
- name: Install Playwright browsers
|
|
272
|
+
run: pnpm exec playwright install chromium --with-deps
|
|
273
|
+
|
|
274
|
+
- name: Run e2e tests
|
|
275
|
+
run: pnpm test:e2e`:""}
|
|
276
|
+
`}async function he(e,t){if(!e.features.githubActions)return;let o=ge.join(t,".github","workflows");await c(ge.join(o,"ci.yml"),yt(e))}import ye from"path";import{execa as Q}from"execa";var wt=`# Dependencies
|
|
277
|
+
node_modules/
|
|
278
|
+
.pnpm-store/
|
|
279
|
+
|
|
280
|
+
# Build outputs
|
|
281
|
+
dist/
|
|
282
|
+
.next/
|
|
283
|
+
out/
|
|
284
|
+
build/
|
|
285
|
+
|
|
286
|
+
# Environment
|
|
287
|
+
.env*
|
|
288
|
+
!.env.example
|
|
289
|
+
|
|
290
|
+
# IDE
|
|
291
|
+
.vscode/
|
|
292
|
+
.idea/
|
|
293
|
+
*.swp
|
|
294
|
+
*.swo
|
|
295
|
+
|
|
296
|
+
# OS
|
|
297
|
+
.DS_Store
|
|
298
|
+
Thumbs.db
|
|
299
|
+
|
|
300
|
+
# Turbo
|
|
301
|
+
.turbo/
|
|
302
|
+
|
|
303
|
+
# Testing
|
|
304
|
+
coverage/
|
|
305
|
+
playwright-report/
|
|
306
|
+
test-results/
|
|
307
|
+
|
|
308
|
+
# Debug
|
|
309
|
+
npm-debug.log*
|
|
310
|
+
pnpm-debug.log*
|
|
311
|
+
`;function bt(e){let t=e.apps.filter(a=>a.type==="frontend"),o=e.apps.filter(a=>a.type==="backend"),n=e.apps.map(a=>`- **${a.name}** \u2014 ${a.type==="frontend"?"Next.js (frontend)":"Express + TypeScript (backend)"}`).join(`
|
|
312
|
+
`),s=e.apps.map(a=>`pnpm dev --filter=${a.name}`).join(`
|
|
313
|
+
`),i="";e.shadcn.enabled&&(i=`
|
|
314
|
+
## Adding UI Components
|
|
315
|
+
|
|
316
|
+
Run from the project root \u2014 no need to \`cd\`:
|
|
317
|
+
|
|
318
|
+
\`\`\`bash
|
|
319
|
+
# Add a component (button, input, card, etc.)
|
|
320
|
+
pnpm ui:add button
|
|
321
|
+
|
|
322
|
+
# Add a block (login page, dashboard, etc.)
|
|
323
|
+
pnpm ui:add login-01
|
|
324
|
+
\`\`\`
|
|
325
|
+
|
|
326
|
+
Components go to \`packages/ui/src/components/\`.
|
|
327
|
+
Blocks go to \`packages/ui/src/blocks/\`.
|
|
328
|
+
|
|
329
|
+
### Importing
|
|
330
|
+
|
|
331
|
+
\`\`\`tsx
|
|
332
|
+
// Import a component
|
|
333
|
+
import { Button } from '@repo/ui/src/components/button';
|
|
334
|
+
|
|
335
|
+
// Import a block
|
|
336
|
+
import { LoginForm } from '@repo/ui/src/blocks/login-form';
|
|
337
|
+
|
|
338
|
+
// Import a utility
|
|
339
|
+
import { cn } from '@repo/ui/lib/utils';
|
|
340
|
+
\`\`\`
|
|
341
|
+
`);let l="";t.length>0&&(l=`
|
|
342
|
+
## Deployment
|
|
343
|
+
|
|
344
|
+
${t.map(d=>`### ${d.name}
|
|
345
|
+
1. Import your repo on [Vercel](https://vercel.com)
|
|
346
|
+
2. Set **Root Directory** to \`apps/${d.name}\`
|
|
347
|
+
3. Set **Build Command** to \`cd ../.. && pnpm turbo run build --filter=${d.name}\`
|
|
348
|
+
4. Deploy`).join(`
|
|
349
|
+
|
|
350
|
+
`)}
|
|
351
|
+
`);let m="";if(o.length>0){let a=o.map(d=>`### ${d.name}
|
|
352
|
+
1. Build: \`pnpm build --filter=${d.name}\`
|
|
353
|
+
2. Run: \`node apps/${d.name}/dist/index.js\`
|
|
354
|
+
3. Or use Docker / Railway / Fly.io for deployment`).join(`
|
|
355
|
+
|
|
356
|
+
`);m+=`
|
|
357
|
+
${a}
|
|
358
|
+
`}return`# ${e.projectName}
|
|
359
|
+
|
|
360
|
+
A Turborepo monorepo generated with [Monoframe](https://github.com/Abubokkor98/monoframe).
|
|
361
|
+
|
|
362
|
+
## Apps
|
|
363
|
+
|
|
364
|
+
${n}
|
|
365
|
+
|
|
366
|
+
## Getting Started
|
|
367
|
+
|
|
368
|
+
\`\`\`bash
|
|
369
|
+
# Install dependencies
|
|
370
|
+
pnpm install
|
|
371
|
+
|
|
372
|
+
# Run all apps in development
|
|
373
|
+
pnpm dev
|
|
374
|
+
|
|
375
|
+
# Run a specific app
|
|
376
|
+
${s}
|
|
377
|
+
\`\`\`
|
|
378
|
+
|
|
379
|
+
## Commands
|
|
380
|
+
|
|
381
|
+
| Command | Description |
|
|
382
|
+
|---------|-------------|
|
|
383
|
+
| \`pnpm dev\` | Start all apps in development mode |
|
|
384
|
+
| \`pnpm build\` | Build all apps |
|
|
385
|
+
| \`pnpm lint\` | Lint all apps |
|
|
386
|
+
| \`pnpm dev --filter=<app>\` | Start a specific app |
|
|
387
|
+
| \`pnpm ui:add <component>\` | Add a shadcn component or block |
|
|
388
|
+
|
|
389
|
+
## Project Structure
|
|
390
|
+
|
|
391
|
+
\`\`\`
|
|
392
|
+
${e.projectName}/
|
|
393
|
+
\u251C\u2500\u2500 apps/
|
|
394
|
+
${e.apps.map((a,d)=>`\u2502 ${d===e.apps.length-1?"\u2514":"\u251C"}\u2500\u2500 ${a.name}/`).join(`
|
|
395
|
+
`)}
|
|
396
|
+
\u251C\u2500\u2500 packages/
|
|
397
|
+
\u2502 \u251C\u2500\u2500 ui/
|
|
398
|
+
\u2502 \u2502 \u251C\u2500\u2500 src/components/ \u2190 Shared primitives (button, card)
|
|
399
|
+
\u2502 \u2502 \u251C\u2500\u2500 src/blocks/ \u2190 Shared blocks (login, dashboard)
|
|
400
|
+
\u2502 \u2502 \u251C\u2500\u2500 src/providers/ \u2190 Shared providers (motion, scroll)
|
|
401
|
+
\u2502 \u2502 \u2514\u2500\u2500 lib/utils.ts
|
|
402
|
+
\u2502 \u251C\u2500\u2500 config-typescript/ \u2190 Shared TypeScript config
|
|
403
|
+
\u2502 \u2514\u2500\u2500 config-${e.codeQuality==="biome"?"biome":"eslint"}/ \u2190 Shared ${e.codeQuality==="biome"?"Biome":"ESLint"} config
|
|
404
|
+
\u251C\u2500\u2500 turbo.json
|
|
405
|
+
\u251C\u2500\u2500 pnpm-workspace.yaml
|
|
406
|
+
\u2514\u2500\u2500 package.json
|
|
407
|
+
\`\`\`
|
|
408
|
+
${i}${l}${m}
|
|
409
|
+
## License
|
|
410
|
+
|
|
411
|
+
MIT
|
|
412
|
+
`}async function jt(e){let t=A("Initializing git repository...");try{return await Q("git",["init"],{cwd:e,stdio:"pipe"}),await Q("git",["add","-A"],{cwd:e,stdio:"pipe"}),await Q("git",["commit","-m","chore: initial commit from Monoframe"],{cwd:e,stdio:"pipe"}),t.succeed("Git repository initialized"),!0}catch{return t.fail("Git init failed \u2014 you can run `git init` manually."),!1}}async function we(e,t){return await c(ye.join(t,".gitignore"),wt),await c(ye.join(t,"README.md"),bt(e)),await jt(t)}async function be(e){let t=xt.resolve(process.cwd(),e.projectName),o=!N.existsSync(t);if(N.existsSync(t)&&N.readdirSync(t).length>0)throw new Error(`Directory "${e.projectName}" already exists and is not empty. Choose a different project name or remove the directory.`);w.info(`
|
|
413
|
+
Scaffolding project in ${t}...`),await u(t);try{await ie(e,t),await se(e,t),await re(e,t),await ae(e,t),await le(e,t),await me(e,t),await ue(e,t),await fe(e,t),await he(e,t),await we(e,t)}catch(n){throw o&&await N.remove(t),n}w.success(`
|
|
414
|
+
Project generated successfully!`)}function je(e){e instanceof Error?w.error(`
|
|
415
|
+
Error: ${e.message}`):w.error(`
|
|
416
|
+
An unknown error occurred: ${String(e)}`),process.exit(1)}async function xe(e){try{e.resetPreferences&&U()&&w.info("Preferences cleared.");let t;if(e.yes)t=te;else{let o=await W(),n=await Y(),s=await Z(n),i=await ee();t={...o,apps:n,shadcn:s,animations:i.animations,features:i.features}}await be(oe.parse(t)),e.yes||H({codeQuality:t.codeQuality,shadcn:t.shadcn,animations:t.animations,features:t.features})}catch(t){t instanceof b&&(w.warn(`
|
|
417
|
+
Operation cancelled.`),process.exit(0)),je(t)}}var B=new Pt;B.name("monoframe").description("Scaffold production-ready monorepos").version("0.0.0");B.command("init").description("Initialize a new monorepo project").option("-y, --yes","Skip prompts and use default options",!1).option("--reset-preferences","Clear saved preferences and use defaults",!1).action(e=>{xe(e)});B.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "monoframe",
|
|
3
|
+
"version": "0.0.1-beta.0",
|
|
4
|
+
"description": "Scaffold production-ready monorepos",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"monoframe": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"monorepo",
|
|
16
|
+
"turborepo",
|
|
17
|
+
"nextjs",
|
|
18
|
+
"scaffold",
|
|
19
|
+
"cli",
|
|
20
|
+
"generator",
|
|
21
|
+
"typescript",
|
|
22
|
+
"tailwindcss",
|
|
23
|
+
"shadcn",
|
|
24
|
+
"fullstack"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/Abubokkor98/monoframe.git",
|
|
29
|
+
"directory": "packages/cli"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/Abubokkor98/monoframe#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/Abubokkor98/monoframe/issues"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "tsup --watch"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"commander": "^14.0.3",
|
|
40
|
+
"conf": "^15.1.0",
|
|
41
|
+
"execa": "^9.6.1",
|
|
42
|
+
"fast-glob": "^3.3.3",
|
|
43
|
+
"fs-extra": "^11.3.4",
|
|
44
|
+
"ora": "^9.3.0",
|
|
45
|
+
"picocolors": "^1.1.1",
|
|
46
|
+
"prompts": "^2.4.2",
|
|
47
|
+
"zod": "^4.3.6"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
|
|
3
|
+
"organizeImports": {
|
|
4
|
+
"enabled": true
|
|
5
|
+
},
|
|
6
|
+
"linter": {
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"rules": {
|
|
9
|
+
"recommended": true,
|
|
10
|
+
"suspicious": {
|
|
11
|
+
"noExplicitAny": "off",
|
|
12
|
+
"noArrayIndexKey": "off"
|
|
13
|
+
},
|
|
14
|
+
"style": {
|
|
15
|
+
"useImportType": "off"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"formatter": {
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"formatWithErrors": false,
|
|
22
|
+
"indentStyle": "space",
|
|
23
|
+
"indentWidth": 2,
|
|
24
|
+
"lineWidth": 100
|
|
25
|
+
},
|
|
26
|
+
"javascript": {
|
|
27
|
+
"formatter": {
|
|
28
|
+
"quoteStyle": "single",
|
|
29
|
+
"semicolons": "always",
|
|
30
|
+
"trailingCommas": "all"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
|
|
4
|
+
const config = [
|
|
5
|
+
js.configs.recommended,
|
|
6
|
+
...tseslint.configs.recommended,
|
|
7
|
+
{
|
|
8
|
+
ignores: ['node_modules/**', 'dist/**'],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.ts'],
|
|
12
|
+
rules: {
|
|
13
|
+
'no-unused-vars': 'off',
|
|
14
|
+
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export default config;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { dirname } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { FlatCompat } from '@eslint/eslintrc';
|
|
4
|
+
import js from '@eslint/js';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const compat = new FlatCompat({
|
|
10
|
+
baseDirectory: __dirname,
|
|
11
|
+
recommendedConfig: js.configs.recommended,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const config = [
|
|
15
|
+
...compat.extends('next/core-web-vitals', 'prettier'),
|
|
16
|
+
{
|
|
17
|
+
ignores: ['.next/**', 'node_modules/**', 'dist/**'],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
21
|
+
rules: {
|
|
22
|
+
// Customize rules for Next.js apps here
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export default config;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2022",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"lib": ["es2022", "dom", "dom.iterable"],
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"noEmit": true
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"ui": "tui",
|
|
4
|
+
"tasks": {
|
|
5
|
+
"build": {
|
|
6
|
+
"dependsOn": ["^build"],
|
|
7
|
+
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
|
8
|
+
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
|
|
9
|
+
},
|
|
10
|
+
"lint": {
|
|
11
|
+
"dependsOn": ["^lint"]
|
|
12
|
+
},
|
|
13
|
+
"dev": {
|
|
14
|
+
"cache": false,
|
|
15
|
+
"persistent": true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|