xertica-ui 2.0.0 → 2.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.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/bin/cli.ts +472 -285
- package/components/assistant/index.ts +1 -0
- package/dist/assistant.cjs.js +136 -0
- package/dist/assistant.es.js +137 -1
- package/dist/cli.js +256 -91
- package/dist/components/assistant/index.d.ts +1 -0
- package/dist/utils/demo-responses.d.ts +3 -0
- package/package.json +1 -1
- package/templates/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -528,7 +528,7 @@ var generateTokensCss = (theme) => {
|
|
|
528
528
|
var __filename = fileURLToPath(import.meta.url);
|
|
529
529
|
var __dirname = path.dirname(__filename);
|
|
530
530
|
var program = new Command();
|
|
531
|
-
program.name("xertica-ui").description("CLI to initialize Xertica UI projects").version("
|
|
531
|
+
program.name("xertica-ui").description("CLI to initialize Xertica UI projects").version("2.0.2");
|
|
532
532
|
program.command("init").description("Initialize a new Xertica UI project").argument("[directory]", "Directory to initialize in", ".").action(async (directory) => {
|
|
533
533
|
const targetDir = path.resolve(process.cwd(), directory);
|
|
534
534
|
const templatesDir = path.resolve(__dirname, "../templates");
|
|
@@ -583,9 +583,8 @@ program.command("init").description("Initialize a new Xertica UI project").argum
|
|
|
583
583
|
];
|
|
584
584
|
for (const file of rootFilesToCopy) {
|
|
585
585
|
const srcPath = path.join(templatesDir, file);
|
|
586
|
-
const destPath = path.join(targetDir, file);
|
|
587
586
|
if (await fs.pathExists(srcPath)) {
|
|
588
|
-
await fs.copy(srcPath,
|
|
587
|
+
await fs.copy(srcPath, path.join(targetDir, file));
|
|
589
588
|
}
|
|
590
589
|
}
|
|
591
590
|
const pkgTemplatePath = path.join(templatesDir, "package.json");
|
|
@@ -595,86 +594,136 @@ program.command("init").description("Initialize a new Xertica UI project").argum
|
|
|
595
594
|
pkgContent.name = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
596
595
|
await fs.writeJson(path.join(targetDir, "package.json"), pkgContent, { spaces: 2 });
|
|
597
596
|
}
|
|
597
|
+
await fs.copy(
|
|
598
|
+
path.join(templatesDir, "src", "main.tsx"),
|
|
599
|
+
path.join(targetDir, "src", "main.tsx")
|
|
600
|
+
);
|
|
598
601
|
await fs.ensureDir(path.join(targetDir, "src", "app"));
|
|
599
602
|
await fs.copy(
|
|
600
603
|
path.join(templatesDir, "src", "app", "App.tsx"),
|
|
601
604
|
path.join(targetDir, "src", "app", "App.tsx")
|
|
602
605
|
);
|
|
606
|
+
await fs.ensureDir(path.join(targetDir, "src", "app", "components"));
|
|
603
607
|
await fs.copy(
|
|
604
|
-
path.join(templatesDir, "src", "
|
|
605
|
-
path.join(targetDir, "src", "
|
|
608
|
+
path.join(templatesDir, "src", "app", "components", "AppLayout.tsx"),
|
|
609
|
+
path.join(targetDir, "src", "app", "components", "AppLayout.tsx")
|
|
606
610
|
);
|
|
607
611
|
await fs.copy(
|
|
608
|
-
path.join(templatesDir, "src", "
|
|
609
|
-
path.join(targetDir, "src", "
|
|
612
|
+
path.join(templatesDir, "src", "shared"),
|
|
613
|
+
path.join(targetDir, "src", "shared")
|
|
610
614
|
);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
reset: { file: "ResetPasswordPage.tsx", dir: "ResetPassword", shouldCopy: hasLogin },
|
|
617
|
-
home: { file: "HomePage.tsx", dir: "Home", shouldCopy: hasHome },
|
|
618
|
-
template: { file: "TemplatePage.tsx", dir: "Template", shouldCopy: hasTemplate }
|
|
619
|
-
};
|
|
620
|
-
const srcPagesDir = path.join(templatesDir, "src", "app", "pages");
|
|
621
|
-
for (const key in optionalPages) {
|
|
622
|
-
const { file, dir, shouldCopy } = optionalPages[key];
|
|
623
|
-
if (shouldCopy) {
|
|
624
|
-
const srcFilePath = path.join(srcPagesDir, file);
|
|
625
|
-
if (await fs.pathExists(srcFilePath)) {
|
|
626
|
-
await fs.copy(srcFilePath, path.join(targetDir, "src", "app", "pages", file));
|
|
627
|
-
}
|
|
628
|
-
if (dir) {
|
|
629
|
-
const srcDirPath = path.join(srcPagesDir, dir);
|
|
630
|
-
if (await fs.pathExists(srcDirPath)) {
|
|
631
|
-
await fs.copy(srcDirPath, path.join(targetDir, "src", "app", "pages", dir));
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
}
|
|
615
|
+
if (hasLogin) {
|
|
616
|
+
await fs.copy(
|
|
617
|
+
path.join(templatesDir, "src", "features", "auth"),
|
|
618
|
+
path.join(targetDir, "src", "features", "auth")
|
|
619
|
+
);
|
|
635
620
|
}
|
|
636
|
-
if (
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
621
|
+
if (hasHome) {
|
|
622
|
+
await fs.copy(
|
|
623
|
+
path.join(templatesDir, "src", "features", "home"),
|
|
624
|
+
path.join(targetDir, "src", "features", "home")
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
if (hasTemplate) {
|
|
628
|
+
await fs.copy(
|
|
629
|
+
path.join(templatesDir, "src", "features", "template"),
|
|
630
|
+
path.join(targetDir, "src", "features", "template")
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
await fs.ensureDir(path.join(targetDir, "src", "pages"));
|
|
634
|
+
const pagesToCopy = [];
|
|
635
|
+
if (hasLogin) pagesToCopy.push("LoginPage.tsx", "ForgotPasswordPage.tsx", "VerifyEmailPage.tsx", "ResetPasswordPage.tsx");
|
|
636
|
+
if (hasHome) pagesToCopy.push("HomePage.tsx");
|
|
637
|
+
if (hasTemplate) pagesToCopy.push("TemplatePage.tsx");
|
|
638
|
+
for (const pageFile of pagesToCopy) {
|
|
639
|
+
const src = path.join(templatesDir, "src", "pages", pageFile);
|
|
640
|
+
if (await fs.pathExists(src)) {
|
|
641
|
+
await fs.copy(src, path.join(targetDir, "src", "pages", pageFile));
|
|
656
642
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
643
|
+
}
|
|
644
|
+
const firstProtectedPath = hasHome ? "/home" : hasTemplate ? "/template" : "/login";
|
|
645
|
+
const authGuardImports = [
|
|
646
|
+
`import React, { useState, useEffect } from 'react';`,
|
|
647
|
+
`import { Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';`
|
|
648
|
+
];
|
|
649
|
+
if (hasLogin) {
|
|
650
|
+
authGuardImports.push(`import { getStoredUser, storeUser, clearStoredUser } from '../../shared/lib/auth';`);
|
|
651
|
+
authGuardImports.push(`import type { User } from '../../shared/types/auth';`);
|
|
652
|
+
authGuardImports.push(`import { LoginPage } from '../../pages/LoginPage';`);
|
|
653
|
+
authGuardImports.push(`import { ForgotPasswordPage } from '../../pages/ForgotPasswordPage';`);
|
|
654
|
+
authGuardImports.push(`import { VerifyEmailPage } from '../../pages/VerifyEmailPage';`);
|
|
655
|
+
authGuardImports.push(`import { ResetPasswordPage } from '../../pages/ResetPasswordPage';`);
|
|
656
|
+
} else {
|
|
657
|
+
authGuardImports.push(`import { getStoredUser, storeUser, clearStoredUser } from '../../shared/lib/auth';`);
|
|
658
|
+
authGuardImports.push(`import type { User } from '../../shared/types/auth';`);
|
|
659
|
+
}
|
|
660
|
+
if (hasHome) authGuardImports.push(`import { HomePage } from '../../pages/HomePage';`);
|
|
661
|
+
if (hasTemplate) authGuardImports.push(`import { TemplatePage } from '../../pages/TemplatePage';`);
|
|
662
|
+
const protectedRoutes = [];
|
|
663
|
+
if (hasHome) protectedRoutes.push(` <Route path="/home" element={<ProtectedRoute user={user}><HomePage user={user} onLogout={handleLogout} /></ProtectedRoute>} />`);
|
|
664
|
+
if (hasTemplate) protectedRoutes.push(` <Route path="/template" element={<ProtectedRoute user={user}><TemplatePage user={user} onLogout={handleLogout} /></ProtectedRoute>} />`);
|
|
665
|
+
const authRoutes = [];
|
|
666
|
+
if (hasLogin) {
|
|
667
|
+
authRoutes.push(` <Route path="/login" element={user ? <Navigate to="${firstProtectedPath}" replace /> : <LoginPage onLogin={handleLogin} />} />`);
|
|
668
|
+
authRoutes.push(` <Route path="/forgot-password" element={user ? <Navigate to="${firstProtectedPath}" replace /> : <ForgotPasswordPage />} />`);
|
|
669
|
+
authRoutes.push(` <Route path="/verify-email" element={user ? <Navigate to="${firstProtectedPath}" replace /> : <VerifyEmailPage />} />`);
|
|
670
|
+
authRoutes.push(` <Route path="/reset-password" element={user ? <Navigate to="${firstProtectedPath}" replace /> : <ResetPasswordPage />} />`);
|
|
671
|
+
}
|
|
672
|
+
const handleLoginFn = hasLogin ? `
|
|
673
|
+
const handleLogin = (email: string, password: string): boolean => {
|
|
674
|
+
if (!email.trim() || !password.trim()) return false;
|
|
675
|
+
const userData: User = { email };
|
|
676
|
+
storeUser(userData);
|
|
677
|
+
setUser(userData);
|
|
678
|
+
navigate('${firstProtectedPath}');
|
|
679
|
+
return true;
|
|
680
|
+
};` : "";
|
|
681
|
+
const authPathsRedirect = hasLogin ? `
|
|
682
|
+
useEffect(() => {
|
|
683
|
+
const authPaths = ['/login', '/forgot-password', '/verify-email', '/reset-password'];
|
|
684
|
+
if (user && authPaths.includes(location.pathname)) {
|
|
685
|
+
navigate('${firstProtectedPath}', { replace: true });
|
|
686
|
+
}
|
|
687
|
+
}, [user, location.pathname, navigate]);` : "";
|
|
688
|
+
const authGuardContent = `${authGuardImports.join("\n")}
|
|
689
|
+
|
|
690
|
+
function ProtectedRoute({ children, user }: { children: React.ReactNode; user: User | null }) {
|
|
691
|
+
if (!user) return <Navigate to="${hasLogin ? "/login" : firstProtectedPath}" replace />;
|
|
692
|
+
return <>{children}</>;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export function AuthGuard() {
|
|
696
|
+
const [user, setUser] = useState<User | null>(null);
|
|
697
|
+
const navigate = useNavigate();${hasLogin ? `
|
|
698
|
+
const location = useLocation();` : ""}
|
|
699
|
+
|
|
700
|
+
useEffect(() => {
|
|
701
|
+
setUser(getStoredUser());
|
|
702
|
+
}, []);
|
|
703
|
+
${authPathsRedirect}${handleLoginFn}
|
|
704
|
+
|
|
705
|
+
const handleLogout = () => {
|
|
706
|
+
clearStoredUser();
|
|
707
|
+
setUser(null);
|
|
708
|
+
navigate('${hasLogin ? "/login" : firstProtectedPath}');
|
|
709
|
+
};
|
|
661
710
|
|
|
662
|
-
export default function App() {
|
|
663
711
|
return (
|
|
664
|
-
<
|
|
665
|
-
<
|
|
666
|
-
|
|
667
|
-
${
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
</XerticaProvider>
|
|
712
|
+
<div className="min-h-screen bg-muted overflow-x-hidden max-w-full">
|
|
713
|
+
<Routes>
|
|
714
|
+
${authRoutes.join("\n")}
|
|
715
|
+
${protectedRoutes.join("\n")}
|
|
716
|
+
<Route path="/" element={<Navigate to="${hasLogin ? firstProtectedPath === "/login" ? "/login" : firstProtectedPath : firstProtectedPath}" replace />} />
|
|
717
|
+
<Route path="*" element={<Navigate to="${hasLogin ? "/login" : firstProtectedPath}" replace />} />
|
|
718
|
+
</Routes>
|
|
719
|
+
</div>
|
|
673
720
|
);
|
|
674
721
|
}
|
|
675
722
|
`;
|
|
676
|
-
|
|
677
|
-
|
|
723
|
+
await fs.writeFile(
|
|
724
|
+
path.join(targetDir, "src", "app", "components", "AuthGuard.tsx"),
|
|
725
|
+
authGuardContent
|
|
726
|
+
);
|
|
678
727
|
const selectedTheme = colorThemes.find((t) => t.id === response.theme) || colorThemes[0];
|
|
679
728
|
const tokensDir = path.join(targetDir, "src", "styles", "xertica");
|
|
680
729
|
await fs.ensureDir(tokensDir);
|
|
@@ -682,8 +731,7 @@ ${routes.join("\n")}
|
|
|
682
731
|
path.join(templatesDir, "src", "styles", "index.css"),
|
|
683
732
|
path.join(targetDir, "src", "styles", "index.css")
|
|
684
733
|
);
|
|
685
|
-
|
|
686
|
-
await fs.writeFile(path.join(tokensDir, "tokens.css"), newTokensCss);
|
|
734
|
+
await fs.writeFile(path.join(tokensDir, "tokens.css"), generateTokensCss(selectedTheme));
|
|
687
735
|
spinner.succeed("Project initialized successfully!");
|
|
688
736
|
if (response.install) {
|
|
689
737
|
const installSpinner = ora("Installing dependencies...").start();
|
|
@@ -705,34 +753,151 @@ ${routes.join("\n")}
|
|
|
705
753
|
console.error(error);
|
|
706
754
|
}
|
|
707
755
|
});
|
|
708
|
-
program.command("update").alias("update-theme").description("Update theme
|
|
756
|
+
program.command("update").alias("update-theme").description("Update theme or project files to the latest version").action(async () => {
|
|
709
757
|
const targetDir = process.cwd();
|
|
710
|
-
const
|
|
758
|
+
const { updateType } = await prompts({
|
|
759
|
+
type: "select",
|
|
760
|
+
name: "updateType",
|
|
761
|
+
message: "What do you want to update?",
|
|
762
|
+
choices: [
|
|
763
|
+
{ title: "Theme only", description: "Change the color tokens (tokens.css)", value: "theme" },
|
|
764
|
+
{ title: "Project files", description: "Update app shell, shared, features and pages to a specific version", value: "project" }
|
|
765
|
+
]
|
|
766
|
+
});
|
|
767
|
+
if (!updateType) return;
|
|
768
|
+
if (updateType === "theme") {
|
|
769
|
+
const { theme } = await prompts({
|
|
770
|
+
type: "select",
|
|
771
|
+
name: "theme",
|
|
772
|
+
message: "Select the new color theme:",
|
|
773
|
+
choices: colorThemes.map((t) => ({
|
|
774
|
+
title: t.name,
|
|
775
|
+
description: t.description,
|
|
776
|
+
value: t.id
|
|
777
|
+
})),
|
|
778
|
+
initial: 0
|
|
779
|
+
});
|
|
780
|
+
if (!theme) return;
|
|
781
|
+
const spinner2 = ora("Updating theme...").start();
|
|
782
|
+
try {
|
|
783
|
+
const tokensPath = path.join(targetDir, "src", "styles", "xertica", "tokens.css");
|
|
784
|
+
const selectedTheme = colorThemes.find((t) => t.id === theme);
|
|
785
|
+
if (selectedTheme) {
|
|
786
|
+
await fs.ensureDir(path.dirname(tokensPath));
|
|
787
|
+
await fs.writeFile(tokensPath, generateTokensCss(selectedTheme));
|
|
788
|
+
spinner2.succeed(`Theme updated to "${selectedTheme.name}" successfully!`);
|
|
789
|
+
} else {
|
|
790
|
+
spinner2.fail("Theme not found.");
|
|
791
|
+
}
|
|
792
|
+
} catch (error) {
|
|
793
|
+
spinner2.fail("Failed to update theme");
|
|
794
|
+
console.error(error);
|
|
795
|
+
}
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
const { versionType } = await prompts({
|
|
711
799
|
type: "select",
|
|
712
|
-
name: "
|
|
713
|
-
message: "
|
|
714
|
-
choices:
|
|
715
|
-
title:
|
|
716
|
-
description:
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
800
|
+
name: "versionType",
|
|
801
|
+
message: "Which version do you want to update to?",
|
|
802
|
+
choices: [
|
|
803
|
+
{ title: "Latest", description: "Install the latest published version", value: "latest" },
|
|
804
|
+
{ title: "Specific version", description: "Enter a version number (e.g. 2.0.2)", value: "specific" }
|
|
805
|
+
]
|
|
806
|
+
});
|
|
807
|
+
if (!versionType) return;
|
|
808
|
+
let targetVersion = "latest";
|
|
809
|
+
if (versionType === "specific") {
|
|
810
|
+
const { version } = await prompts({
|
|
811
|
+
type: "text",
|
|
812
|
+
name: "version",
|
|
813
|
+
message: "Enter the version (e.g. 2.0.2):",
|
|
814
|
+
validate: (v) => /^\d+\.\d+\.\d+/.test(v.trim()) ? true : "Enter a valid semver (e.g. 2.0.2)"
|
|
815
|
+
});
|
|
816
|
+
if (!version) return;
|
|
817
|
+
targetVersion = version.trim();
|
|
818
|
+
}
|
|
819
|
+
const { filesToUpdate } = await prompts({
|
|
820
|
+
type: "multiselect",
|
|
821
|
+
name: "filesToUpdate",
|
|
822
|
+
message: "Select which parts of the project to update:",
|
|
823
|
+
choices: [
|
|
824
|
+
{ title: "App shell (src/app/)", description: "App.tsx, AppLayout.tsx", value: "app", selected: true },
|
|
825
|
+
{ title: "Shared utilities (src/shared/)", description: "auth.ts, navigation.ts, types", value: "shared", selected: true },
|
|
826
|
+
{ title: "Features (src/features/)", description: "auth, home, template UI components", value: "features", selected: true },
|
|
827
|
+
{ title: "Pages (src/pages/)", description: "Thin page wrapper components", value: "pages", selected: true },
|
|
828
|
+
{ title: "Root config files", description: "vite.config.ts, tsconfig.json, etc.", value: "config", selected: false }
|
|
829
|
+
]
|
|
720
830
|
});
|
|
721
|
-
if (!
|
|
722
|
-
const
|
|
831
|
+
if (!filesToUpdate || filesToUpdate.length === 0) return;
|
|
832
|
+
const { confirmed } = await prompts({
|
|
833
|
+
type: "confirm",
|
|
834
|
+
name: "confirmed",
|
|
835
|
+
message: chalk.yellow(`\u26A0\uFE0F This will overwrite the selected files. Local changes will be lost. Continue?`),
|
|
836
|
+
initial: false
|
|
837
|
+
});
|
|
838
|
+
if (!confirmed) {
|
|
839
|
+
console.log(chalk.gray("Update cancelled."));
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
const spinner = ora(`Installing xertica-ui@${targetVersion}...`).start();
|
|
723
843
|
try {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
844
|
+
await execa("npm", ["install", `xertica-ui@${targetVersion}`], { cwd: targetDir });
|
|
845
|
+
spinner.text = "Copying updated files...";
|
|
846
|
+
const updatedTemplatesDir = path.join(targetDir, "node_modules", "xertica-ui", "templates");
|
|
847
|
+
if (filesToUpdate.includes("app")) {
|
|
848
|
+
await fs.copy(
|
|
849
|
+
path.join(updatedTemplatesDir, "src", "app", "App.tsx"),
|
|
850
|
+
path.join(targetDir, "src", "app", "App.tsx"),
|
|
851
|
+
{ overwrite: true }
|
|
852
|
+
);
|
|
853
|
+
await fs.copy(
|
|
854
|
+
path.join(updatedTemplatesDir, "src", "app", "components", "AppLayout.tsx"),
|
|
855
|
+
path.join(targetDir, "src", "app", "components", "AppLayout.tsx"),
|
|
856
|
+
{ overwrite: true }
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
if (filesToUpdate.includes("shared")) {
|
|
860
|
+
await fs.copy(
|
|
861
|
+
path.join(updatedTemplatesDir, "src", "shared"),
|
|
862
|
+
path.join(targetDir, "src", "shared"),
|
|
863
|
+
{ overwrite: true }
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
if (filesToUpdate.includes("features")) {
|
|
867
|
+
for (const feature of ["auth", "home", "template"]) {
|
|
868
|
+
const destFeature = path.join(targetDir, "src", "features", feature);
|
|
869
|
+
const srcFeature = path.join(updatedTemplatesDir, "src", "features", feature);
|
|
870
|
+
if (await fs.pathExists(destFeature) && await fs.pathExists(srcFeature)) {
|
|
871
|
+
await fs.copy(srcFeature, destFeature, { overwrite: true });
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (filesToUpdate.includes("pages")) {
|
|
876
|
+
const pagesDir = path.join(targetDir, "src", "pages");
|
|
877
|
+
const srcPagesDir = path.join(updatedTemplatesDir, "src", "pages");
|
|
878
|
+
if (await fs.pathExists(pagesDir) && await fs.pathExists(srcPagesDir)) {
|
|
879
|
+
const existingPages = await fs.readdir(pagesDir);
|
|
880
|
+
for (const pageFile of existingPages) {
|
|
881
|
+
const src = path.join(srcPagesDir, pageFile);
|
|
882
|
+
if (await fs.pathExists(src)) {
|
|
883
|
+
await fs.copy(src, path.join(pagesDir, pageFile), { overwrite: true });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (filesToUpdate.includes("config")) {
|
|
889
|
+
const configFiles = ["vite.config.ts", "tsconfig.json", "tsconfig.node.json", "postcss.config.js"];
|
|
890
|
+
for (const file of configFiles) {
|
|
891
|
+
const src = path.join(updatedTemplatesDir, "..", file);
|
|
892
|
+
if (await fs.pathExists(src)) {
|
|
893
|
+
await fs.copy(src, path.join(targetDir, file), { overwrite: true });
|
|
894
|
+
}
|
|
895
|
+
}
|
|
733
896
|
}
|
|
897
|
+
spinner.succeed(`Project updated to xertica-ui@${targetVersion} successfully!`);
|
|
898
|
+
console.log(chalk.gray("\n Run npm run dev to start the development server."));
|
|
734
899
|
} catch (error) {
|
|
735
|
-
spinner.fail("Failed to update
|
|
900
|
+
spinner.fail("Failed to update project");
|
|
736
901
|
console.error(error);
|
|
737
902
|
}
|
|
738
903
|
});
|
|
@@ -3,3 +3,4 @@ export { CodeBlock } from './code-block';
|
|
|
3
3
|
export { MarkdownMessage } from './markdown-message';
|
|
4
4
|
export { ModernChatInput } from './modern-chat-input';
|
|
5
5
|
export { FormattedDocument } from './formatted-document';
|
|
6
|
+
export { generateDemoResponse } from '../../utils/demo-responses';
|
package/package.json
CHANGED
package/templates/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-xertica-app",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"react-dom": "^18.3.1",
|
|
18
18
|
"react-router-dom": "^7.1.3",
|
|
19
19
|
"sonner": "^1.7.3",
|
|
20
|
-
"xertica-ui": "^2.0.
|
|
20
|
+
"xertica-ui": "^2.0.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@eslint/js": "^9.18.0",
|