create-bdpa-react-scaffold 1.8.9 → 1.9.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.
Binary file
package/create-ui-lib.js CHANGED
@@ -375,6 +375,7 @@ write("index.html", `
375
375
  <html lang="en">
376
376
  <head>
377
377
  <meta charset="UTF-8" />
378
+ <link rel="icon" type="image/png" href="/BDPA_edited.png" />
378
379
  <title>BDPA React Scaffold and Demo</title>
379
380
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
380
381
  </head>
@@ -396,7 +397,7 @@ write("HOWTO.md", `
396
397
  // src/pages/Dashboard.jsx
397
398
  import React from "react";
398
399
  import Container from "../components/layout/Container";
399
- import Card from "../components/ui/Card";
400
+ import { Card, CardContent } from "@/components/ui/card";
400
401
 
401
402
  export default function Dashboard() {
402
403
  return (
@@ -628,14 +629,13 @@ import ReactDOM from "react-dom/client";
628
629
  import { BrowserRouter } from "react-router-dom";
629
630
  import App from "./App.jsx";
630
631
  import "./index.css";
631
- import { ToastProvider } from "./components/ui/ToastProvider.jsx";
632
+ import { Toaster } from "@/components/ui/sonner";
632
633
 
633
634
  ReactDOM.createRoot(document.getElementById("root")).render(
634
635
  <React.StrictMode>
635
636
  <BrowserRouter>
636
- <ToastProvider>
637
- <App />
638
- </ToastProvider>
637
+ <App />
638
+ <Toaster />
639
639
  </BrowserRouter>
640
640
  </React.StrictMode>
641
641
  );
@@ -657,15 +657,6 @@ export function cn(...inputs) {
657
657
 
658
658
  write("src/index.js", `
659
659
  export { Button } from "./components/ui/button.jsx";
660
- export { default as Card } from "./components/ui/Card.jsx";
661
- export { default as Input } from "./components/ui/Input.jsx";
662
- export { default as FormField } from "./components/ui/FormField.jsx";
663
- export { default as Table } from "./components/ui/Table.jsx";
664
- export { default as Navbar } from "./components/ui/Navbar.jsx";
665
- export { default as Sidebar } from "./components/ui/Sidebar.jsx";
666
- export { default as Modal } from "./components/ui/Modal.jsx";
667
- export { default as Tabs } from "./components/ui/Tabs.jsx";
668
- export { ToastProvider, useToast } from "./components/ui/ToastProvider.jsx";
669
660
 
670
661
  export { default as Login } from "./pages/auth/Login.jsx";
671
662
  export { default as Register } from "./pages/auth/Register.jsx";
@@ -680,41 +671,31 @@ export { hashPassword, verifyPassword, getPasswordStrength, getPasswordStrengthL
680
671
  write("src/App.jsx", `
681
672
  import { useState } from "react";
682
673
  import { Routes, Route, useNavigate } from "react-router-dom";
683
- import {
684
- Button,
685
- Card,
686
- Input,
687
- FormField,
688
- Table,
689
- Navbar,
690
- Sidebar,
691
- Modal,
692
- Tabs,
693
- ApiClient,
694
- useToast,
695
- Login,
696
- Register
697
- } from "./index.js";
698
-
699
- const columns = [
700
- { key: "name", label: "Student" },
701
- { key: "course", label: "Course" },
702
- { key: "status", label: "Status" }
703
- ];
704
-
705
- const data = [
674
+ import { Button } from "@/components/ui/button";
675
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
676
+ import { Input } from "@/components/ui/input";
677
+ import { Label } from "@/components/ui/label";
678
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
679
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
680
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
681
+ import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
682
+ 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";
687
+
688
+ const enrollmentData = [
706
689
  { name: "Alex", course: "Web Design Fundamentals", status: "Enrolled" },
707
690
  { name: "Jordan", course: "Advanced Web App Design", status: "Waitlisted" },
708
691
  { name: "Taylor", course: "eSports Strategy", status: "Enrolled" }
709
692
  ];
710
693
 
711
694
  function Dashboard() {
712
- const [sidebarOpen, setSidebarOpen] = useState(false);
713
695
  const [modalOpen, setModalOpen] = useState(false);
714
696
  const [posts, setPosts] = useState([]);
715
697
  const [loadingPosts, setLoadingPosts] = useState(false);
716
698
  const [postsError, setPostsError] = useState("");
717
- const toast = useToast();
718
699
  const navigate = useNavigate();
719
700
  const client = new ApiClient("https://jsonplaceholder.typicode.com");
720
701
 
@@ -730,129 +711,183 @@ function Dashboard() {
730
711
  setLoadingPosts(false);
731
712
  };
732
713
 
733
- const tabs = [
734
- { label: "Overview", content: <p>Welcome to the BDPA React Scaffold and Demo.</p> },
735
- { label: "Components", content: <p>Buttons, Cards, Inputs, Tables, and more.</p> },
736
- { label: "Auth", content: <p>Login + Registration pages included.</p> }
714
+ const navLinks = [
715
+ { label: "Home", href: "/" },
716
+ { label: "Login", href: "/login" },
717
+ { label: "Register", href: "/register" }
737
718
  ];
738
719
 
739
720
  return (
740
721
  <div className="flex h-screen overflow-hidden">
741
722
 
742
- {/* Sidebar */}
743
- <Sidebar
744
- open={sidebarOpen}
745
- onToggle={() => setSidebarOpen(!sidebarOpen)}
746
- links={[
747
- { label: "Home", href: "/" },
748
- { label: "Login", href: "/login" },
749
- { label: "Register", href: "/register" }
750
- ]}
751
- />
723
+ {/* Sidebar (desktop) */}
724
+ <aside className="hidden md:flex flex-col w-64 border-r bg-white">
725
+ <div className="p-4 border-b font-semibold">Menu</div>
726
+ <nav className="p-4 space-y-1">
727
+ {navLinks.map((l) => (
728
+ <a key={l.label} href={l.href} className="block px-2 py-2 rounded hover:bg-gray-100 text-sm">
729
+ {l.label}
730
+ </a>
731
+ ))}
732
+ </nav>
733
+ </aside>
752
734
 
753
735
  {/* Main content */}
754
736
  <div className="flex-1 flex flex-col">
755
737
 
756
738
  {/* Navbar */}
757
- <Navbar onMenuClick={() => setSidebarOpen(!sidebarOpen)} />
739
+ <nav className="bg-white border-b px-4 py-3 flex items-center justify-between">
740
+ {/* Mobile sidebar trigger */}
741
+ <Sheet>
742
+ <SheetTrigger asChild>
743
+ <Button variant="ghost" size="icon" className="md:hidden">
744
+ <Menu />
745
+ </Button>
746
+ </SheetTrigger>
747
+ <SheetContent side="left" className="w-64 p-0">
748
+ <div className="p-4 border-b font-semibold">Menu</div>
749
+ <nav className="p-4 space-y-1">
750
+ {navLinks.map((l) => (
751
+ <a key={l.label} href={l.href} className="block px-2 py-2 rounded hover:bg-gray-100 text-sm">
752
+ {l.label}
753
+ </a>
754
+ ))}
755
+ </nav>
756
+ </SheetContent>
757
+ </Sheet>
758
+ <h1 className="text-xl font-bold">BDPA React Scaffold and Demo</h1>
759
+ <div />
760
+ </nav>
758
761
 
759
762
  {/* Page content */}
760
763
  <div className="p-6 space-y-6 overflow-auto">
761
764
 
762
765
  {/* BDPA Logo Section */}
763
766
  <Card className="text-center">
764
- <img
765
- src="/src/assets/images/BDPA_edited.avif"
766
- alt="BDPA Logo"
767
- className="h-32 mx-auto mb-4"
768
- />
769
- <h1 className="text-3xl font-bold text-blue-600">Welcome to BDPA</h1>
770
- <p className="text-gray-600 mt-2">Black Data Professionals Association</p>
767
+ <CardContent className="pt-6">
768
+ <img
769
+ src="/BDPA_edited.png"
770
+ alt="BDPA Logo"
771
+ className="h-32 mx-auto mb-4"
772
+ />
773
+ <h1 className="text-3xl font-bold text-blue-600">Welcome to BDPA</h1>
774
+ <p className="text-gray-600 mt-2">Black Data Professionals Association</p>
775
+ </CardContent>
771
776
  </Card>
772
777
 
773
- <Tabs tabs={tabs} />
778
+ {/* Tabs */}
779
+ <Tabs defaultValue="overview">
780
+ <TabsList>
781
+ <TabsTrigger value="overview">Overview</TabsTrigger>
782
+ <TabsTrigger value="components">Components</TabsTrigger>
783
+ <TabsTrigger value="auth">Auth</TabsTrigger>
784
+ </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>
788
+ </Tabs>
774
789
 
775
790
  <div className="grid md:grid-cols-2 gap-6">
776
791
 
777
792
  {/* Form/Card example */}
778
793
  <Card>
779
- <h2 className="text-lg font-semibold mb-4">Sample Form</h2>
780
-
781
- <div className="space-y-4">
782
- <FormField label="Student Name">
783
- <Input placeholder="e.g. Alex Johnson" />
784
- </FormField>
785
-
786
- <FormField label="Email">
787
- <Input type="email" placeholder="student@example.com" />
788
- </FormField>
789
-
790
- <FormField label="Course">
791
- <Input placeholder="Web Design Fundamentals" />
792
- </FormField>
793
-
794
+ <CardHeader><CardTitle>Sample Form</CardTitle></CardHeader>
795
+ <CardContent className="space-y-4">
796
+ <div className="space-y-1">
797
+ <Label htmlFor="s-name">Student Name</Label>
798
+ <Input id="s-name" placeholder="e.g. Alex Johnson" />
799
+ </div>
800
+ <div className="space-y-1">
801
+ <Label htmlFor="s-email">Email</Label>
802
+ <Input id="s-email" type="email" placeholder="student@example.com" />
803
+ </div>
804
+ <div className="space-y-1">
805
+ <Label htmlFor="s-course">Course</Label>
806
+ <Input id="s-course" placeholder="Web Design Fundamentals" />
807
+ </div>
794
808
  <div className="flex gap-2 pt-2">
795
809
  <Button>Save</Button>
796
810
  <Button variant="secondary">Cancel</Button>
797
811
  </div>
798
- </div>
812
+ </CardContent>
799
813
  </Card>
800
814
 
801
815
  {/* Table example */}
802
816
  <Card>
803
- <h2 className="text-lg font-semibold mb-4">Enrollment Overview</h2>
804
- <Table columns={columns} data={data} />
817
+ <CardHeader><CardTitle>Enrollment Overview</CardTitle></CardHeader>
818
+ <CardContent>
819
+ <Table>
820
+ <TableHeader>
821
+ <TableRow>
822
+ <TableHead>Student</TableHead>
823
+ <TableHead>Course</TableHead>
824
+ <TableHead>Status</TableHead>
825
+ </TableRow>
826
+ </TableHeader>
827
+ <TableBody>
828
+ {enrollmentData.map((row) => (
829
+ <TableRow key={row.name}>
830
+ <TableCell>{row.name}</TableCell>
831
+ <TableCell>{row.course}</TableCell>
832
+ <TableCell>{row.status}</TableCell>
833
+ </TableRow>
834
+ ))}
835
+ </TableBody>
836
+ </Table>
837
+ </CardContent>
805
838
  </Card>
806
839
  </div>
807
840
 
808
- {/* Buttons */}
841
+ {/* Button Variants */}
809
842
  <Card>
810
- <h2 className="text-lg font-semibold mb-4">Button Variants</h2>
811
- <div className="flex flex-wrap gap-3">
843
+ <CardHeader><CardTitle>Button Variants</CardTitle></CardHeader>
844
+ <CardContent className="flex flex-wrap gap-3">
812
845
  <Button>Primary</Button>
813
846
  <Button variant="secondary">Secondary</Button>
814
847
  <Button variant="destructive">Danger</Button>
815
848
  <Button variant="outline">Outline</Button>
816
- </div>
849
+ </CardContent>
817
850
  </Card>
818
851
 
819
852
  {/* Live API Demo */}
820
853
  <Card>
821
- <h2 className="text-lg font-semibold mb-4">Live API Demo (JSONPlaceholder)</h2>
822
- <div className="flex items-center gap-3 mb-3">
823
- <Button onClick={fetchPosts} disabled={loadingPosts}>
824
- {loadingPosts ? "Loading..." : "Fetch Posts"}
825
- </Button>
826
- {postsError && (
827
- <span className="text-sm text-red-600">{postsError}</span>
854
+ <CardHeader><CardTitle>Live API Demo (JSONPlaceholder)</CardTitle></CardHeader>
855
+ <CardContent>
856
+ <div className="flex items-center gap-3 mb-3">
857
+ <Button onClick={fetchPosts} disabled={loadingPosts}>
858
+ {loadingPosts ? "Loading..." : "Fetch Posts"}
859
+ </Button>
860
+ {postsError && <span className="text-sm text-red-600">{postsError}</span>}
861
+ </div>
862
+ {posts.length > 0 && (
863
+ <ul className="list-disc pl-6 space-y-1">
864
+ {posts.map((p) => (
865
+ <li key={p.id} className="text-sm">
866
+ <span className="font-medium">#{p.id}</span> {p.title}
867
+ </li>
868
+ ))}
869
+ </ul>
828
870
  )}
829
- </div>
830
- {posts.length > 0 && (
831
- <ul className="list-disc pl-6 space-y-1">
832
- {posts.map((p) => (
833
- <li key={p.id} className="text-sm">
834
- <span className="font-medium">#{p.id}</span> {p.title}
835
- </li>
836
- ))}
837
- </ul>
838
- )}
871
+ </CardContent>
839
872
  </Card>
840
873
 
841
- {/* Modal + Toast */}
874
+ {/* Dialog + Toast */}
842
875
  <div className="flex gap-4">
843
- <Button onClick={() => setModalOpen(true)}>Open Modal</Button>
844
- <Button onClick={() => toast.show("This is a toast!", "success")}>
876
+ <Button onClick={() => setModalOpen(true)}>Open Dialog</Button>
877
+ <Button onClick={() => toast.success("This is a toast!")}>
845
878
  Show Toast
846
879
  </Button>
847
880
  </div>
848
881
 
849
- <Modal open={modalOpen} onClose={() => setModalOpen(false)}>
850
- <h2 className="text-lg font-semibold mb-4">Modal Title</h2>
851
- <p>This is a modal example.</p>
852
- <Button className="mt-4" onClick={() => setModalOpen(false)}>
853
- Close
854
- </Button>
855
- </Modal>
882
+ <Dialog open={modalOpen} onOpenChange={setModalOpen}>
883
+ <DialogContent>
884
+ <DialogHeader>
885
+ <DialogTitle>Dialog Title</DialogTitle>
886
+ </DialogHeader>
887
+ <p className="text-sm">This is a dialog example using shadcn/ui.</p>
888
+ <Button className="mt-4" onClick={() => setModalOpen(false)}>Close</Button>
889
+ </DialogContent>
890
+ </Dialog>
856
891
 
857
892
  </div>
858
893
  </div>
@@ -893,287 +928,9 @@ export default function App() {
893
928
  }
894
929
  `);
895
930
 
896
- // -------------------------------
897
- // UI Components
898
- // -------------------------------
899
-
900
- // Note: Button component is provided by shadcn/ui (src/components/ui/button.jsx)
901
- // Installed via: npx shadcn@latest add button
902
-
903
- write("src/components/ui/Card.jsx", `
904
- export default function Card({ children, className = "" }) {
905
- return (
906
- <div
907
- className={\`bg-white shadow-sm rounded-lg p-4 md:p-6 border border-gray-200 \${className}\`}
908
- >
909
- {children}
910
- </div>
911
- );
912
- }
913
- `);
914
-
915
- write("src/components/ui/Input.jsx", `
916
- export default function Input({ label, className = "", ...props }) {
917
- return (
918
- <label className="flex flex-col gap-1 text-sm">
919
- {label && (
920
- <span className="font-medium text-gray-700">
921
- {label}
922
- </span>
923
- )}
924
- <input
925
- className={\`border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none text-sm \${className}\`}
926
- {...props}
927
- />
928
- </label>
929
- );
930
- }
931
- `);
932
-
933
- write("src/components/ui/FormField.jsx", `
934
- export default function FormField({ label, error, children, helperText }) {
935
- return (
936
- <div className="flex flex-col gap-1 text-sm">
937
- {label && (
938
- <label className="font-medium text-gray-700">
939
- {label}
940
- </label>
941
- )}
942
-
943
- {children}
944
-
945
- {helperText && !error && (
946
- <p className="text-xs text-gray-500">{helperText}</p>
947
- )}
948
-
949
- {error && (
950
- <p className="text-xs text-red-600">
951
- {error}
952
- </p>
953
- )}
954
- </div>
955
- );
956
- }
957
- `);
958
-
959
- write("src/components/ui/Table.jsx", `
960
- export default function Table({ columns, data }) {
961
- return (
962
- <div className="overflow-x-auto">
963
- <table className="min-w-full border border-gray-200 bg-white rounded-lg overflow-hidden">
964
- <thead className="bg-gray-100">
965
- <tr>
966
- {columns.map((col) => (
967
- <th
968
- key={col.key}
969
- className="px-4 py-2 text-left text-xs font-semibold text-gray-700 border-b border-gray-200"
970
- >
971
- {col.label}
972
- </th>
973
- ))}
974
- </tr>
975
- </thead>
976
-
977
- <tbody>
978
- {data.map((row, i) => (
979
- <tr
980
- key={i}
981
- className={i % 2 === 0 ? "bg-white" : "bg-gray-50"}
982
- >
983
- {columns.map((col) => (
984
- <td
985
- key={col.key}
986
- className="px-4 py-2 text-sm text-gray-800 border-b border-gray-100"
987
- >
988
- {row[col.key]}
989
- </td>
990
- ))}
991
- </tr>
992
- ))}
993
- </tbody>
994
- </table>
995
- </div>
996
- );
997
- }
998
- `);
999
-
1000
- write("src/components/ui/Navbar.jsx", `
1001
- import { Menu, ChevronDown } from "lucide-react";
1002
- import { useState } from "react";
1003
-
1004
- export default function Navbar({ onMenuClick }) {
1005
- const [dropdownOpen, setDropdownOpen] = useState(false);
1006
-
1007
- const dropdownItems = [
1008
- { label: "Profile", href: "#" },
1009
- { label: "Settings", href: "#" },
1010
- { label: "Help", href: "#" },
1011
- { label: "Feedback", href: "#" },
1012
- { label: "Logout", href: "#" }
1013
- ];
1014
-
1015
- return (
1016
- <nav className="bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between">
1017
- <button className="md:hidden" onClick={onMenuClick}>
1018
- <Menu />
1019
- </button>
1020
- <h1 className="text-xl font-bold">BDPA React Scaffold and Demo</h1>
1021
-
1022
- {/* Dropdown Menu */}
1023
- <div className="relative">
1024
- <button
1025
- onClick={() => setDropdownOpen(!dropdownOpen)}
1026
- className="flex items-center gap-2 px-3 py-2 rounded hover:bg-gray-100"
1027
- >
1028
- Menu
1029
- <ChevronDown size={18} />
1030
- </button>
1031
-
1032
- {dropdownOpen && (
1033
- <div className="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-lg shadow-lg z-50">
1034
- {dropdownItems.map((item, index) => (
1035
- <a
1036
- key={index}
1037
- href={item.href}
1038
- className="block px-4 py-2 hover:bg-gray-100 first:rounded-t-lg last:rounded-b-lg"
1039
- >
1040
- {item.label}
1041
- </a>
1042
- ))}
1043
- </div>
1044
- )}
1045
- </div>
1046
- </nav>
1047
- );
1048
- }
1049
- `);
1050
-
1051
- write("src/components/ui/Sidebar.jsx", `
1052
- import { Link } from "react-router-dom";
1053
-
1054
- export default function Sidebar({ open, onToggle, links }) {
1055
- return (
1056
- <div
1057
- className={\`
1058
- fixed md:static inset-y-0 left-0 z-40
1059
- bg-white border-r border-gray-200
1060
- h-full w-64 transform
1061
- transition-transform duration-200
1062
- \${open ? "translate-x-0" : "-translate-x-full md:translate-x-0"}
1063
- \`}
1064
- >
1065
- <div className="p-4 border-b border-gray-200 flex justify-between items-center">
1066
- <h2 className="font-semibold">Menu</h2>
1067
- <button className="md:hidden" onClick={onToggle}>✕</button>
1068
- </div>
1069
-
1070
- <ul className="p-4 space-y-2">
1071
- {links.map((l) => (
1072
- <li key={l.label}>
1073
- <Link to={l.href} className="block px-2 py-2 rounded hover:bg-gray-100">
1074
- {l.label}
1075
- </Link>
1076
- </li>
1077
- ))}
1078
- </ul>
1079
- </div>
1080
- );
1081
- }
1082
- `);
1083
-
1084
- write("src/components/ui/Modal.jsx", `
1085
- export default function Modal({ open, onClose, children }) {
1086
- if (!open) return null;
1087
-
1088
- return (
1089
- <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
1090
- <div className="bg-white rounded-lg shadow-lg p-6 w-full max-w-md relative">
1091
- <button
1092
- className="absolute top-3 right-3 text-gray-500 hover:text-gray-700"
1093
- onClick={onClose}
1094
- >
1095
-
1096
- </button>
1097
-
1098
- {children}
1099
- </div>
1100
- </div>
1101
- );
1102
- }
1103
- `);
1104
-
1105
- write("src/components/ui/Tabs.jsx", `
1106
- import { useState } from "react";
1107
-
1108
- export default function Tabs({ tabs }) {
1109
- const [active, setActive] = useState(0);
1110
-
1111
- return (
1112
- <div>
1113
- <div className="flex gap-4 border-b border-gray-200">
1114
- {tabs.map((t, i) => (
1115
- <button
1116
- key={i}
1117
- onClick={() => setActive(i)}
1118
- className={\`pb-2 text-sm font-medium \${active === i
1119
- ? "border-b-2 border-blue-600 text-blue-600"
1120
- : "text-gray-600 hover:text-gray-800"
1121
- }\`}
1122
- >
1123
- {t.label}
1124
- </button>
1125
- ))}
1126
- </div>
1127
-
1128
- <div className="mt-4">{tabs[active].content}</div>
1129
- </div>
1130
- );
1131
- }
1132
- `);
1133
-
1134
- write("src/components/ui/ToastProvider.jsx", `
1135
- import { createContext, useContext, useState } from "react";
1136
-
1137
- const ToastContext = createContext();
1138
-
1139
- export function useToast() {
1140
- return useContext(ToastContext);
1141
- }
1142
-
1143
- export function ToastProvider({ children }) {
1144
- const [toasts, setToasts] = useState([]);
1145
-
1146
- const show = (message, type = "info") => {
1147
- const id = Date.now();
1148
- setToasts((t) => [...t, { id, message, type }]);
1149
- setTimeout(() => {
1150
- setToasts((t) => t.filter((toast) => toast.id !== id));
1151
- }, 3000);
1152
- };
1153
-
1154
- return (
1155
- <ToastContext.Provider value={{ show }}>
1156
- {children}
1157
-
1158
- <div className="fixed bottom-4 right-4 space-y-3 z-50">
1159
- {toasts.map((t) => (
1160
- <div
1161
- key={t.id}
1162
- className={\`px-4 py-2 rounded-md shadow text-white \${t.type === "success"
1163
- ? "bg-green-600"
1164
- : t.type === "error"
1165
- ? "bg-red-600"
1166
- : "bg-gray-800"
1167
- }\`}
1168
- >
1169
- {t.message}
1170
- </div>
1171
- ))}
1172
- </div>
1173
- </ToastContext.Provider>
1174
- );
1175
- }
1176
- `);
931
+ // Note: All UI components (Card, Input, Form, Table, Navbar, Tabs, Toast, etc.)
932
+ // are provided by shadcn/ui — installed via installShadcn() below.
933
+ // No manual component files are written here.
1177
934
 
1178
935
  // -------------------------------
1179
936
  // Auth Components
@@ -1181,28 +938,36 @@ export function ToastProvider({ children }) {
1181
938
 
1182
939
  write("src/pages/auth/Login.jsx", `
1183
940
  import { Button } from "@/components/ui/button";
1184
- import Input from "../../components/ui/Input.jsx";
1185
- import Card from "../../components/ui/Card.jsx";
941
+ import { Input } from "@/components/ui/input";
942
+ import { Label } from "@/components/ui/label";
943
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1186
944
 
1187
945
  export default function Login({ onSubmit }) {
1188
946
  return (
1189
947
  <div className="flex items-center justify-center min-h-screen bg-gray-100">
1190
- <Card className="w-full max-w-sm space-y-4">
1191
- <h2 className="text-xl font-bold">Sign In</h2>
1192
-
1193
- <Input label="Email" type="email" placeholder="you@example.com" />
1194
- <Input label="Password" type="password" placeholder="••••••••" />
1195
-
1196
- <Button className="w-full" onClick={onSubmit}>
1197
- Sign In
1198
- </Button>
1199
-
1200
- <p className="text-sm text-center text-gray-600">
1201
- Don’t have an account?{" "}
1202
- <a href="/register" className="text-blue-600 hover:underline">
1203
- Create one
1204
- </a>
1205
- </p>
948
+ <Card className="w-full max-w-sm">
949
+ <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="••••••••" />
960
+ </div>
961
+ <Button className="w-full" onClick={onSubmit}>
962
+ Sign In
963
+ </Button>
964
+ <p className="text-sm text-center text-gray-600">
965
+ Don’t have an account?{" "}
966
+ <a href="/register" className="text-blue-600 hover:underline">
967
+ Create one
968
+ </a>
969
+ </p>
970
+ </CardContent>
1206
971
  </Card>
1207
972
  </div>
1208
973
  );
@@ -1210,29 +975,40 @@ export default function Login({ onSubmit }) {
1210
975
 
1211
976
  write("src/pages/auth/Register.jsx", `
1212
977
  import { Button } from "@/components/ui/button";
1213
- import Input from "../../components/ui/Input.jsx";
1214
- import Card from "../../components/ui/Card.jsx";
978
+ import { Input } from "@/components/ui/input";
979
+ import { Label } from "@/components/ui/label";
980
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1215
981
 
1216
982
  export default function Register({ onSubmit }) {
1217
983
  return (
1218
984
  <div className="flex items-center justify-center min-h-screen bg-gray-100">
1219
- <Card className="w-full max-w-sm space-y-4">
1220
- <h2 className="text-xl font-bold">Create Account</h2>
1221
-
1222
- <Input label="Full Name" placeholder="Your Name" />
1223
- <Input label="Email" type="email" placeholder="you@example.com" />
1224
- <Input label="Password" type="password" placeholder="" />
1225
-
1226
- <Button className="w-full" onClick={onSubmit}>
1227
- Register
1228
- </Button>
1229
-
1230
- <p className="text-sm text-center text-gray-600">
1231
- Already have an account?{" "}
1232
- <a href="/login" className="text-blue-600 hover:underline">
1233
- Sign in
1234
- </a>
1235
- </p>
985
+ <Card className="w-full max-w-sm">
986
+ <CardHeader>
987
+ <CardTitle>Create Account</CardTitle>
988
+ </CardHeader>
989
+ <CardContent className="space-y-4">
990
+ <div className="space-y-1">
991
+ <Label htmlFor="name">Full Name</Label>
992
+ <Input id="name" placeholder="Your Name" />
993
+ </div>
994
+ <div className="space-y-1">
995
+ <Label htmlFor="email">Email</Label>
996
+ <Input id="email" type="email" placeholder="you@example.com" />
997
+ </div>
998
+ <div className="space-y-1">
999
+ <Label htmlFor="password">Password</Label>
1000
+ <Input id="password" type="password" placeholder="••••••••" />
1001
+ </div>
1002
+ <Button className="w-full" onClick={onSubmit}>
1003
+ Register
1004
+ </Button>
1005
+ <p className="text-sm text-center text-gray-600">
1006
+ Already have an account?{" "}
1007
+ <a href="/login" className="text-blue-600 hover:underline">
1008
+ Sign in
1009
+ </a>
1010
+ </p>
1011
+ </CardContent>
1236
1012
  </Card>
1237
1013
  </div>
1238
1014
  );
@@ -1400,18 +1176,18 @@ console.log("\nNext steps:");
1400
1176
  console.log(" 1. npm run dev");
1401
1177
  console.log(" 3. Open http://localhost:3000 in your browser\n");
1402
1178
 
1403
- // Create assets folder structure
1404
- fs.mkdirSync(path.join(BASE_DIR, "src/assets/images"), { recursive: true });
1405
- console.log("✔ Created: src/assets/images");
1179
+ // Create public folder structure
1180
+ fs.mkdirSync(path.join(BASE_DIR, "public"), { recursive: true });
1181
+ console.log("✔ Created: public");
1406
1182
 
1407
- // Copy BDPA logo image
1408
- const bdpaImagePath = path.join(__dirname, "BDPA_edited.avif");
1409
- const bdpaDestPath = path.join(BASE_DIR, "src/assets/images/BDPA_edited.avif");
1183
+ // Copy BDPA logo image to public (used as favicon)
1184
+ const bdpaImagePath = path.join(__dirname, "BDPA_edited.png");
1185
+ const bdpaDestPath = path.join(BASE_DIR, "public/BDPA_edited.png");
1410
1186
  if (fs.existsSync(bdpaImagePath)) {
1411
1187
  fs.copyFileSync(bdpaImagePath, bdpaDestPath);
1412
- console.log("✔ Copied: src/assets/images/BDPA_edited.avif\n");
1188
+ console.log("✔ Copied: public/BDPA_edited.png\n");
1413
1189
  } else {
1414
- console.log("⚠ Warning: BDPA_edited.avif not found in package\n");
1190
+ console.log("⚠ Warning: BDPA_edited.png not found in package\n");
1415
1191
  }
1416
1192
 
1417
1193
  if (doInstall) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bdpa-react-scaffold",
3
- "version": "1.8.9",
3
+ "version": "1.9.0",
4
4
  "description": "Scaffold a React + Tailwind UI library demo via Vite.",
5
5
  "bin": {
6
6
  "create-bdpa-react-scaffold": "create-ui-lib.js"
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  "create-ui-lib.js",
10
10
  "README.md",
11
- "BDPA_edited.avif"
11
+ "BDPA_edited.png"
12
12
  ],
13
13
  "keywords": [
14
14
  "create",
package/BDPA_edited.avif DELETED
Binary file