create-unmint 1.2.0 → 1.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.
package/dist/index.js CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk4 from "chalk";
5
+ import chalk5 from "chalk";
6
6
  import figlet from "figlet";
7
7
  import gradient from "gradient-string";
8
+ import fs7 from "fs-extra";
9
+ import path7 from "path";
8
10
 
9
11
  // src/commands/init.ts
10
12
  import fs2 from "fs-extra";
@@ -109,6 +111,66 @@ function getDefaultConfig(projectName) {
109
111
  installDeps: true
110
112
  };
111
113
  }
114
+ async function promptAddConfig(hasExistingDocs, customPath) {
115
+ const answers = await inquirer.prompt([
116
+ {
117
+ type: "input",
118
+ name: "docsRoute",
119
+ message: "Add Unmint docs at which route?",
120
+ default: customPath || (hasExistingDocs ? "/documentation" : "/docs"),
121
+ validate: (input) => {
122
+ if (!input.startsWith("/")) return "Route must start with /";
123
+ if (!/^\/[a-z0-9-/]*$/i.test(input)) {
124
+ return "Route can only contain letters, numbers, hyphens, and slashes";
125
+ }
126
+ return true;
127
+ }
128
+ },
129
+ {
130
+ type: "input",
131
+ name: "title",
132
+ message: "Docs title:",
133
+ default: "Documentation"
134
+ },
135
+ {
136
+ type: "input",
137
+ name: "description",
138
+ message: "Docs description:",
139
+ default: "Documentation for your project"
140
+ },
141
+ {
142
+ type: "list",
143
+ name: "accentColor",
144
+ message: "Accent color:",
145
+ choices: accentColors.map((c) => ({
146
+ name: c.name === "Cyan" ? `${c.name} ${chalk.dim("(default)")}` : c.name,
147
+ value: c.value
148
+ })),
149
+ default: "#0891b2"
150
+ },
151
+ {
152
+ type: "input",
153
+ name: "customAccent",
154
+ message: "Custom accent color (hex):",
155
+ when: (answers2) => answers2.accentColor === "custom",
156
+ validate: (input) => {
157
+ if (!/^#[0-9a-f]{6}$/i.test(input)) {
158
+ return "Please enter a valid hex color (e.g., #ff5733)";
159
+ }
160
+ return true;
161
+ }
162
+ }
163
+ ]);
164
+ if (answers.accentColor === "custom" && answers.customAccent) {
165
+ answers.accentColor = answers.customAccent;
166
+ }
167
+ return {
168
+ docsRoute: answers.docsRoute,
169
+ title: answers.title,
170
+ description: answers.description,
171
+ accentColor: answers.accentColor
172
+ };
173
+ }
112
174
 
113
175
  // src/scaffold.ts
114
176
  import fs from "fs-extra";
@@ -488,6 +550,588 @@ async function applyUpdates(projectDir, changes) {
488
550
  return results;
489
551
  }
490
552
 
