gradient-forge 1.0.1 → 1.0.2

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 (2) hide show
  1. package/cli/index.mjs +98 -50
  2. package/package.json +1 -1
package/cli/index.mjs CHANGED
@@ -567,6 +567,7 @@ const promptSelect = async (title, items, defaultIndex = 0) => {
567
567
  }
568
568
 
569
569
  let index = defaultIndex;
570
+ let buffer = "";
570
571
 
571
572
  const render = () => {
572
573
  process.stdout.write("\x1b[2J\x1b[H");
@@ -581,27 +582,35 @@ const promptSelect = async (title, items, defaultIndex = 0) => {
581
582
  };
582
583
 
583
584
  const onKey = (data) => {
584
- const key = data.toString();
585
- if (key === "\u0003") {
586
- process.stdin.setRawMode(false);
587
- process.stdin.pause();
588
- process.exit(1);
589
- }
590
- if (key === "\r") {
585
+ buffer += data.toString();
586
+
587
+ // Handle escape sequences for arrow keys
588
+ if (buffer.includes("\u001b[A")) {
589
+ // Up arrow
590
+ index = index > 0 ? index - 1 : items.length - 1;
591
+ buffer = "";
592
+ render();
593
+ } else if (buffer.includes("\u001b[B")) {
594
+ // Down arrow
595
+ index = index < items.length - 1 ? index + 1 : 0;
596
+ buffer = "";
597
+ render();
598
+ } else if (buffer.includes("\r") || buffer.includes("\n")) {
599
+ // Enter key
591
600
  process.stdin.setRawMode(false);
592
601
  process.stdin.pause();
593
602
  process.stdin.removeListener("data", onKey);
594
603
  process.stdout.write("\x1b[?25h");
595
604
  resolve(items[index]);
596
605
  return;
597
- }
598
- if (key === "\u001b[A") {
599
- index = index > 0 ? index - 1 : items.length - 1;
600
- render();
601
- }
602
- if (key === "\u001b[B") {
603
- index = index < items.length - 1 ? index + 1 : 0;
604
- render();
606
+ } else if (buffer.includes("\u0003")) {
607
+ // Ctrl+C
608
+ process.stdin.setRawMode(false);
609
+ process.stdin.pause();
610
+ process.exit(1);
611
+ } else {
612
+ // Clear buffer after processing
613
+ buffer = "";
605
614
  }
606
615
  };
607
616
 
@@ -750,40 +759,73 @@ const generateSetupInstructions = (projectRoot, themeId, mode, themeLabel) => {
750
759
  Theme: ${themeLabel}
751
760
  Mode: ${mode}
752
761
 
753
- ## Quick Setup (Done!)
754
-
755
- ✅ Already configured:
756
- - app/gradient-forge.css - Theme CSS
757
- - components/theme/theme-context.tsx - Theme provider + ThemeSwitcher component
758
- - components/theme/theme-engine.ts - Theme definitions
759
- - app/globals.css - Theme imported
762
+ All files created automatically!
763
+ ✅ Theme applied!
760
764
 
761
- ## Add to your app:
762
-
763
- 1. Wrap your app with ThemeProvider in layout.tsx:
764
- import { ThemeProvider } from "./components/theme/theme-context";
765
-
766
- export default function RootLayout({ children }) {
767
- return (
768
- <html lang="en" className="${mode} ${themeId}" data-theme="${themeId}" data-color-mode="${mode}">
769
- <body>
770
- <ThemeProvider>{children}</ThemeProvider>
771
- </body>
772
- </html>
773
- );
774
- }
775
-
776
- 2. Add the theme switcher anywhere in your app:
777
- import { ThemeSwitcher } from "./components/theme/theme-context";
778
-
779
- // Add <ThemeSwitcher /> anywhere to let users change themes!
780
-
781
- ## Done! 🎉 Your app now has gradient themes!
765
+ Your app now has beautiful gradient themes! 🎉
782
766
 
783
767
  For more themes, visit: https://gradient-forge.vercel.app
784
768
  `;
785
769
  };
786
770
 
771
+ const autoInjectLayout = (projectRoot, themeId, mode) => {
772
+ const layoutPaths = [
773
+ path.join(projectRoot, "app", "layout.tsx"),
774
+ path.join(projectRoot, "src", "app", "layout.tsx"),
775
+ ];
776
+
777
+ for (const layoutPath of layoutPaths) {
778
+ if (fs.existsSync(layoutPath)) {
779
+ let content = fs.readFileSync(layoutPath, "utf8");
780
+
781
+ // Check if already has ThemeProvider
782
+ if (content.includes("ThemeProvider")) {
783
+ return { success: true, path: layoutPath, message: "Already configured" };
784
+ }
785
+
786
+ // Add import - insert after the first import or at the start
787
+ const importStatement = `import { ThemeProvider } from "./components/theme/theme-context";`;
788
+
789
+ // Find position after the last import line
790
+ const lines = content.split('\n');
791
+ let insertIndex = 0;
792
+ for (let i = 0; i < lines.length; i++) {
793
+ if (lines[i].trim().startsWith('import ') && !lines[i].includes('from "') && !lines[i].includes("from '")) {
794
+ continue;
795
+ }
796
+ if (lines[i].trim().startsWith('import ')) {
797
+ insertIndex = i + 1;
798
+ }
799
+ }
800
+
801
+ // Insert the import
802
+ if (insertIndex > 0 && lines[insertIndex - 1].trim() !== '') {
803
+ lines.splice(insertIndex, 0, importStatement);
804
+ } else {
805
+ lines.splice(insertIndex, 0, importStatement);
806
+ }
807
+ content = lines.join('\n');
808
+
809
+ // Wrap body content with ThemeProvider
810
+ content = content.replace(
811
+ /(<body[^>]*>)([\s\S]*)(<\/body>)/,
812
+ '$1<ThemeProvider>$2</ThemeProvider>$3'
813
+ );
814
+
815
+ // Add theme classes to html tag - use className for JSX
816
+ content = content.replace(
817
+ /<html[^>]*>/,
818
+ `<html lang="en" className="${mode} ${themeId}" data-theme="${themeId}" data-color-mode="${mode}">`
819
+ );
820
+
821
+ fs.writeFileSync(layoutPath, content);
822
+ return { success: true, path: layoutPath };
823
+ }
824
+ }
825
+
826
+ return { success: false, message: "No layout.tsx found" };
827
+ };
828
+
787
829
  const init = async () => {
788
830
  log("");
789
831
  log("🎨 Gradient Forge CLI - Initialize Theme");
@@ -863,17 +905,23 @@ const init = async () => {
863
905
  }
864
906
  }
865
907
 
866
- // Generate setup instructions
867
- const instructions = generateSetupInstructions(projectRoot, themeId, mode, selectedTheme.label);
868
- const readmePath = path.join(projectRoot, "GRADIENT_FORGE_SETUP.md");
869
- fs.writeFileSync(readmePath, instructions);
870
- logSuccess(`Created setup guide: ${path.relative(projectRoot, readmePath)}`);
871
-
908
+ // Auto-inject into layout.tsx
909
+ const layoutResult = autoInjectLayout(projectRoot, themeId, mode);
910
+ if (layoutResult.success) {
911
+ logSuccess(`Updated layout: ${path.relative(projectRoot, layoutResult.path)}`);
912
+ } else {
913
+ logInfo("Note: Could not auto-detect layout.tsx");
914
+ }
915
+
872
916
  log("");
873
917
  log("======================================");
874
918
  logSuccess("Theme setup complete! 🎉");
875
919
  log("");
876
- log(instructions);
920
+ log(`Theme: ${selectedTheme.label} (${mode})`);
921
+ log("");
922
+ log("Your app now has beautiful gradient themes!");
923
+ log("Run: npm run dev");
924
+ log("");
877
925
  };
878
926
 
879
927
  const exportCommand = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gradient-forge",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A production-ready gradient theming framework for shadcn/ui with CLI support",
5
5
  "type": "module",
6
6
  "bin": {