Spaces:
Running
Running
James McCool
commited on
Commit
·
b967c2c
1
Parent(s):
68b07dd
Initial commit from LLM generated shadcn table logic
Browse files- package-lock.json +162 -0
- package.json +11 -0
- postcss.config.js +6 -0
- src/App.js +16 -15
- src/components/DataTable.jsx +96 -0
- src/components/ui/button.jsx +29 -0
- src/components/ui/table.jsx +89 -0
- src/index.css +56 -10
- src/lib/utils.js +6 -0
- tailwind.config.js +77 -0
package-lock.json
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "react-template",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"lockfileVersion": 1,
|
5 |
+
"requires": true,
|
6 |
+
"dependencies": {
|
7 |
+
"@radix-ui/react-compose-refs": {
|
8 |
+
"version": "1.1.2",
|
9 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
10 |
+
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="
|
11 |
+
},
|
12 |
+
"@radix-ui/react-slot": {
|
13 |
+
"version": "1.2.3",
|
14 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
15 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
16 |
+
"requires": {
|
17 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
18 |
+
}
|
19 |
+
},
|
20 |
+
"autoprefixer": {
|
21 |
+
"version": "10.4.21",
|
22 |
+
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
23 |
+
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
|
24 |
+
"dev": true,
|
25 |
+
"requires": {
|
26 |
+
"browserslist": "^4.24.4",
|
27 |
+
"caniuse-lite": "^1.0.30001702",
|
28 |
+
"fraction.js": "^4.3.7",
|
29 |
+
"normalize-range": "^0.1.2",
|
30 |
+
"picocolors": "^1.1.1",
|
31 |
+
"postcss-value-parser": "^4.2.0"
|
32 |
+
}
|
33 |
+
},
|
34 |
+
"browserslist": {
|
35 |
+
"version": "4.25.2",
|
36 |
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz",
|
37 |
+
"integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==",
|
38 |
+
"dev": true,
|
39 |
+
"requires": {
|
40 |
+
"caniuse-lite": "^1.0.30001733",
|
41 |
+
"electron-to-chromium": "^1.5.199",
|
42 |
+
"node-releases": "^2.0.19",
|
43 |
+
"update-browserslist-db": "^1.1.3"
|
44 |
+
}
|
45 |
+
},
|
46 |
+
"caniuse-lite": {
|
47 |
+
"version": "1.0.30001734",
|
48 |
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz",
|
49 |
+
"integrity": "sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A==",
|
50 |
+
"dev": true
|
51 |
+
},
|
52 |
+
"class-variance-authority": {
|
53 |
+
"version": "0.7.1",
|
54 |
+
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
55 |
+
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
56 |
+
"requires": {
|
57 |
+
"clsx": "^2.1.1"
|
58 |
+
}
|
59 |
+
},
|
60 |
+
"clsx": {
|
61 |
+
"version": "2.1.1",
|
62 |
+
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
63 |
+
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="
|
64 |
+
},
|
65 |
+
"electron-to-chromium": {
|
66 |
+
"version": "1.5.200",
|
67 |
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.200.tgz",
|
68 |
+
"integrity": "sha512-rFCxROw7aOe4uPTfIAx+rXv9cEcGx+buAF4npnhtTqCJk5KDFRnh3+KYj7rdVh6lsFt5/aPs+Irj9rZ33WMA7w==",
|
69 |
+
"dev": true
|
70 |
+
},
|
71 |
+
"escalade": {
|
72 |
+
"version": "3.2.0",
|
73 |
+
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
74 |
+
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
75 |
+
"dev": true
|
76 |
+
},
|
77 |
+
"fraction.js": {
|
78 |
+
"version": "4.3.7",
|
79 |
+
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
80 |
+
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
|
81 |
+
"dev": true
|
82 |
+
},
|
83 |
+
"lucide-react": {
|
84 |
+
"version": "0.539.0",
|
85 |
+
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.539.0.tgz",
|
86 |
+
"integrity": "sha512-VVISr+VF2krO91FeuCrm1rSOLACQUYVy7NQkzrOty52Y8TlTPcXcMdQFj9bYzBgXbWCiywlwSZ3Z8u6a+6bMlg=="
|
87 |
+
},
|
88 |
+
"nanoid": {
|
89 |
+
"version": "3.3.11",
|
90 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
91 |
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
92 |
+
"dev": true
|
93 |
+
},
|
94 |
+
"node-releases": {
|
95 |
+
"version": "2.0.19",
|
96 |
+
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
97 |
+
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
98 |
+
"dev": true
|
99 |
+
},
|
100 |
+
"normalize-range": {
|
101 |
+
"version": "0.1.2",
|
102 |
+
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
103 |
+
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
|
104 |
+
"dev": true
|
105 |
+
},
|
106 |
+
"picocolors": {
|
107 |
+
"version": "1.1.1",
|
108 |
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
109 |
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
110 |
+
"dev": true
|
111 |
+
},
|
112 |
+
"postcss": {
|
113 |
+
"version": "8.5.6",
|
114 |
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
115 |
+
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
116 |
+
"dev": true,
|
117 |
+
"requires": {
|
118 |
+
"nanoid": "^3.3.11",
|
119 |
+
"picocolors": "^1.1.1",
|
120 |
+
"source-map-js": "^1.2.1"
|
121 |
+
}
|
122 |
+
},
|
123 |
+
"postcss-value-parser": {
|
124 |
+
"version": "4.2.0",
|
125 |
+
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
126 |
+
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
127 |
+
"dev": true
|
128 |
+
},
|
129 |
+
"source-map-js": {
|
130 |
+
"version": "1.2.1",
|
131 |
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
132 |
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
133 |
+
"dev": true
|
134 |
+
},
|
135 |
+
"tailwind-merge": {
|
136 |
+
"version": "3.3.1",
|
137 |
+
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
|
138 |
+
"integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="
|
139 |
+
},
|
140 |
+
"tailwindcss": {
|
141 |
+
"version": "4.1.11",
|
142 |
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
|
143 |
+
"integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
|
144 |
+
"dev": true
|
145 |
+
},
|
146 |
+
"tailwindcss-animate": {
|
147 |
+
"version": "1.0.7",
|
148 |
+
"resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
|
149 |
+
"integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="
|
150 |
+
},
|
151 |
+
"update-browserslist-db": {
|
152 |
+
"version": "1.1.3",
|
153 |
+
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
154 |
+
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
|
155 |
+
"dev": true,
|
156 |
+
"requires": {
|
157 |
+
"escalade": "^3.2.0",
|
158 |
+
"picocolors": "^1.1.1"
|
159 |
+
}
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
package.json
CHANGED
@@ -3,13 +3,19 @@
|
|
3 |
"version": "0.1.0",
|
4 |
"private": true,
|
5 |
"dependencies": {
|
|
|
6 |
"@testing-library/dom": "^10.4.0",
|
7 |
"@testing-library/jest-dom": "^6.6.3",
|
8 |
"@testing-library/react": "^16.3.0",
|
9 |
"@testing-library/user-event": "^13.5.0",
|
|
|
|
|
|
|
10 |
"react": "^19.1.0",
|
11 |
"react-dom": "^19.1.0",
|
12 |
"react-scripts": "5.0.1",
|
|
|
|
|
13 |
"web-vitals": "^2.1.4"
|
14 |
},
|
15 |
"scripts": {
|
@@ -35,5 +41,10 @@
|
|
35 |
"last 1 firefox version",
|
36 |
"last 1 safari version"
|
37 |
]
|
|
|
|
|
|
|
|
|
|
|
38 |
}
|
39 |
}
|
|
|
3 |
"version": "0.1.0",
|
4 |
"private": true,
|
5 |
"dependencies": {
|
6 |
+
"@radix-ui/react-slot": "^1.2.3",
|
7 |
"@testing-library/dom": "^10.4.0",
|
8 |
"@testing-library/jest-dom": "^6.6.3",
|
9 |
"@testing-library/react": "^16.3.0",
|
10 |
"@testing-library/user-event": "^13.5.0",
|
11 |
+
"class-variance-authority": "^0.7.1",
|
12 |
+
"clsx": "^2.1.1",
|
13 |
+
"lucide-react": "^0.539.0",
|
14 |
"react": "^19.1.0",
|
15 |
"react-dom": "^19.1.0",
|
16 |
"react-scripts": "5.0.1",
|
17 |
+
"tailwind-merge": "^3.3.1",
|
18 |
+
"tailwindcss-animate": "^1.0.7",
|
19 |
"web-vitals": "^2.1.4"
|
20 |
},
|
21 |
"scripts": {
|
|
|
41 |
"last 1 firefox version",
|
42 |
"last 1 safari version"
|
43 |
]
|
44 |
+
},
|
45 |
+
"devDependencies": {
|
46 |
+
"autoprefixer": "^10.4.21",
|
47 |
+
"postcss": "^8.5.6",
|
48 |
+
"tailwindcss": "^4.1.11"
|
49 |
}
|
50 |
}
|
postcss.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {},
|
5 |
+
},
|
6 |
+
}
|
src/App.js
CHANGED
@@ -1,23 +1,24 @@
|
|
1 |
-
import
|
2 |
import './App.css';
|
|
|
3 |
|
4 |
function App() {
|
5 |
return (
|
6 |
-
<div className="
|
7 |
-
<header className="
|
8 |
-
<
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
rel="noopener noreferrer"
|
17 |
-
>
|
18 |
-
Learn React
|
19 |
-
</a>
|
20 |
</header>
|
|
|
|
|
|
|
|
|
21 |
</div>
|
22 |
);
|
23 |
}
|
|
|
1 |
+
import React from 'react';
|
2 |
import './App.css';
|
3 |
+
import DataTable from './components/DataTable';
|
4 |
|
5 |
function App() {
|
6 |
return (
|
7 |
+
<div className="min-h-screen bg-background">
|
8 |
+
<header className="border-b bg-card">
|
9 |
+
<div className="container mx-auto px-6 py-4">
|
10 |
+
<h1 className="text-3xl font-bold text-foreground">
|
11 |
+
MongoDB Data Viewer
|
12 |
+
</h1>
|
13 |
+
<p className="text-muted-foreground mt-2">
|
14 |
+
A React app with shadcn/ui styling to display MongoDB data
|
15 |
+
</p>
|
16 |
+
</div>
|
|
|
|
|
|
|
|
|
17 |
</header>
|
18 |
+
|
19 |
+
<main className="container mx-auto py-8">
|
20 |
+
<DataTable />
|
21 |
+
</main>
|
22 |
</div>
|
23 |
);
|
24 |
}
|
src/components/DataTable.jsx
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState, useEffect } from 'react';
|
2 |
+
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell, TableCaption } from './ui/table';
|
3 |
+
import { Button } from './ui/button';
|
4 |
+
|
5 |
+
const DataTable = () => {
|
6 |
+
const [data, setData] = useState([]);
|
7 |
+
const [loading, setLoading] = useState(true);
|
8 |
+
const [error, setError] = useState(null);
|
9 |
+
|
10 |
+
// Mock data for demonstration - replace with actual MongoDB data
|
11 |
+
const mockData = [
|
12 |
+
{ id: 1, name: 'John Doe', email: '[email protected]', role: 'Developer' },
|
13 |
+
{ id: 2, name: 'Jane Smith', email: '[email protected]', role: 'Designer' },
|
14 |
+
{ id: 3, name: 'Bob Johnson', email: '[email protected]', role: 'Manager' },
|
15 |
+
{ id: 4, name: 'Alice Brown', email: '[email protected]', role: 'Developer' },
|
16 |
+
{ id: 5, name: 'Charlie Wilson', email: '[email protected]', role: 'Designer' },
|
17 |
+
];
|
18 |
+
|
19 |
+
useEffect(() => {
|
20 |
+
// Simulate loading data
|
21 |
+
setTimeout(() => {
|
22 |
+
setData(mockData);
|
23 |
+
setLoading(false);
|
24 |
+
}, 1000);
|
25 |
+
}, []);
|
26 |
+
|
27 |
+
const fetchFromMongoDB = async () => {
|
28 |
+
try {
|
29 |
+
setLoading(true);
|
30 |
+
// Replace this with your actual MongoDB connection logic
|
31 |
+
// const response = await fetch('/api/data');
|
32 |
+
// const result = await response.json();
|
33 |
+
// setData(result);
|
34 |
+
|
35 |
+
// For now, using mock data
|
36 |
+
setData(mockData);
|
37 |
+
} catch (err) {
|
38 |
+
setError('Failed to fetch data');
|
39 |
+
} finally {
|
40 |
+
setLoading(false);
|
41 |
+
}
|
42 |
+
};
|
43 |
+
|
44 |
+
if (loading) {
|
45 |
+
return (
|
46 |
+
<div className="flex items-center justify-center p-8">
|
47 |
+
<div className="text-lg text-muted-foreground">Loading...</div>
|
48 |
+
</div>
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
if (error) {
|
53 |
+
return (
|
54 |
+
<div className="flex items-center justify-center p-8">
|
55 |
+
<div className="text-red-500">{error}</div>
|
56 |
+
</div>
|
57 |
+
);
|
58 |
+
}
|
59 |
+
|
60 |
+
return (
|
61 |
+
<div className="w-full max-w-4xl mx-auto p-6">
|
62 |
+
<div className="flex justify-between items-center mb-6">
|
63 |
+
<h2 className="text-2xl font-bold text-foreground">User Data</h2>
|
64 |
+
<Button onClick={fetchFromMongoDB}>
|
65 |
+
Refresh Data
|
66 |
+
</Button>
|
67 |
+
</div>
|
68 |
+
|
69 |
+
<div className="border rounded-lg bg-card">
|
70 |
+
<Table>
|
71 |
+
<TableCaption>A list of users from the database.</TableCaption>
|
72 |
+
<TableHeader>
|
73 |
+
<TableRow>
|
74 |
+
<TableHead>ID</TableHead>
|
75 |
+
<TableHead>Name</TableHead>
|
76 |
+
<TableHead>Email</TableHead>
|
77 |
+
<TableHead>Role</TableHead>
|
78 |
+
</TableRow>
|
79 |
+
</TableHeader>
|
80 |
+
<TableBody>
|
81 |
+
{data.map((user) => (
|
82 |
+
<TableRow key={user.id}>
|
83 |
+
<TableCell className="font-medium">{user.id}</TableCell>
|
84 |
+
<TableCell>{user.name}</TableCell>
|
85 |
+
<TableCell>{user.email}</TableCell>
|
86 |
+
<TableCell>{user.role}</TableCell>
|
87 |
+
</TableRow>
|
88 |
+
))}
|
89 |
+
</TableBody>
|
90 |
+
</Table>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
);
|
94 |
+
};
|
95 |
+
|
96 |
+
export default DataTable;
|
src/components/ui/button.jsx
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as React from "react"
|
2 |
+
import { Slot } from "@radix-ui/react-slot"
|
3 |
+
import { cn } from "../../lib/utils"
|
4 |
+
|
5 |
+
const buttonVariants = cn(
|
6 |
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
7 |
+
"bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2",
|
8 |
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
9 |
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
10 |
+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
11 |
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
12 |
+
"hover:bg-accent hover:text-accent-foreground",
|
13 |
+
"h-9 w-9 p-0",
|
14 |
+
"h-11 w-11"
|
15 |
+
)
|
16 |
+
|
17 |
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
18 |
+
const Comp = asChild ? Slot : "button"
|
19 |
+
return (
|
20 |
+
<Comp
|
21 |
+
className={cn(buttonVariants, className)}
|
22 |
+
ref={ref}
|
23 |
+
{...props}
|
24 |
+
/>
|
25 |
+
)
|
26 |
+
})
|
27 |
+
Button.displayName = "Button"
|
28 |
+
|
29 |
+
export { Button }
|
src/components/ui/table.jsx
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as React from "react"
|
2 |
+
import { cn } from "../../lib/utils"
|
3 |
+
|
4 |
+
const Table = React.forwardRef(({ className, ...props }, ref) => (
|
5 |
+
<div className="relative w-full overflow-auto">
|
6 |
+
<table
|
7 |
+
ref={ref}
|
8 |
+
className={cn("w-full caption-bottom text-sm", className)}
|
9 |
+
{...props}
|
10 |
+
/>
|
11 |
+
</div>
|
12 |
+
))
|
13 |
+
Table.displayName = "Table"
|
14 |
+
|
15 |
+
const TableHeader = React.forwardRef(({ className, ...props }, ref) => (
|
16 |
+
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
17 |
+
))
|
18 |
+
TableHeader.displayName = "TableHeader"
|
19 |
+
|
20 |
+
const TableBody = React.forwardRef(({ className, ...props }, ref) => (
|
21 |
+
<tbody
|
22 |
+
ref={ref}
|
23 |
+
className={cn("[&_tr:last-child]:border-0", className)}
|
24 |
+
{...props}
|
25 |
+
/>
|
26 |
+
))
|
27 |
+
TableBody.displayName = "TableBody"
|
28 |
+
|
29 |
+
const TableFooter = React.forwardRef(({ className, ...props }, ref) => (
|
30 |
+
<tfoot
|
31 |
+
ref={ref}
|
32 |
+
className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)}
|
33 |
+
{...props}
|
34 |
+
/>
|
35 |
+
))
|
36 |
+
TableFooter.displayName = "TableFooter"
|
37 |
+
|
38 |
+
const TableRow = React.forwardRef(({ className, ...props }, ref) => (
|
39 |
+
<tr
|
40 |
+
ref={ref}
|
41 |
+
className={cn(
|
42 |
+
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
43 |
+
className
|
44 |
+
)}
|
45 |
+
{...props}
|
46 |
+
/>
|
47 |
+
))
|
48 |
+
TableRow.displayName = "TableRow"
|
49 |
+
|
50 |
+
const TableHead = React.forwardRef(({ className, ...props }, ref) => (
|
51 |
+
<th
|
52 |
+
ref={ref}
|
53 |
+
className={cn(
|
54 |
+
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
55 |
+
className
|
56 |
+
)}
|
57 |
+
{...props}
|
58 |
+
/>
|
59 |
+
))
|
60 |
+
TableHead.displayName = "TableHead"
|
61 |
+
|
62 |
+
const TableCell = React.forwardRef(({ className, ...props }, ref) => (
|
63 |
+
<td
|
64 |
+
ref={ref}
|
65 |
+
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
66 |
+
{...props}
|
67 |
+
/>
|
68 |
+
))
|
69 |
+
TableCell.displayName = "TableCell"
|
70 |
+
|
71 |
+
const TableCaption = React.forwardRef(({ className, ...props }, ref) => (
|
72 |
+
<caption
|
73 |
+
ref={ref}
|
74 |
+
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
75 |
+
{...props}
|
76 |
+
/>
|
77 |
+
))
|
78 |
+
TableCaption.displayName = "TableCaption"
|
79 |
+
|
80 |
+
export {
|
81 |
+
Table,
|
82 |
+
TableHeader,
|
83 |
+
TableBody,
|
84 |
+
TableFooter,
|
85 |
+
TableHead,
|
86 |
+
TableRow,
|
87 |
+
TableCell,
|
88 |
+
TableCaption,
|
89 |
+
}
|
src/index.css
CHANGED
@@ -1,13 +1,59 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
}
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
13 |
}
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
@layer base {
|
6 |
+
:root {
|
7 |
+
--background: 0 0% 100%;
|
8 |
+
--foreground: 222.2 84% 4.9%;
|
9 |
+
--card: 0 0% 100%;
|
10 |
+
--card-foreground: 222.2 84% 4.9%;
|
11 |
+
--popover: 0 0% 100%;
|
12 |
+
--popover-foreground: 222.2 84% 4.9%;
|
13 |
+
--primary: 222.2 47.4% 11.2%;
|
14 |
+
--primary-foreground: 210 40% 98%;
|
15 |
+
--secondary: 210 40% 96%;
|
16 |
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
17 |
+
--muted: 210 40% 96%;
|
18 |
+
--muted-foreground: 215.4 16.3% 46.9%;
|
19 |
+
--accent: 210 40% 96%;
|
20 |
+
--accent-foreground: 222.2 47.4% 11.2%;
|
21 |
+
--destructive: 0 84.2% 60.2%;
|
22 |
+
--destructive-foreground: 210 40% 98%;
|
23 |
+
--border: 214.3 31.8% 91.4%;
|
24 |
+
--input: 214.3 31.8% 91.4%;
|
25 |
+
--ring: 222.2 84% 4.9%;
|
26 |
+
--radius: 0.5rem;
|
27 |
+
}
|
28 |
+
|
29 |
+
.dark {
|
30 |
+
--background: 222.2 84% 4.9%;
|
31 |
+
--foreground: 210 40% 98%;
|
32 |
+
--card: 222.2 84% 4.9%;
|
33 |
+
--card-foreground: 210 40% 98%;
|
34 |
+
--popover: 222.2 84% 4.9%;
|
35 |
+
--popover-foreground: 210 40% 98%;
|
36 |
+
--primary: 210 40% 98%;
|
37 |
+
--primary-foreground: 222.2 47.4% 11.2%;
|
38 |
+
--secondary: 217.2 32.6% 17.5%;
|
39 |
+
--secondary-foreground: 210 40% 98%;
|
40 |
+
--muted: 217.2 32.6% 17.5%;
|
41 |
+
--muted-foreground: 215 20.2% 65.1%;
|
42 |
+
--accent: 217.2 32.6% 17.5%;
|
43 |
+
--accent-foreground: 210 40% 98%;
|
44 |
+
--destructive: 0 62.8% 30.6%;
|
45 |
+
--destructive-foreground: 210 40% 98%;
|
46 |
+
--border: 217.2 32.6% 17.5%;
|
47 |
+
--input: 217.2 32.6% 17.5%;
|
48 |
+
--ring: 212.7 26.8% 83.9%;
|
49 |
+
}
|
50 |
}
|
51 |
|
52 |
+
@layer base {
|
53 |
+
* {
|
54 |
+
@apply border-border;
|
55 |
+
}
|
56 |
+
body {
|
57 |
+
@apply bg-background text-foreground;
|
58 |
+
}
|
59 |
}
|
src/lib/utils.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { clsx } from "clsx"
|
2 |
+
import { twMerge } from "tailwind-merge"
|
3 |
+
|
4 |
+
export function cn(...inputs) {
|
5 |
+
return twMerge(clsx(inputs))
|
6 |
+
}
|
tailwind.config.js
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @type {import('tailwindcss').Config} */
|
2 |
+
module.exports = {
|
3 |
+
darkMode: ["class"],
|
4 |
+
content: [
|
5 |
+
'./pages/**/*.{js,jsx}',
|
6 |
+
'./components/**/*.{js,jsx}',
|
7 |
+
'./app/**/*.{js,jsx}',
|
8 |
+
'./src/**/*.{js,jsx}',
|
9 |
+
],
|
10 |
+
prefix: "",
|
11 |
+
theme: {
|
12 |
+
container: {
|
13 |
+
center: true,
|
14 |
+
padding: "2rem",
|
15 |
+
screens: {
|
16 |
+
"2xl": "1400px",
|
17 |
+
},
|
18 |
+
},
|
19 |
+
extend: {
|
20 |
+
colors: {
|
21 |
+
border: "hsl(var(--border))",
|
22 |
+
input: "hsl(var(--input))",
|
23 |
+
ring: "hsl(var(--ring))",
|
24 |
+
background: "hsl(var(--background))",
|
25 |
+
foreground: "hsl(var(--foreground))",
|
26 |
+
primary: {
|
27 |
+
DEFAULT: "hsl(var(--primary))",
|
28 |
+
foreground: "hsl(var(--primary-foreground))",
|
29 |
+
},
|
30 |
+
secondary: {
|
31 |
+
DEFAULT: "hsl(var(--secondary))",
|
32 |
+
foreground: "hsl(var(--secondary-foreground))",
|
33 |
+
},
|
34 |
+
destructive: {
|
35 |
+
DEFAULT: "hsl(var(--destructive))",
|
36 |
+
foreground: "hsl(var(--destructive-foreground))",
|
37 |
+
},
|
38 |
+
muted: {
|
39 |
+
DEFAULT: "hsl(var(--muted))",
|
40 |
+
foreground: "hsl(var(--muted-foreground))",
|
41 |
+
},
|
42 |
+
accent: {
|
43 |
+
DEFAULT: "hsl(var(--accent))",
|
44 |
+
foreground: "hsl(var(--accent-foreground))",
|
45 |
+
},
|
46 |
+
popover: {
|
47 |
+
DEFAULT: "hsl(var(--popover))",
|
48 |
+
foreground: "hsl(var(--popover-foreground))",
|
49 |
+
},
|
50 |
+
card: {
|
51 |
+
DEFAULT: "hsl(var(--card))",
|
52 |
+
foreground: "hsl(var(--card-foreground))",
|
53 |
+
},
|
54 |
+
},
|
55 |
+
borderRadius: {
|
56 |
+
lg: "var(--radius)",
|
57 |
+
md: "calc(var(--radius) - 2px)",
|
58 |
+
sm: "calc(var(--radius) - 4px)",
|
59 |
+
},
|
60 |
+
keyframes: {
|
61 |
+
"accordion-down": {
|
62 |
+
from: { height: "0" },
|
63 |
+
to: { height: "var(--radix-accordion-content-height)" },
|
64 |
+
},
|
65 |
+
"accordion-up": {
|
66 |
+
from: { height: "var(--radix-accordion-content-height)" },
|
67 |
+
to: { height: "0" },
|
68 |
+
},
|
69 |
+
},
|
70 |
+
animation: {
|
71 |
+
"accordion-down": "accordion-down 0.2s ease-out",
|
72 |
+
"accordion-up": "accordion-up 0.2s ease-out",
|
73 |
+
},
|
74 |
+
},
|
75 |
+
},
|
76 |
+
plugins: [require("tailwindcss-animate")],
|
77 |
+
}
|