553
+ // src/commands/add.ts
554
+ import chalk4 from "chalk";
555
+ import ora3 from "ora";
556
+ import path6 from "path";
557
+ import fs6 from "fs-extra";
558
+ import { execa as execa2 } from "execa";
559
+
560
+ // src/utils/detect-project.ts
561
+ import fs4 from "fs-extra";
562
+ import path4 from "path";
563
+ async function detectProject(cwd) {
564
+ const result = {
565
+ isExistingProject: false,
566
+ framework: "unknown",
567
+ useSrcDir: false,
568
+ appDir: "app",
569
+ hasExistingDocs: false,
570
+ hasFumadocs: false,
571
+ packageManager: "npm",
572
+ nextConfigPath: null,
573
+ globalsCssPath: null,
574
+ tailwindConfigPath: null
575
+ };
576
+ const packageJsonPath = path4.join(cwd, "package.json");
577
+ if (!await fs4.pathExists(packageJsonPath)) {
578
+ return result;
579
+ }
580
+ result.isExistingProject = true;
581
+ const nextConfigExtensions = ["js", "ts", "mjs"];
582
+ for (const ext of nextConfigExtensions) {
583
+ const configPath = path4.join(cwd, `next.config.${ext}`);
584
+ if (await fs4.pathExists(configPath)) {
585
+ result.nextConfigPath = configPath;
586
+ break;
587
+ }
588
+ }
589
+ if (!result.nextConfigPath) {
590
+ return result;
591
+ }
592
+ const srcAppPath = path4.join(cwd, "src/app");
593
+ const appPath = path4.join(cwd, "app");
594
+ if (await fs4.pathExists(srcAppPath)) {
595
+ result.useSrcDir = true;
596
+ result.appDir = "src/app";
597
+ result.framework = "next-app";
598
+ } else if (await fs4.pathExists(appPath)) {
599
+ result.useSrcDir = false;
600
+ result.appDir = "app";
601
+ result.framework = "next-app";
602
+ } else {
603
+ const pagesPath = path4.join(cwd, "pages");
604
+ const srcPagesPath = path4.join(cwd, "src/pages");
605
+ if (await fs4.pathExists(pagesPath) || await fs4.pathExists(srcPagesPath)) {
606
+ result.framework = "next-pages";
607
+ }
608
+ return result;
609
+ }
610
+ const docsPath = path4.join(cwd, result.appDir, "docs");
611
+ result.hasExistingDocs = await fs4.pathExists(docsPath);
612
+ try {
613
+ const pkg = await fs4.readJson(packageJsonPath);
614
+ const allDeps = {
615
+ ...pkg.dependencies,
616
+ ...pkg.devDependencies
617
+ };
618
+ result.hasFumadocs = "fumadocs-core" in allDeps || "fumadocs-mdx" in allDeps;
619
+ } catch {
620
+ }
621
+ result.packageManager = await detectPackageManager2(cwd);
622
+ const globalsCssPaths = [
623
+ path4.join(cwd, result.appDir, "globals.css"),
624
+ path4.join(cwd, "src/styles/globals.css"),
625
+ path4.join(cwd, "styles/globals.css")
626
+ ];
627
+ for (const cssPath of globalsCssPaths) {
628
+ if (await fs4.pathExists(cssPath)) {
629
+ result.globalsCssPath = cssPath;
630
+ break;
631
+ }
632
+ }
633
+ const tailwindConfigExtensions = ["ts", "js", "mjs"];
634
+ for (const ext of tailwindConfigExtensions) {
635
+ const configPath = path4.join(cwd, `tailwind.config.${ext}`);
636
+ if (await fs4.pathExists(configPath)) {
637
+ result.tailwindConfigPath = configPath;
638
+ break;
639
+ }
640
+ }
641
+ return result;
642
+ }
643
+ async function detectPackageManager2(cwd) {
644
+ if (await fs4.pathExists(path4.join(cwd, "pnpm-lock.yaml"))) {
645
+ return "pnpm";
646
+ }
647
+ if (await fs4.pathExists(path4.join(cwd, "yarn.lock"))) {
648
+ return "yarn";
649
+ }
650
+ if (await fs4.pathExists(path4.join(cwd, "bun.lockb"))) {
651
+ return "bun";
652
+ }
653
+ const userAgent = process.env.npm_config_user_agent || "";
654
+ if (userAgent.includes("pnpm")) return "pnpm";
655
+ if (userAgent.includes("yarn")) return "yarn";
656
+ if (userAgent.includes("bun")) return "bun";
657
+ return "npm";
658
+ }
659
+ function validateProjectForAdd(info) {
660
+ if (!info.isExistingProject) {
661
+ return {
662
+ valid: false,
663
+ error: 'No package.json found. Use "npx create-unmint my-docs" to create a new project.'
664
+ };
665
+ }
666
+ if (!info.nextConfigPath) {
667
+ return {
668
+ valid: false,
669
+ error: "No Next.js config found. This directory does not appear to be a Next.js project."
670
+ };
671
+ }
672
+ if (info.framework === "next-pages") {
673
+ return {
674
+ valid: false,
675
+ error: "Unmint requires App Router. Your project appears to use Pages Router."
676
+ };
677
+ }
678
+ if (info.framework === "unknown") {
679
+ return {
680
+ valid: false,
681
+ error: "Could not detect app directory. Make sure your project uses the Next.js App Router."
682
+ };
683
+ }
684
+ return { valid: true };
685
+ }
686
+
687
+ // src/utils/merge.ts
688
+ import fs5 from "fs-extra";
689
+ import path5 from "path";
690
+ var UNMINT_DEPENDENCIES = {
691
+ "fumadocs-core": "^16.4.7",
692
+ "fumadocs-mdx": "^14.2.5"
693
+ };
694
+ async function mergeDependencies(packageJsonPath, depsToAdd = UNMINT_DEPENDENCIES) {
695
+ const pkg = await fs5.readJson(packageJsonPath);
696
+ const added = [];
697
+ const skipped = [];
698
+ pkg.dependencies = pkg.dependencies || {};
699
+ for (const [name, version] of Object.entries(depsToAdd)) {
700
+ if (pkg.dependencies[name] || pkg.devDependencies?.[name]) {
701
+ skipped.push(name);
702
+ } else {
703
+ pkg.dependencies[name] = version;
704
+ added.push(name);
705
+ }
706
+ }
707
+ pkg.dependencies = Object.fromEntries(
708
+ Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))
709
+ );
710
+ await fs5.writeJson(packageJsonPath, pkg, { spaces: 2 });
711
+ return { added, skipped };
712
+ }
713
+ function getUnmintCssVariables(accentColor, darkAccentColor) {
714
+ return `
715
+ /* Unmint Docs - Scoped accent colors */
716
+ .unmint-docs {
717
+ --accent: ${accentColor};
718
+ --accent-foreground: #ffffff;
719
+ --accent-muted: ${hexToRgba(accentColor, 0.1)};
720
+ }
721
+
722
+ .dark .unmint-docs {
723
+ --accent: ${darkAccentColor};
724
+ --accent-foreground: #0f172a;
725
+ --accent-muted: ${hexToRgba(darkAccentColor, 0.1)};
726
+ }
727
+
728
+ /* Syntax highlighting - Shiki integration for docs */
729
+ .unmint-docs pre code span {
730
+ color: var(--shiki-light);
731
+ }
732
+
733
+ .dark .unmint-docs pre code span {
734
+ color: var(--shiki-dark);
735
+ }
736
+ `;
737
+ }
738
+ async function mergeGlobalsCss(globalsCssPath, accentColor, darkAccentColor) {
739
+ const existing = await fs5.readFile(globalsCssPath, "utf-8");
740
+ if (existing.includes(".unmint-docs")) {
741
+ return false;
742
+ }
743
+ const cssToAdd = getUnmintCssVariables(accentColor, darkAccentColor);
744
+ await fs5.appendFile(globalsCssPath, cssToAdd);
745
+ return true;
746
+ }
747
+ async function wrapNextConfig(nextConfigPath) {
748
+ const existing = await fs5.readFile(nextConfigPath, "utf-8");
749
+ if (existing.includes("fumadocs-mdx") || existing.includes("createMDX")) {
750
+ return false;
751
+ }
752
+ const ext = path5.extname(nextConfigPath);
753
+ let modified;
754
+ if (ext === ".ts") {
755
+ modified = wrapTypescriptConfig(existing);
756
+ } else {
757
+ modified = wrapJavascriptConfig(existing);
758
+ }
759
+ await fs5.writeFile(nextConfigPath, modified);
760
+ return true;
761
+ }
762
+ function wrapTypescriptConfig(existing) {
763
+ const importLine = "import { createMDX } from 'fumadocs-mdx/next'\n";
764
+ const exportMatch = existing.match(/export\s+default\s+(\w+)/);
765
+ if (exportMatch) {
766
+ const configName = exportMatch[1];
767
+ let modified = importLine + existing;
768
+ modified = modified.replace(
769
+ /export\s+default\s+\w+/,
770
+ `const withMDX = createMDX()
771
+
772
+ export default withMDX(${configName})`
773
+ );
774
+ return modified;
775
+ }
776
+ if (existing.includes("export default {")) {
777
+ let modified = importLine + existing.replace(
778
+ "export default {",
779
+ "const nextConfig = {"
780
+ );
781
+ modified = modified.trimEnd() + "\n\nconst withMDX = createMDX()\n\nexport default withMDX(nextConfig)\n";
782
+ return modified;
783
+ }
784
+ return importLine + existing;
785
+ }
786
+ function wrapJavascriptConfig(existing) {
787
+ const isESM = existing.includes("export default") || existing.includes("import ");
788
+ if (isESM) {
789
+ const importLine = "import { createMDX } from 'fumadocs-mdx/next'\n";
790
+ const exportMatch = existing.match(/export\s+default\s+(\w+)/);
791
+ if (exportMatch) {
792
+ const configName = exportMatch[1];
793
+ let modified = importLine + existing;
794
+ modified = modified.replace(
795
+ /export\s+default\s+\w+/,
796
+ `const withMDX = createMDX()
797
+
798
+ export default withMDX(${configName})`
799
+ );
800
+ return modified;
801
+ }
802
+ if (existing.includes("export default {")) {
803
+ let modified = importLine + existing.replace(
804
+ "export default {",
805
+ "const nextConfig = {"
806
+ );
807
+ modified = modified.trimEnd() + "\n\nconst withMDX = createMDX()\n\nexport default withMDX(nextConfig)\n";
808
+ return modified;
809
+ }
810
+ return importLine + existing;
811
+ }
812
+ const requireLine = "const { createMDX } = require('fumadocs-mdx/next')\n";
813
+ if (existing.includes("module.exports")) {
814
+ let modified = requireLine + existing.replace(
815
+ /module\.exports\s*=\s*(\w+)/,
816
+ (_, configName) => `const withMDX = createMDX()
817
+
818
+ module.exports = withMDX(${configName})`
819
+ );
820
+ return modified;
821
+ }
822
+ return requireLine + existing;
823
+ }
824
+ function hexToRgba(hex, alpha) {
825
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
826
+ if (!result) return `rgba(0, 0, 0, ${alpha})`;
827
+ const r = parseInt(result[1], 16);
828
+ const g = parseInt(result[2], 16);
829
+ const b = parseInt(result[3], 16);
830
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
831
+ }
832
+ function lightenColor2(hex, percent = 30) {
833
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
834
+ if (!result) return hex;
835
+ let r = parseInt(result[1], 16);
836
+ let g = parseInt(result[2], 16);
837
+ let b = parseInt(result[3], 16);
838
+ r = Math.min(255, Math.floor(r + (255 - r) * (percent / 100)));
839
+ g = Math.min(255, Math.floor(g + (255 - g) * (percent / 100)));
840
+ b = Math.min(255, Math.floor(b + (255 - b) * (percent / 100)));
841
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
842
+ }
843
+ async function createSourceConfig(targetDir) {
844
+ const sourceConfigPath = path5.join(targetDir, "source.config.ts");
845
+ if (await fs5.pathExists(sourceConfigPath)) {
846
+ return;
847
+ }
848
+ const content = `import { defineConfig, defineDocs } from 'fumadocs-mdx/config'
849
+ import { rehypeCode } from 'fumadocs-core/mdx-plugins'
850
+
851
+ export const docs = defineDocs({
852
+ dir: 'content/docs',
853
+ })
854
+
855
+ export default defineConfig({
856
+ mdxOptions: {
857
+ rehypePlugins: [
858
+ [
859
+ rehypeCode,
860
+ {
861
+ themes: {
862
+ light: 'github-light',
863
+ dark: 'github-dark',
864
+ },
865
+ },
866
+ ],
867
+ ],
868
+ },
869
+ })
870
+ `;
871
+ await fs5.writeFile(sourceConfigPath, content);
872
+ }
873
+ async function createMdxComponents(targetDir, appDir) {
874
+ const mdxComponentsPath = path5.join(targetDir, "mdx-components.tsx");
875
+ if (await fs5.pathExists(mdxComponentsPath)) {
876
+ return;
877
+ }
878
+ const componentsPath = appDir.includes("src") ? "@/app/components/docs/mdx" : "@/app/components/docs/mdx";
879
+ const content = `import type { MDXComponents } from 'mdx/types'
880
+ import defaultComponents from 'fumadocs-ui/mdx'
881
+ import { Accordion } from '${componentsPath}/accordion'
882
+ import { Callout, Note, Tip, Warning, Info } from '${componentsPath}/callout'
883
+ import { Card, CardGroup } from '${componentsPath}/card'
884
+ import { CodeBlock } from '${componentsPath}/code-block'
885
+ import { Frame } from '${componentsPath}/frame'
886
+ import { Steps, Step } from '${componentsPath}/steps'
887
+ import { Tab, Tabs } from '${componentsPath}/tabs'
888
+
889
+ export function useMDXComponents(components: MDXComponents): MDXComponents {
890
+ return {
891
+ ...defaultComponents,
892
+ ...components,
893
+ Accordion,
894
+ Callout,
895
+ Note,
896
+ Tip,
897
+ Warning,
898
+ Info,
899
+ Card,
900
+ CardGroup,
901
+ CodeBlock,
902
+ Frame,
903
+ Steps,
904
+ Step,
905
+ Tab,
906
+ Tabs,
907
+ }
908
+ }
909
+ `;
910
+ await fs5.writeFile(mdxComponentsPath, content);
911
+ }
912
+
913
+ // src/commands/add.ts
914
+ async function add(options = {}) {
915
+ const cwd = process.cwd();
916
+ const spinner = ora3("Detecting project...").start();
917
+ const projectInfo = await detectProject(cwd);
918
+ const validation = validateProjectForAdd(projectInfo);
919
+ if (!validation.valid) {
920
+ spinner.fail(validation.error);
921
+ process.exit(1);
922
+ }
923
+ spinner.succeed(`Detected Next.js project (App Router)`);
924
+ console.log(chalk4.dim(` Using ${projectInfo.useSrcDir ? "src/app" : "app"} directory structure`));
925
+ console.log();
926
+ if (projectInfo.hasExistingDocs && !options.path) {
927
+ console.log(chalk4.yellow("\u26A0 A /docs route already exists in this project."));
928
+ console.log(chalk4.dim(" Use --path to specify a different route (e.g., --path /documentation)"));
929
+ console.log();
930
+ }
931
+ const config = options.yes ? getDefaultAddConfig(options.path) : await promptAddConfig(projectInfo.hasExistingDocs, options.path);
932
+ const docsRoutePath = path6.join(cwd, projectInfo.appDir, config.docsRoute.replace(/^\//, ""));
933
+ if (await fs6.pathExists(docsRoutePath)) {
934
+ console.log(chalk4.red(`
935
+ \u2716 The route ${config.docsRoute} already exists at ${docsRoutePath}`));
936
+ console.log(chalk4.dim(" Choose a different route or manually merge the directories."));
937
+ process.exit(1);
938
+ }
939
+ console.log();
940
+ console.log(chalk4.cyan(" Adding Unmint to your project..."));
941
+ console.log();
942
+ await copyDocsFiles(cwd, projectInfo, config);
943
+ await mergeConfigurations(cwd, projectInfo, config);
944
+ await installDependencies(cwd, projectInfo.packageManager);
945
+ printSuccessMessage(config, projectInfo.packageManager);
946
+ }
947
+ function getDefaultAddConfig(customPath) {
948
+ return {
949
+ docsRoute: customPath || "/docs",
950
+ title: "Documentation",
951
+ description: "Documentation for your project",
952
+ accentColor: "#0891b2"
953
+ };
954
+ }
955
+ async function copyDocsFiles(cwd, projectInfo, config) {
956
+ const spinner = ora3("Copying docs files...").start();
957
+ const templateDir = await resolveTemplateDir();
958
+ const appDir = projectInfo.appDir;
959
+ const routeName = config.docsRoute.replace(/^\//, "");
960
+ const libDir = projectInfo.useSrcDir ? "src/lib" : "lib";
961
+ const copyOperations = [
962
+ // Docs route
963
+ {
964
+ from: path6.join(templateDir, "app/docs"),
965
+ to: path6.join(cwd, appDir, routeName)
966
+ },
967
+ // Docs components
968
+ {
969
+ from: path6.join(templateDir, "app/components/docs"),
970
+ to: path6.join(cwd, appDir, "components/docs")
971
+ },
972
+ // Providers (theme provider)
973
+ {
974
+ from: path6.join(templateDir, "app/providers"),
975
+ to: path6.join(cwd, appDir, "providers")
976
+ },
977
+ // API routes
978
+ {
979
+ from: path6.join(templateDir, "app/api/search"),
980
+ to: path6.join(cwd, appDir, "api/search")
981
+ },
982
+ {
983
+ from: path6.join(templateDir, "app/api/og"),
984
+ to: path6.join(cwd, appDir, "api/og")
985
+ },
986
+ // Content (always at root)
987
+ {
988
+ from: path6.join(templateDir, "content/docs"),
989
+ to: path6.join(cwd, "content/docs")
990
+ },
991
+ // Lib files (in src/lib if using src directory)
992
+ {
993
+ from: path6.join(templateDir, "lib/docs-source.ts"),
994
+ to: path6.join(cwd, libDir, "docs-source.ts")
995
+ },
996
+ {
997
+ from: path6.join(templateDir, "lib/theme-config.ts"),
998
+ to: path6.join(cwd, libDir, "unmint-config.ts")
999
+ },
1000
+ // Logo files (copy to public directory if not present)
1001
+ {
1002
+ from: path6.join(templateDir, "public/logo.svg"),
1003
+ to: path6.join(cwd, "public/logo.svg")
1004
+ },
1005
+ {
1006
+ from: path6.join(templateDir, "public/logo.png"),
1007
+ to: path6.join(cwd, "public/logo.png")
1008
+ }
1009
+ ];
1010
+ await fs6.ensureDir(path6.join(cwd, "public"));
1011
+ await fs6.ensureDir(path6.join(cwd, libDir));
1012
+ for (const op of copyOperations) {
1013
+ if (await fs6.pathExists(op.from)) {
1014
+ await fs6.copy(op.from, op.to, { overwrite: false });
1015
+ }
1016
+ }
1017
+ const utilsPath = path6.join(cwd, libDir, "utils.ts");
1018
+ if (!await fs6.pathExists(utilsPath)) {
1019
+ await fs6.copy(
1020
+ path6.join(templateDir, "lib/utils.ts"),
1021
+ utilsPath
1022
+ );
1023
+ }
1024
+ if (projectInfo.useSrcDir) {
1025
+ const docsSourcePath = path6.join(cwd, libDir, "docs-source.ts");
1026
+ if (await fs6.pathExists(docsSourcePath)) {
1027
+ let content = await fs6.readFile(docsSourcePath, "utf-8");
1028
+ content = content.replace(
1029
+ /from ['"]\.\.\/\.source\/server['"]/,
1030
+ "from '../../.source/server'"
1031
+ );
1032
+ await fs6.writeFile(docsSourcePath, content);
1033
+ }
1034
+ }
1035
+ await updateDocsImports(cwd, appDir, routeName);
1036
+ await updateThemeConfig(cwd, config);
1037
+ spinner.succeed(`Added ${appDir}/${routeName}/ route with layout`);
1038
+ ora3().succeed(`Added docs components to ${appDir}/components/docs/`);
1039
+ ora3().succeed("Added content/docs/ directory with sample content");
1040
+ }
1041
+ async function resolveTemplateDir() {
1042
+ const bundledPath = path6.join(import.meta.dirname, "../../template");
1043
+ if (await fs6.pathExists(bundledPath)) {
1044
+ return bundledPath;
1045
+ }
1046
+ const devPath = path6.join(import.meta.dirname, "../../../template");
1047
+ if (await fs6.pathExists(devPath)) {
1048
+ return devPath;
1049
+ }
1050
+ throw new Error("Could not find template directory");
1051
+ }
1052
+ async function updateDocsImports(cwd, appDir, routeName) {
1053
+ const filesToUpdate = [
1054
+ path6.join(cwd, appDir, routeName, "layout.tsx"),
1055
+ path6.join(cwd, appDir, routeName, "[[...slug]]", "page.tsx"),
1056
+ path6.join(cwd, appDir, "components/docs/docs-sidebar.tsx"),
1057
+ path6.join(cwd, appDir, "components/docs/docs-header.tsx"),
1058
+ path6.join(cwd, appDir, "components/docs/mobile-sidebar.tsx"),
1059
+ path6.join(cwd, appDir, "components/docs/search-dialog.tsx"),
1060
+ path6.join(cwd, appDir, "api/og/route.tsx")
1061
+ ];
1062
+ for (const filePath of filesToUpdate) {
1063
+ if (await fs6.pathExists(filePath)) {
1064
+ let content = await fs6.readFile(filePath, "utf-8");
1065
+ if (content.includes("@/lib/theme-config")) {
1066
+ content = content.replace(
1067
+ /@\/lib\/theme-config/g,
1068
+ "@/lib/unmint-config"
1069
+ );
1070
+ await fs6.writeFile(filePath, content);
1071
+ }
1072
+ }
1073
+ }
1074
+ }
1075
+ async function updateThemeConfig(cwd, config) {
1076
+ const configPath = path6.join(cwd, "lib/unmint-config.ts");
1077
+ if (!await fs6.pathExists(configPath)) return;
1078
+ let content = await fs6.readFile(configPath, "utf-8");
1079
+ content = content.replace(
1080
+ /name:\s*['"][^'"]*['"]/,
1081
+ `name: '${config.title}'`
1082
+ );
1083
+ content = content.replace(
1084
+ /description:\s*['"][^'"]*['"]/,
1085
+ `description: '${config.description}'`
1086
+ );
1087
+ await fs6.writeFile(configPath, content);
1088
+ }
1089
+ async function mergeConfigurations(cwd, projectInfo, config) {
1090
+ const packageJsonPath = path6.join(cwd, "package.json");
1091
+ const { added } = await mergeDependencies(packageJsonPath);
1092
+ if (added.length > 0) {
1093
+ ora3().succeed(`Merged ${added.length} dependencies into package.json`);
1094
+ }
1095
+ if (projectInfo.globalsCssPath) {
1096
+ const darkAccent = lightenColor2(config.accentColor, 30);
1097
+ const merged = await mergeGlobalsCss(projectInfo.globalsCssPath, config.accentColor, darkAccent);
1098
+ if (merged) {
1099
+ ora3().succeed("Added CSS variables to globals.css");
1100
+ }
1101
+ }
1102
+ if (projectInfo.nextConfigPath) {
1103
+ const wrapped = await wrapNextConfig(projectInfo.nextConfigPath);
1104
+ if (wrapped) {
1105
+ ora3().succeed("Updated next.config for MDX support");
1106
+ }
1107
+ }
1108
+ await createSourceConfig(cwd);
1109
+ ora3().succeed("Created source.config.ts");
1110
+ await createMdxComponents(cwd, projectInfo.appDir);
1111
+ ora3().succeed("Created mdx-components.tsx");
1112
+ }
1113
+ async function installDependencies(cwd, packageManager) {
1114
+ const spinner = ora3("Installing dependencies...").start();
1115
+ try {
1116
+ const installCmd = packageManager === "npm" ? "install" : "install";
1117
+ await execa2(packageManager, [installCmd], { cwd, stdio: "pipe" });
1118
+ spinner.succeed(`Installed ${Object.keys(UNMINT_DEPENDENCIES).join(", ")}`);
1119
+ } catch (error) {
1120
+ spinner.warn("Could not install dependencies automatically");
1121
+ console.log(chalk4.dim(` Run "${packageManager} install" manually`));
1122
+ }
1123
+ }
1124
+ function printSuccessMessage(config, packageManager) {
1125
+ console.log();
1126
+ console.log(chalk4.green(" Success! Unmint docs added to your project."));
1127
+ console.log();
1128
+ console.log(" Next steps:");
1129
+ console.log(chalk4.cyan(` ${packageManager} run dev`));
1130
+ console.log();
1131
+ console.log(` Your docs will be at ${chalk4.cyan(`http://localhost:3000${config.docsRoute}`)}`);
1132
+ console.log();
1133
+ }
1134
+
491
1135
  // src/index.ts
492
1136
  var cyanGradient = gradient([
493
1137
  "#065f5f",
@@ -508,17 +1152,31 @@ function printBanner() {
508
1152
  });
509
1153
  console.log();
510
1154
  console.log(cyanGradient.multiline(banner));
511
- console.log(chalk4.dim(" Beautiful documentation, open source"));
1155
+ console.log(chalk5.dim(" Beautiful documentation, open source"));
512
1156
  console.log();
513
1157
  }
514
1158
  var program = new Command();
515
- program.name("create-unmint").description("Create and manage Unmint documentation projects").version("1.0.0");
516
- program.argument("[project-name]", "Name of the project to create").option("-y, --yes", "Skip prompts and use defaults").option("--update", "Update an existing Unmint project").option("--dry-run", "Show what would be updated without making changes").action(async (projectName, options) => {
1159
+ program.name("create-unmint").description("Create and manage Unmint documentation projects").version("1.2.0");
1160
+ program.argument("[project-name]", 'Name of the project to create (use "." for current directory)').option("-y, --yes", "Skip prompts and use defaults").option("--add", "Add Unmint docs to an existing Next.js project").option("--path <route>", "Custom route path for docs (e.g., /documentation)").option("--update", "Update an existing Unmint project").option("--dry-run", "Show what would be updated without making changes").action(async (projectName, options) => {
517
1161
  printBanner();
518
1162
  if (options.update) {
519
1163
  await update(options);
520
- } else {
521
- await init(projectName, options);
1164
+ return;
1165
+ }
1166
+ if (options.add) {
1167
+ await add({ yes: options.yes, path: options.path });
1168
+ return;
1169
+ }
1170
+ if (projectName === ".") {
1171
+ const cwd = process.cwd();
1172
+ const hasNextConfig = await fs7.pathExists(path7.join(cwd, "next.config.ts")) || await fs7.pathExists(path7.join(cwd, "next.config.js")) || await fs7.pathExists(path7.join(cwd, "next.config.mjs"));
1173
+ if (hasNextConfig) {
1174
+ console.log(chalk5.dim(" Detected existing Next.js project, using add mode..."));
1175
+ console.log();
1176
+ await add({ yes: options.yes, path: options.path });
1177
+ return;
1178
+ }
522
1179
  }
1180
+ await init(projectName, options);
523
1181
  });
524
1182
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-unmint",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Create a new Unmint documentation project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@ export const siteConfig = {
13
13
 
14
14
  // Logo configuration
15
15
  logo: {
16
- src: '/logo.png',
16
+ src: '/logo.svg',
17
17
  alt: 'Unmint',
18
18
  width: 40,
19
19
  height: 40,