create-bdpa-react-scaffold 1.9.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.
Files changed (2) hide show
  1. package/create-ui-lib.js +607 -84
  2. package/package.json +2 -2
package/create-ui-lib.js CHANGED
@@ -658,6 +658,7 @@ export function cn(...inputs) {
658
658
  write("src/index.js", `
659
659
  export { Button } from "./components/ui/button.jsx";
660
660
 
661
+ export { default as Home } from "./pages/Home.jsx";
661
662
  export { default as Login } from "./pages/auth/Login.jsx";
662
663
  export { default as Register } from "./pages/auth/Register.jsx";
663
664
 
@@ -669,8 +670,50 @@ export { hashPassword, verifyPassword, getPasswordStrength, getPasswordStrengthL
669
670
  `);
670
671
 
671
672
  write("src/App.jsx", `
672
- import { useState } from "react";
673
673
  import { Routes, Route, useNavigate } from "react-router-dom";
674
+ import { toast } from "sonner";
675
+ import Home from "./pages/Home.jsx";
676
+ import Login from "./pages/auth/Login.jsx";
677
+ import Register from "./pages/auth/Register.jsx";
678
+ import ComponentTest from "./pages/ComponentTest.jsx";
679
+
680
+ export default function App() {
681
+ const navigate = useNavigate();
682
+
683
+ return (
684
+ <Routes>
685
+ <Route path="/" element={<Home />} />
686
+ <Route
687
+ path="/login"
688
+ element={
689
+ <Login
690
+ onSubmit={() => {
691
+ toast.success("Login submitted!");
692
+ navigate("/");
693
+ }}
694
+ />
695
+ }
696
+ />
697
+ <Route
698
+ path="/register"
699
+ element={
700
+ <Register
701
+ onSubmit={() => {
702
+ toast.success("Registration submitted!");
703
+ navigate("/");
704
+ }}
705
+ />
706
+ }
707
+ />
708
+ <Route path="/component-test" element={<ComponentTest />} />
709
+ </Routes>
710
+ );
711
+ }
712
+ `);
713
+
714
+ write("src/pages/Home.jsx", `
715
+ import { useState } from "react";
716
+ import { useNavigate } from "react-router-dom";
674
717
  import { Button } from "@/components/ui/button";
675
718
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
676
719
  import { Input } from "@/components/ui/input";
@@ -679,24 +722,38 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
679
722
  import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
680
723
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
681
724
  import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
725
+ import { Badge } from "@/components/ui/badge";
726
+ import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
727
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
728
+ import { Checkbox } from "@/components/ui/checkbox";
729
+ import { Progress } from "@/components/ui/progress";
730
+ import { Separator } from "@/components/ui/separator";
731
+ import { Switch } from "@/components/ui/switch";
732
+ import { Textarea } from "@/components/ui/textarea";
733
+ import { Skeleton } from "@/components/ui/skeleton";
734
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
682
735
  import { toast } from "sonner";
683
- import { Menu } from "lucide-react";
684
- import { ApiClient } from "./utils/api.js";
685
- import Login from "./pages/auth/Login.jsx";
686
- import Register from "./pages/auth/Register.jsx";
736
+ import { Menu, Info, CheckCircle } from "lucide-react";
737
+ import { ApiClient } from "@/utils/api.js";
687
738
 
688
739
  const enrollmentData = [
689
740
  { name: "Alex", course: "Web Design Fundamentals", status: "Enrolled" },
690
741
  { name: "Jordan", course: "Advanced Web App Design", status: "Waitlisted" },
691
- { name: "Taylor", course: "eSports Strategy", status: "Enrolled" }
742
+ { name: "Taylor", course: "eSports Strategy", status: "Enrolled" },
692
743
  ];
693
744
 
694
- function Dashboard() {
745
+ const navLinks = [
746
+ { label: "Home", href: "/" },
747
+ { label: "Login", href: "/login" },
748
+ { label: "Register", href: "/register" },
749
+ { label: "Component Test", href: "/component-test" },
750
+ ];
751
+
752
+ export default function Home() {
695
753
  const [modalOpen, setModalOpen] = useState(false);
696
754
  const [posts, setPosts] = useState([]);
697
755
  const [loadingPosts, setLoadingPosts] = useState(false);
698
756
  const [postsError, setPostsError] = useState("");
699
- const navigate = useNavigate();
700
757
  const client = new ApiClient("https://jsonplaceholder.typicode.com");
701
758
 
702
759
  const fetchPosts = async () => {
@@ -711,12 +768,6 @@ function Dashboard() {
711
768
  setLoadingPosts(false);
712
769
  };
713
770
 
714
- const navLinks = [
715
- { label: "Home", href: "/" },
716
- { label: "Login", href: "/login" },
717
- { label: "Register", href: "/register" }
718
- ];
719
-
720
771
  return (
721
772
  <div className="flex h-screen overflow-hidden">
722
773
 
@@ -737,7 +788,6 @@ function Dashboard() {
737
788
 
738
789
  {/* Navbar */}
739
790
  <nav className="bg-white border-b px-4 py-3 flex items-center justify-between">
740
- {/* Mobile sidebar trigger */}
741
791
  <Sheet>
742
792
  <SheetTrigger asChild>
743
793
  <Button variant="ghost" size="icon" className="md:hidden">
@@ -762,14 +812,10 @@ function Dashboard() {
762
812
  {/* Page content */}
763
813
  <div className="p-6 space-y-6 overflow-auto">
764
814
 
765
- {/* BDPA Logo Section */}
815
+ {/* BDPA Logo */}
766
816
  <Card className="text-center">
767
817
  <CardContent className="pt-6">
768
- <img
769
- src="/BDPA_edited.png"
770
- alt="BDPA Logo"
771
- className="h-32 mx-auto mb-4"
772
- />
818
+ <img src="/BDPA_edited.png" alt="BDPA Logo" className="h-32 mx-auto mb-4" />
773
819
  <h1 className="text-3xl font-bold text-blue-600">Welcome to BDPA</h1>
774
820
  <p className="text-gray-600 mt-2">Black Data Professionals Association</p>
775
821
  </CardContent>
@@ -782,14 +828,28 @@ function Dashboard() {
782
828
  <TabsTrigger value="components">Components</TabsTrigger>
783
829
  <TabsTrigger value="auth">Auth</TabsTrigger>
784
830
  </TabsList>
785
- <TabsContent value="overview"><p className="mt-2 text-sm">Welcome to the BDPA React Scaffold and Demo.</p></TabsContent>
786
- <TabsContent value="components"><p className="mt-2 text-sm">Buttons, Cards, Inputs, Tables, and more.</p></TabsContent>
787
- <TabsContent value="auth"><p className="mt-2 text-sm">Login + Registration pages included.</p></TabsContent>
831
+ <TabsContent value="overview">
832
+ <Alert className="mt-2">
833
+ <CheckCircle className="h-4 w-4" />
834
+ <AlertTitle>Welcome!</AlertTitle>
835
+ <AlertDescription>Welcome to the BDPA React Scaffold and Demo. shadcn/ui components are fully installed.</AlertDescription>
836
+ </Alert>
837
+ </TabsContent>
838
+ <TabsContent value="components">
839
+ <Alert className="mt-2" variant="default">
840
+ <Info className="h-4 w-4" />
841
+ <AlertTitle>Components</AlertTitle>
842
+ <AlertDescription>Buttons, Cards, Inputs, Tables, Badges, Selects, and more — all from shadcn/ui.</AlertDescription>
843
+ </Alert>
844
+ </TabsContent>
845
+ <TabsContent value="auth">
846
+ <p className="mt-2 text-sm">Login + Registration pages included.</p>
847
+ </TabsContent>
788
848
  </Tabs>
789
849
 
790
850
  <div className="grid md:grid-cols-2 gap-6">
791
851
 
792
- {/* Form/Card example */}
852
+ {/* Sample Form */}
793
853
  <Card>
794
854
  <CardHeader><CardTitle>Sample Form</CardTitle></CardHeader>
795
855
  <CardContent className="space-y-4">
@@ -812,7 +872,7 @@ function Dashboard() {
812
872
  </CardContent>
813
873
  </Card>
814
874
 
815
- {/* Table example */}
875
+ {/* Enrollment Table */}
816
876
  <Card>
817
877
  <CardHeader><CardTitle>Enrollment Overview</CardTitle></CardHeader>
818
878
  <CardContent>
@@ -842,10 +902,85 @@ function Dashboard() {
842
902
  <Card>
843
903
  <CardHeader><CardTitle>Button Variants</CardTitle></CardHeader>
844
904
  <CardContent className="flex flex-wrap gap-3">
845
- <Button>Primary</Button>
905
+ <TooltipProvider>
906
+ <Tooltip>
907
+ <TooltipTrigger asChild><Button>Primary</Button></TooltipTrigger>
908
+ <TooltipContent>Primary action</TooltipContent>
909
+ </Tooltip>
910
+ </TooltipProvider>
846
911
  <Button variant="secondary">Secondary</Button>
847
912
  <Button variant="destructive">Danger</Button>
848
913
  <Button variant="outline">Outline</Button>
914
+ <Button variant="ghost">Ghost</Button>
915
+ <Button variant="link">Link</Button>
916
+ </CardContent>
917
+ </Card>
918
+
919
+ <Separator />
920
+
921
+ {/* Badges */}
922
+ <Card>
923
+ <CardHeader><CardTitle>Badges</CardTitle></CardHeader>
924
+ <CardContent className="flex flex-wrap gap-2">
925
+ <Badge>Default</Badge>
926
+ <Badge variant="secondary">Secondary</Badge>
927
+ <Badge variant="destructive">Destructive</Badge>
928
+ <Badge variant="outline">Outline</Badge>
929
+ </CardContent>
930
+ </Card>
931
+
932
+ {/* Select / Checkbox / Switch / Textarea / Progress */}
933
+ <div className="grid md:grid-cols-2 gap-6">
934
+ <Card>
935
+ <CardHeader><CardTitle>Select &amp; Switch</CardTitle></CardHeader>
936
+ <CardContent className="space-y-4">
937
+ <div className="space-y-1">
938
+ <Label>Course Level</Label>
939
+ <Select>
940
+ <SelectTrigger>
941
+ <SelectValue placeholder="Select level" />
942
+ </SelectTrigger>
943
+ <SelectContent>
944
+ <SelectItem value="beginner">Beginner</SelectItem>
945
+ <SelectItem value="intermediate">Intermediate</SelectItem>
946
+ <SelectItem value="advanced">Advanced</SelectItem>
947
+ </SelectContent>
948
+ </Select>
949
+ </div>
950
+ <div className="flex items-center gap-2">
951
+ <Checkbox id="terms" />
952
+ <Label htmlFor="terms">Accept terms &amp; conditions</Label>
953
+ </div>
954
+ <div className="flex items-center gap-2">
955
+ <Switch id="notifications" />
956
+ <Label htmlFor="notifications">Enable notifications</Label>
957
+ </div>
958
+ </CardContent>
959
+ </Card>
960
+
961
+ <Card>
962
+ <CardHeader><CardTitle>Textarea &amp; Progress</CardTitle></CardHeader>
963
+ <CardContent className="space-y-4">
964
+ <div className="space-y-1">
965
+ <Label htmlFor="bio">Bio</Label>
966
+ <Textarea id="bio" placeholder="Tell us about yourself..." />
967
+ </div>
968
+ <div className="space-y-1">
969
+ <Label>Profile Completion</Label>
970
+ <Progress value={65} className="h-2" />
971
+ <p className="text-xs text-muted-foreground">65% complete</p>
972
+ </div>
973
+ </CardContent>
974
+ </Card>
975
+ </div>
976
+
977
+ {/* Skeleton */}
978
+ <Card>
979
+ <CardHeader><CardTitle>Skeleton Loading State</CardTitle></CardHeader>
980
+ <CardContent className="space-y-2">
981
+ <Skeleton className="h-4 w-full" />
982
+ <Skeleton className="h-4 w-3/4" />
983
+ <Skeleton className="h-4 w-1/2" />
849
984
  </CardContent>
850
985
  </Card>
851
986
 
@@ -874,9 +1009,7 @@ function Dashboard() {
874
1009
  {/* Dialog + Toast */}
875
1010
  <div className="flex gap-4">
876
1011
  <Button onClick={() => setModalOpen(true)}>Open Dialog</Button>
877
- <Button onClick={() => toast.success("This is a toast!")}>
878
- Show Toast
879
- </Button>
1012
+ <Button onClick={() => toast.success("This is a toast!")}>Show Toast</Button>
880
1013
  </div>
881
1014
 
882
1015
  <Dialog open={modalOpen} onOpenChange={setModalOpen}>
@@ -894,38 +1027,6 @@ function Dashboard() {
894
1027
  </div>
895
1028
  );
896
1029
  }
897
-
898
- export default function App() {
899
- const navigate = useNavigate();
900
-
901
- return (
902
- <Routes>
903
- <Route path="/" element={<Dashboard />} />
904
- <Route
905
- path="/login"
906
- element={
907
- <Login
908
- onSubmit={() => {
909
- alert("Login submitted!");
910
- navigate("/");
911
- }}
912
- />
913
- }
914
- />
915
- <Route
916
- path="/register"
917
- element={
918
- <Register
919
- onSubmit={() => {
920
- alert("Registration submitted!");
921
- navigate("/");
922
- }}
923
- />
924
- }
925
- />
926
- </Routes>
927
- );
928
- }
929
1030
  `);
930
1031
 
931
1032
  // Note: All UI components (Card, Input, Form, Table, Navbar, Tabs, Toast, etc.)
@@ -937,32 +1038,83 @@ export default function App() {
937
1038
  // -------------------------------
938
1039
 
939
1040
  write("src/pages/auth/Login.jsx", `
1041
+ import { useState } from "react";
940
1042
  import { Button } from "@/components/ui/button";
941
1043
  import { Input } from "@/components/ui/input";
942
1044
  import { Label } from "@/components/ui/label";
943
1045
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1046
+ import { Alert, AlertDescription } from "@/components/ui/alert";
1047
+ import { Checkbox } from "@/components/ui/checkbox";
1048
+ import { Separator } from "@/components/ui/separator";
1049
+ import { Badge } from "@/components/ui/badge";
944
1050
 
945
1051
  export default function Login({ onSubmit }) {
1052
+ const [email, setEmail] = useState("");
1053
+ const [password, setPassword] = useState("");
1054
+ const [error, setError] = useState("");
1055
+ const [rememberMe, setRememberMe] = useState(false);
1056
+
1057
+ const handleSubmit = (e) => {
1058
+ e.preventDefault();
1059
+ if (!email || !password) {
1060
+ setError("Email and password are required.");
1061
+ return;
1062
+ }
1063
+ setError("");
1064
+ if (onSubmit) onSubmit({ email, password, rememberMe });
1065
+ };
1066
+
946
1067
  return (
947
1068
  <div className="flex items-center justify-center min-h-screen bg-gray-100">
948
1069
  <Card className="w-full max-w-sm">
949
1070
  <CardHeader>
950
- <CardTitle>Sign In</CardTitle>
951
- </CardHeader>
952
- <CardContent className="space-y-4">
953
- <div className="space-y-1">
954
- <Label htmlFor="email">Email</Label>
955
- <Input id="email" type="email" placeholder="you@example.com" />
956
- </div>
957
- <div className="space-y-1">
958
- <Label htmlFor="password">Password</Label>
959
- <Input id="password" type="password" placeholder="••••••••" />
1071
+ <div className="flex items-center justify-between">
1072
+ <CardTitle>Sign In</CardTitle>
1073
+ <Badge variant="outline">shadcn/ui</Badge>
960
1074
  </div>
961
- <Button className="w-full" onClick={onSubmit}>
962
- Sign In
963
- </Button>
1075
+ </CardHeader>
1076
+ <CardContent>
1077
+ <form onSubmit={handleSubmit} className="space-y-4">
1078
+ {error && (
1079
+ <Alert variant="destructive">
1080
+ <AlertDescription>{error}</AlertDescription>
1081
+ </Alert>
1082
+ )}
1083
+ <div className="space-y-1">
1084
+ <Label htmlFor="email">Email</Label>
1085
+ <Input
1086
+ id="email"
1087
+ type="email"
1088
+ placeholder="you@example.com"
1089
+ value={email}
1090
+ onChange={(e) => setEmail(e.target.value)}
1091
+ />
1092
+ </div>
1093
+ <div className="space-y-1">
1094
+ <Label htmlFor="password">Password</Label>
1095
+ <Input
1096
+ id="password"
1097
+ type="password"
1098
+ placeholder="Password"
1099
+ value={password}
1100
+ onChange={(e) => setPassword(e.target.value)}
1101
+ />
1102
+ </div>
1103
+ <div className="flex items-center gap-2">
1104
+ <Checkbox
1105
+ id="remember"
1106
+ checked={rememberMe}
1107
+ onCheckedChange={setRememberMe}
1108
+ />
1109
+ <Label htmlFor="remember" className="text-sm">Remember me</Label>
1110
+ </div>
1111
+ <Button type="submit" className="w-full">
1112
+ Sign In
1113
+ </Button>
1114
+ </form>
1115
+ <Separator className="my-4" />
964
1116
  <p className="text-sm text-center text-gray-600">
965
- Dont have an account?{" "}
1117
+ Don't have an account?{" "}
966
1118
  <a href="/register" className="text-blue-600 hover:underline">
967
1119
  Create one
968
1120
  </a>
@@ -973,35 +1125,108 @@ export default function Login({ onSubmit }) {
973
1125
  );
974
1126
  }`);
975
1127
 
1128
+
976
1129
  write("src/pages/auth/Register.jsx", `
1130
+ import { useState } from "react";
977
1131
  import { Button } from "@/components/ui/button";
978
1132
  import { Input } from "@/components/ui/input";
979
1133
  import { Label } from "@/components/ui/label";
980
1134
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1135
+ import { Alert, AlertDescription } from "@/components/ui/alert";
1136
+ import { Progress } from "@/components/ui/progress";
1137
+ import { Separator } from "@/components/ui/separator";
1138
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
1139
+ import { Badge } from "@/components/ui/badge";
1140
+
1141
+ function calcStrength(pw) {
1142
+ let s = 0;
1143
+ if (pw.length >= 8) s++;
1144
+ if (pw.length >= 12) s++;
1145
+ if (/[a-z]/.test(pw) && /[A-Z]/.test(pw)) s++;
1146
+ if (/\\d/.test(pw)) s++;
1147
+ if (/[^A-Za-z0-9]/.test(pw)) s++;
1148
+ return Math.min(s, 4);
1149
+ }
1150
+
1151
+ const strengthLabels = ["Weak", "Fair", "Good", "Strong", "Very Strong"];
1152
+ const strengthColors = ["bg-red-500", "bg-orange-400", "bg-yellow-400", "bg-green-400", "bg-green-600"];
981
1153
 
982
1154
  export default function Register({ onSubmit }) {
1155
+ const [name, setName] = useState("");
1156
+ const [email, setEmail] = useState("");
1157
+ const [password, setPassword] = useState("");
1158
+ const [role, setRole] = useState("");
1159
+ const [error, setError] = useState("");
1160
+ const strength = calcStrength(password);
1161
+
1162
+ const handleSubmit = (e) => {
1163
+ e.preventDefault();
1164
+ if (!name || !email || !password) {
1165
+ setError("All fields are required.");
1166
+ return;
1167
+ }
1168
+ if (password.length < 8) {
1169
+ setError("Password must be at least 8 characters.");
1170
+ return;
1171
+ }
1172
+ setError("");
1173
+ if (onSubmit) onSubmit({ name, email, password, role });
1174
+ };
1175
+
983
1176
  return (
984
1177
  <div className="flex items-center justify-center min-h-screen bg-gray-100">
985
1178
  <Card className="w-full max-w-sm">
986
1179
  <CardHeader>
987
- <CardTitle>Create Account</CardTitle>
1180
+ <div className="flex items-center justify-between">
1181
+ <CardTitle>Create Account</CardTitle>
1182
+ <Badge variant="outline">shadcn/ui</Badge>
1183
+ </div>
988
1184
  </CardHeader>
989
- <CardContent className="space-y-4">
1185
+ <CardContent>
1186
+ <form onSubmit={handleSubmit} className="space-y-4">
1187
+ {error && (
1188
+ <Alert variant="destructive">
1189
+ <AlertDescription>{error}</AlertDescription>
1190
+ </Alert>
1191
+ )}
990
1192
  <div className="space-y-1">
991
1193
  <Label htmlFor="name">Full Name</Label>
992
- <Input id="name" placeholder="Your Name" />
1194
+ <Input id="name" placeholder="Your Name" value={name} onChange={(e) => setName(e.target.value)} />
993
1195
  </div>
994
1196
  <div className="space-y-1">
995
1197
  <Label htmlFor="email">Email</Label>
996
- <Input id="email" type="email" placeholder="you@example.com" />
1198
+ <Input id="email" type="email" placeholder="you@example.com" value={email} onChange={(e) => setEmail(e.target.value)} />
1199
+ </div>
1200
+ <div className="space-y-1">
1201
+ <Label htmlFor="r-role">Role</Label>
1202
+ <Select onValueChange={setRole}>
1203
+ <SelectTrigger id="r-role">
1204
+ <SelectValue placeholder="Select your role" />
1205
+ </SelectTrigger>
1206
+ <SelectContent>
1207
+ <SelectItem value="student">Student</SelectItem>
1208
+ <SelectItem value="mentor">Mentor</SelectItem>
1209
+ <SelectItem value="admin">Admin</SelectItem>
1210
+ </SelectContent>
1211
+ </Select>
997
1212
  </div>
998
1213
  <div className="space-y-1">
999
1214
  <Label htmlFor="password">Password</Label>
1000
- <Input id="password" type="password" placeholder="••••••••" />
1215
+ <Input id="password" type="password" placeholder="••••••••" value={password} onChange={(e) => setPassword(e.target.value)} />
1001
1216
  </div>
1002
- <Button className="w-full" onClick={onSubmit}>
1003
- Register
1004
- </Button>
1217
+ {password && (
1218
+ <div className="space-y-1">
1219
+ <Progress value={(strength / 4) * 100} className="h-2" />
1220
+ <p className="text-xs text-muted-foreground">
1221
+ Strength: <span className="font-medium">{strengthLabels[strength]}</span>
1222
+ </p>
1223
+ </div>
1224
+ )}
1225
+ <Button type="submit" className="w-full">
1226
+ Register
1227
+ </Button>
1228
+ </form>
1229
+ <Separator className="my-4" />
1005
1230
  <p className="text-sm text-center text-gray-600">
1006
1231
  Already have an account?{" "}
1007
1232
  <a href="/login" className="text-blue-600 hover:underline">
@@ -1015,6 +1240,304 @@ export default function Register({ onSubmit }) {
1015
1240
  }
1016
1241
  `);
1017
1242
 
1243
+ // -------------------------------
1244
+ // ComponentTest page — comprehensive shadcn test
1245
+ // -------------------------------
1246
+
1247
+ write("src/pages/ComponentTest.jsx", `
1248
+ import { useState } from "react";
1249
+ import { Button } from "@/components/ui/button";
1250
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1251
+ import { Input } from "@/components/ui/input";
1252
+ import { Label } from "@/components/ui/label";
1253
+ import { Badge } from "@/components/ui/badge";
1254
+ import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
1255
+ import { Checkbox } from "@/components/ui/checkbox";
1256
+ import { Switch } from "@/components/ui/switch";
1257
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
1258
+ import { Progress } from "@/components/ui/progress";
1259
+ import { Separator } from "@/components/ui/separator";
1260
+ import { Skeleton } from "@/components/ui/skeleton";
1261
+ import { Textarea } from "@/components/ui/textarea";
1262
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
1263
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
1264
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
1265
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
1266
+ import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
1267
+ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
1268
+ import { toast } from "sonner";
1269
+ import { CheckCircle, Info, AlertCircle } from "lucide-react";
1270
+
1271
+ const sampleRows = [
1272
+ { id: 1, name: "Ada Lovelace", role: "Student", status: "Active" },
1273
+ { id: 2, name: "Grace Hopper", role: "Mentor", status: "Active" },
1274
+ { id: 3, name: "Alan Turing", role: "Admin", status: "Inactive" },
1275
+ ];
1276
+
1277
+ export default function ComponentTest() {
1278
+ const [dialogOpen, setDialogOpen] = useState(false);
1279
+ const [progress, setProgress] = useState(40);
1280
+ const [switchOn, setSwitchOn] = useState(false);
1281
+ const [checked, setChecked] = useState(false);
1282
+
1283
+ return (
1284
+ <div className="p-6 max-w-4xl mx-auto space-y-8">
1285
+ <div className="flex items-center justify-between">
1286
+ <h1 className="text-3xl font-bold">shadcn/ui Component Test</h1>
1287
+ <Badge>All Components</Badge>
1288
+ </div>
1289
+
1290
+ <Separator />
1291
+
1292
+ {/* Alerts */}
1293
+ <Card>
1294
+ <CardHeader><CardTitle>Alert</CardTitle></CardHeader>
1295
+ <CardContent className="space-y-3">
1296
+ <Alert>
1297
+ <Info className="h-4 w-4" />
1298
+ <AlertTitle>Info</AlertTitle>
1299
+ <AlertDescription>This is a default informational alert.</AlertDescription>
1300
+ </Alert>
1301
+ <Alert variant="destructive">
1302
+ <AlertCircle className="h-4 w-4" />
1303
+ <AlertTitle>Error</AlertTitle>
1304
+ <AlertDescription>Something went wrong. Please try again.</AlertDescription>
1305
+ </Alert>
1306
+ </CardContent>
1307
+ </Card>
1308
+
1309
+ {/* Avatar */}
1310
+ <Card>
1311
+ <CardHeader><CardTitle>Avatar</CardTitle></CardHeader>
1312
+ <CardContent className="flex gap-4">
1313
+ <Avatar>
1314
+ <AvatarImage src="https://github.com/shadcn.png" alt="shadcn" />
1315
+ <AvatarFallback>CN</AvatarFallback>
1316
+ </Avatar>
1317
+ <Avatar>
1318
+ <AvatarFallback>AL</AvatarFallback>
1319
+ </Avatar>
1320
+ <Avatar>
1321
+ <AvatarFallback>GH</AvatarFallback>
1322
+ </Avatar>
1323
+ </CardContent>
1324
+ </Card>
1325
+
1326
+ {/* Badge */}
1327
+ <Card>
1328
+ <CardHeader><CardTitle>Badge</CardTitle></CardHeader>
1329
+ <CardContent className="flex flex-wrap gap-2">
1330
+ <Badge>Default</Badge>
1331
+ <Badge variant="secondary">Secondary</Badge>
1332
+ <Badge variant="destructive">Destructive</Badge>
1333
+ <Badge variant="outline">Outline</Badge>
1334
+ </CardContent>
1335
+ </Card>
1336
+
1337
+ {/* Button */}
1338
+ <Card>
1339
+ <CardHeader><CardTitle>Button</CardTitle></CardHeader>
1340
+ <CardContent className="flex flex-wrap gap-2">
1341
+ <Button onClick={() => toast.success("Primary clicked!")}>Primary</Button>
1342
+ <Button variant="secondary">Secondary</Button>
1343
+ <Button variant="destructive">Destructive</Button>
1344
+ <Button variant="outline">Outline</Button>
1345
+ <Button variant="ghost">Ghost</Button>
1346
+ <Button variant="link">Link</Button>
1347
+ <Button disabled>Disabled</Button>
1348
+ <Button size="sm">Small</Button>
1349
+ <Button size="lg">Large</Button>
1350
+ </CardContent>
1351
+ </Card>
1352
+
1353
+ {/* Checkbox + Switch */}
1354
+ <Card>
1355
+ <CardHeader><CardTitle>Checkbox &amp; Switch</CardTitle></CardHeader>
1356
+ <CardContent className="space-y-3">
1357
+ <div className="flex items-center gap-2">
1358
+ <Checkbox id="test-cb" checked={checked} onCheckedChange={setChecked} />
1359
+ <Label htmlFor="test-cb">Accept terms: {checked ? "Yes" : "No"}</Label>
1360
+ </div>
1361
+ <div className="flex items-center gap-2">
1362
+ <Switch id="test-sw" checked={switchOn} onCheckedChange={setSwitchOn} />
1363
+ <Label htmlFor="test-sw">Notifications: {switchOn ? "On" : "Off"}</Label>
1364
+ </div>
1365
+ </CardContent>
1366
+ </Card>
1367
+
1368
+ {/* Input + Textarea + Select + Label */}
1369
+ <Card>
1370
+ <CardHeader><CardTitle>Input / Textarea / Select</CardTitle></CardHeader>
1371
+ <CardContent className="space-y-4">
1372
+ <div className="space-y-1">
1373
+ <Label htmlFor="ct-name">Name</Label>
1374
+ <Input id="ct-name" placeholder="Enter your name" />
1375
+ </div>
1376
+ <div className="space-y-1">
1377
+ <Label htmlFor="ct-bio">Bio</Label>
1378
+ <Textarea id="ct-bio" placeholder="Tell us about yourself" />
1379
+ </div>
1380
+ <div className="space-y-1">
1381
+ <Label>Role</Label>
1382
+ <Select>
1383
+ <SelectTrigger>
1384
+ <SelectValue placeholder="Choose a role" />
1385
+ </SelectTrigger>
1386
+ <SelectContent>
1387
+ <SelectItem value="student">Student</SelectItem>
1388
+ <SelectItem value="mentor">Mentor</SelectItem>
1389
+ <SelectItem value="admin">Admin</SelectItem>
1390
+ </SelectContent>
1391
+ </Select>
1392
+ </div>
1393
+ </CardContent>
1394
+ </Card>
1395
+
1396
+ {/* Progress */}
1397
+ <Card>
1398
+ <CardHeader><CardTitle>Progress</CardTitle></CardHeader>
1399
+ <CardContent className="space-y-3">
1400
+ <Progress value={progress} />
1401
+ <div className="flex gap-2">
1402
+ <Button size="sm" onClick={() => setProgress(Math.max(0, progress - 10))}>-10</Button>
1403
+ <Button size="sm" onClick={() => setProgress(Math.min(100, progress + 10))}>+10</Button>
1404
+ <span className="text-sm self-center">{progress}%</span>
1405
+ </div>
1406
+ </CardContent>
1407
+ </Card>
1408
+
1409
+ {/* Skeleton */}
1410
+ <Card>
1411
+ <CardHeader><CardTitle>Skeleton</CardTitle></CardHeader>
1412
+ <CardContent className="space-y-2">
1413
+ <div className="flex items-center gap-3">
1414
+ <Skeleton className="h-10 w-10 rounded-full" />
1415
+ <div className="space-y-1 flex-1">
1416
+ <Skeleton className="h-4 w-full" />
1417
+ <Skeleton className="h-4 w-2/3" />
1418
+ </div>
1419
+ </div>
1420
+ </CardContent>
1421
+ </Card>
1422
+
1423
+ {/* Tabs */}
1424
+ <Card>
1425
+ <CardHeader><CardTitle>Tabs</CardTitle></CardHeader>
1426
+ <CardContent>
1427
+ <Tabs defaultValue="tab1">
1428
+ <TabsList>
1429
+ <TabsTrigger value="tab1">Tab One</TabsTrigger>
1430
+ <TabsTrigger value="tab2">Tab Two</TabsTrigger>
1431
+ <TabsTrigger value="tab3">Tab Three</TabsTrigger>
1432
+ </TabsList>
1433
+ <TabsContent value="tab1"><p className="mt-2 text-sm">Content for Tab One.</p></TabsContent>
1434
+ <TabsContent value="tab2"><p className="mt-2 text-sm">Content for Tab Two.</p></TabsContent>
1435
+ <TabsContent value="tab3"><p className="mt-2 text-sm">Content for Tab Three.</p></TabsContent>
1436
+ </Tabs>
1437
+ </CardContent>
1438
+ </Card>
1439
+
1440
+ {/* Table */}
1441
+ <Card>
1442
+ <CardHeader><CardTitle>Table</CardTitle></CardHeader>
1443
+ <CardContent>
1444
+ <Table>
1445
+ <TableHeader>
1446
+ <TableRow>
1447
+ <TableHead>#</TableHead>
1448
+ <TableHead>Name</TableHead>
1449
+ <TableHead>Role</TableHead>
1450
+ <TableHead>Status</TableHead>
1451
+ </TableRow>
1452
+ </TableHeader>
1453
+ <TableBody>
1454
+ {sampleRows.map((r) => (
1455
+ <TableRow key={r.id}>
1456
+ <TableCell>{r.id}</TableCell>
1457
+ <TableCell>{r.name}</TableCell>
1458
+ <TableCell>{r.role}</TableCell>
1459
+ <TableCell>
1460
+ <Badge variant={r.status === "Active" ? "default" : "secondary"}>{r.status}</Badge>
1461
+ </TableCell>
1462
+ </TableRow>
1463
+ ))}
1464
+ </TableBody>
1465
+ </Table>
1466
+ </CardContent>
1467
+ </Card>
1468
+
1469
+ {/* Dialog */}
1470
+ <Card>
1471
+ <CardHeader><CardTitle>Dialog</CardTitle></CardHeader>
1472
+ <CardContent>
1473
+ <Button onClick={() => setDialogOpen(true)}>Open Dialog</Button>
1474
+ <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
1475
+ <DialogContent>
1476
+ <DialogHeader>
1477
+ <DialogTitle>shadcn Dialog</DialogTitle>
1478
+ <DialogDescription>This is a modal dialog from shadcn/ui.</DialogDescription>
1479
+ </DialogHeader>
1480
+ <p className="text-sm">Dialog content goes here.</p>
1481
+ <Button className="mt-4" onClick={() => setDialogOpen(false)}>Close</Button>
1482
+ </DialogContent>
1483
+ </Dialog>
1484
+ </CardContent>
1485
+ </Card>
1486
+
1487
+ {/* Sheet */}
1488
+ <Card>
1489
+ <CardHeader><CardTitle>Sheet</CardTitle></CardHeader>
1490
+ <CardContent>
1491
+ <Sheet>
1492
+ <SheetTrigger asChild>
1493
+ <Button variant="outline">Open Sheet</Button>
1494
+ </SheetTrigger>
1495
+ <SheetContent>
1496
+ <SheetHeader>
1497
+ <SheetTitle>Side Sheet</SheetTitle>
1498
+ </SheetHeader>
1499
+ <p className="mt-4 text-sm">Sheet content from shadcn/ui.</p>
1500
+ </SheetContent>
1501
+ </Sheet>
1502
+ </CardContent>
1503
+ </Card>
1504
+
1505
+ {/* Tooltip */}
1506
+ <Card>
1507
+ <CardHeader><CardTitle>Tooltip</CardTitle></CardHeader>
1508
+ <CardContent>
1509
+ <TooltipProvider>
1510
+ <Tooltip>
1511
+ <TooltipTrigger asChild>
1512
+ <Button variant="outline">Hover me</Button>
1513
+ </TooltipTrigger>
1514
+ <TooltipContent>
1515
+ <p>This is a shadcn Tooltip</p>
1516
+ </TooltipContent>
1517
+ </Tooltip>
1518
+ </TooltipProvider>
1519
+ </CardContent>
1520
+ </Card>
1521
+
1522
+ {/* Toast */}
1523
+ <Card>
1524
+ <CardHeader><CardTitle>Toast (Sonner)</CardTitle></CardHeader>
1525
+ <CardContent className="flex flex-wrap gap-2">
1526
+ <Button onClick={() => toast.success("Success toast!")}>Success</Button>
1527
+ <Button variant="destructive" onClick={() => toast.error("Error toast!")}>Error</Button>
1528
+ <Button variant="outline" onClick={() => toast.info("Info toast!")}>Info</Button>
1529
+ <Button variant="secondary" onClick={() => toast.warning("Warning toast!")}>Warning</Button>
1530
+ </CardContent>
1531
+ </Card>
1532
+
1533
+ <div className="flex justify-center pt-4">
1534
+ <a href="/" className="text-sm text-blue-600 hover:underline">&larr; Back to Home</a>
1535
+ </div>
1536
+ </div>
1537
+ );
1538
+ }
1539
+ `);
1540
+
1018
1541
  // -------------------------------
1019
1542
  // Layout Components
1020
1543
  // -------------------------------
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-bdpa-react-scaffold",
3
- "version": "1.9.0",
4
- "description": "Scaffold a React + Tailwind UI library demo via Vite.",
3
+ "version": "2.0.2",
4
+ "description": "Scaffold a React + Tailwind + shadcn/ui component demo via Vite.",
5
5
  "bin": {
6
6
  "create-bdpa-react-scaffold": "create-ui-lib.js"
7
7
  },