create-template-html-css 1.1.3 → 1.2.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.
package/README.md CHANGED
@@ -26,7 +26,7 @@ A powerful CLI library to create HTML+CSS element templates. Generate styled UI
26
26
  - 🌈 **Stunning Gradients** - Colorful and attractive designs
27
27
  - ⚡ **Animations** - Smooth and professional effects
28
28
  - 🔧 **Customizable** - Easy to edit and modify the code
29
- - 📦 **7 Templates** - Button, Card, Form, Navigation, Modal, Footer, Hero
29
+ - 📦 **9 Templates** - Button, Card, Form, Navigation, Modal, Footer, Hero, Slider, Table
30
30
  - 🎯 **Two Modes** - Create new projects or insert into existing HTML pages
31
31
  - 🔒 **Secure** - Input validation and path protection
32
32
  - 📚 **Well Documented** - Comprehensive guides and examples
@@ -257,6 +257,47 @@ Hero section for landing pages:
257
257
  - Animated statistics
258
258
  - Call-to-action buttons
259
259
 
260
+ ### 8. Slider
261
+
262
+ Responsive image carousel component:
263
+
264
+ **Features:**
265
+ - Auto-play functionality
266
+ - Previous/next buttons
267
+ - Dot indicators
268
+ - Smooth fade animations
269
+ - Touch-friendly controls
270
+ - Responsive design
271
+ - Image captions
272
+ - Keyboard navigation (ESC to close)
273
+
274
+ **Includes:**
275
+ - 5 sample slides
276
+ - Navigation arrows
277
+ - Indicator dots
278
+ - Auto-advance timer
279
+
280
+ ### 9. Table
281
+
282
+ Professional data table with advanced features:
283
+
284
+ **Features:**
285
+ - Search functionality
286
+ - Status filtering
287
+ - Sortable columns
288
+ - Pagination support
289
+ - Action buttons (Edit/Delete)
290
+ - Status badges
291
+ - Responsive design
292
+ - Row selection
293
+
294
+ **Includes:**
295
+ - 6 sample employees
296
+ - Multiple columns (ID, Name, Email, Department, Status, Date)
297
+ - Search and filter controls
298
+ - Page navigation
299
+ - Color-coded status indicators
300
+
260
301
  ## 💡 Examples
261
302
 
262
303
  ### Example 1: Create a Button Component
package/bin/cli.js CHANGED
@@ -28,7 +28,9 @@ program
28
28
  { name: 'Navigation', value: 'navigation' },
29
29
  { name: 'Modal', value: 'modal' },
30
30
  { name: 'Footer', value: 'footer' },
31
- { name: 'Hero Section', value: 'hero' }
31
+ { name: 'Hero Section', value: 'hero' },
32
+ { name: 'Slider', value: 'slider' },
33
+ { name: 'Table', value: 'table' }
32
34
  ]
33
35
  },
34
36
  {
@@ -97,7 +99,9 @@ program
97
99
  { name: 'Navigation', value: 'navigation' },
98
100
  { name: 'Modal', value: 'modal' },
99
101
  { name: 'Footer', value: 'footer' },
100
- { name: 'Hero Section', value: 'hero' }
102
+ { name: 'Hero Section', value: 'hero' },
103
+ { name: 'Slider', value: 'slider' },
104
+ { name: 'Table', value: 'table' }
101
105
  ]
102
106
  },
103
107
  {
@@ -141,13 +145,15 @@ program
141
145
  .description('List all available templates')
142
146
  .action(() => {
143
147
  console.log(chalk.blue('\nAvailable templates:\n'));
144
- console.log(' • Button - Styled button component');
148
+ n console.log(' • Button - Styled button component');
145
149
  console.log(' • Card - Card component with image and content');
146
150
  console.log(' • Form - Form with input fields');
147
151
  console.log(' • Navigation - Navigation bar');
148
152
  console.log(' • Modal - Modal dialog');
149
153
  console.log(' • Footer - Footer section');
150
154
  console.log(' • Hero - Hero section with CTA');
155
+ console.log(' • Slider - Image carousel with navigation');
156
+ console.log(' • Table - Data table with search and filtering');
151
157
  console.log('');
152
158
  });
153
159
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-template-html-css",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "CLI tool to generate HTML and CSS templates for common UI elements",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/generator.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs').promises;
2
2
  const path = require('path');
3
3
 
4
4
  // Security: Validate component name against whitelist
5
- const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero'];
5
+ const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero', 'slider', 'table'];
6
6
 
7
7
  // Security: Sanitize filename to prevent path traversal
8
8
  function sanitizeFilename(filename) {
@@ -0,0 +1,59 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{name}} - Slider Component</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <h1>Image Slider</h1>
12
+ <p class="subtitle">Beautiful and responsive image carousel</p>
13
+
14
+ <div class="slider-wrapper">
15
+ <div class="slider">
16
+ <div class="slide fade">
17
+ <img src="https://via.placeholder.com/800x400?text=Slide+1" alt="Slide 1">
18
+ <div class="slide-caption">Slide 1 - Amazing View</div>
19
+ </div>
20
+
21
+ <div class="slide fade">
22
+ <img src="https://via.placeholder.com/800x400?text=Slide+2" alt="Slide 2">
23
+ <div class="slide-caption">Slide 2 - Beautiful Moment</div>
24
+ </div>
25
+
26
+ <div class="slide fade">
27
+ <img src="https://via.placeholder.com/800x400?text=Slide+3" alt="Slide 3">
28
+ <div class="slide-caption">Slide 3 - Perfect Day</div>
29
+ </div>
30
+
31
+ <div class="slide fade">
32
+ <img src="https://via.placeholder.com/800x400?text=Slide+4" alt="Slide 4">
33
+ <div class="slide-caption">Slide 4 - Stunning Scene</div>
34
+ </div>
35
+
36
+ <div class="slide fade">
37
+ <img src="https://via.placeholder.com/800x400?text=Slide+5" alt="Slide 5">
38
+ <div class="slide-caption">Slide 5 - Breathtaking View</div>
39
+ </div>
40
+ </div>
41
+
42
+ <!-- Navigation buttons -->
43
+ <button class="prev" onclick="changeSlide(-1)">&#10094;</button>
44
+ <button class="next" onclick="changeSlide(1)">&#10095;</button>
45
+ </div>
46
+
47
+ <!-- Dots for slide indicators -->
48
+ <div class="dots-container">
49
+ <span class="dot" onclick="currentSlide(1)"></span>
50
+ <span class="dot" onclick="currentSlide(2)"></span>
51
+ <span class="dot" onclick="currentSlide(3)"></span>
52
+ <span class="dot" onclick="currentSlide(4)"></span>
53
+ <span class="dot" onclick="currentSlide(5)"></span>
54
+ </div>
55
+ </div>
56
+
57
+ <script src="script.js"></script>
58
+ </body>
59
+ </html>
@@ -0,0 +1,61 @@
1
+ let slideIndex = 1;
2
+ let autoSlideTimer;
3
+
4
+ // Initialize slider
5
+ document.addEventListener('DOMContentLoaded', function() {
6
+ showSlide(slideIndex);
7
+ startAutoSlide();
8
+ });
9
+
10
+ // Next/previous controls
11
+ function changeSlide(n) {
12
+ clearTimeout(autoSlideTimer);
13
+ showSlide(slideIndex += n);
14
+ startAutoSlide();
15
+ }
16
+
17
+ // Thumbnail image controls
18
+ function currentSlide(n) {
19
+ clearTimeout(autoSlideTimer);
20
+ showSlide(slideIndex = n);
21
+ startAutoSlide();
22
+ }
23
+
24
+ // Display slide
25
+ function showSlide(n) {
26
+ const slides = document.querySelectorAll('.slide');
27
+ const dots = document.querySelectorAll('.dot');
28
+
29
+ // Wrap around
30
+ if (n > slides.length) {
31
+ slideIndex = 1;
32
+ }
33
+ if (n < 1) {
34
+ slideIndex = slides.length;
35
+ }
36
+
37
+ // Remove active class from all slides and dots
38
+ slides.forEach(slide => slide.classList.remove('active'));
39
+ dots.forEach(dot => dot.classList.remove('active'));
40
+
41
+ // Add active class to current slide and dot
42
+ slides[slideIndex - 1].classList.add('active');
43
+ dots[slideIndex - 1].classList.add('active');
44
+ }
45
+
46
+ // Auto slide every 5 seconds
47
+ function startAutoSlide() {
48
+ autoSlideTimer = setTimeout(() => {
49
+ slideIndex++;
50
+ showSlide(slideIndex);
51
+ startAutoSlide();
52
+ }, 5000);
53
+ }
54
+
55
+ // Stop auto slide on user interaction
56
+ document.addEventListener('click', function(e) {
57
+ if (e.target.classList.contains('slide') || e.target.classList.contains('dot')) {
58
+ clearTimeout(autoSlideTimer);
59
+ startAutoSlide();
60
+ }
61
+ });
@@ -0,0 +1,197 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ min-height: 100vh;
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ padding: 20px;
15
+ }
16
+
17
+ .container {
18
+ text-align: center;
19
+ width: 100%;
20
+ max-width: 900px;
21
+ }
22
+
23
+ h1 {
24
+ font-size: 2.5rem;
25
+ margin-bottom: 10px;
26
+ color: white;
27
+ }
28
+
29
+ .subtitle {
30
+ font-size: 1.2rem;
31
+ margin-bottom: 30px;
32
+ color: rgba(255, 255, 255, 0.9);
33
+ }
34
+
35
+ .slider-wrapper {
36
+ position: relative;
37
+ max-width: 800px;
38
+ margin: 0 auto 30px;
39
+ overflow: hidden;
40
+ border-radius: 15px;
41
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
42
+ background: white;
43
+ }
44
+
45
+ .slider {
46
+ position: relative;
47
+ width: 100%;
48
+ overflow: hidden;
49
+ }
50
+
51
+ .slide {
52
+ display: none;
53
+ width: 100%;
54
+ position: relative;
55
+ }
56
+
57
+ .slide img {
58
+ width: 100%;
59
+ height: auto;
60
+ display: block;
61
+ }
62
+
63
+ .slide.active {
64
+ display: block;
65
+ }
66
+
67
+ .slide-caption {
68
+ position: absolute;
69
+ bottom: 0;
70
+ left: 0;
71
+ right: 0;
72
+ background: rgba(0, 0, 0, 0.6);
73
+ color: white;
74
+ padding: 15px;
75
+ font-size: 1.1rem;
76
+ font-weight: 600;
77
+ text-align: center;
78
+ }
79
+
80
+ /* Fade animation */
81
+ .fade {
82
+ animation: fade 1s ease-in-out;
83
+ }
84
+
85
+ @keyframes fade {
86
+ from {
87
+ opacity: 0.7;
88
+ }
89
+ to {
90
+ opacity: 1;
91
+ }
92
+ }
93
+
94
+ /* Navigation buttons */
95
+ .prev, .next {
96
+ cursor: pointer;
97
+ position: absolute;
98
+ top: 50%;
99
+ width: 50px;
100
+ height: 50px;
101
+ margin-top: -25px;
102
+ padding: 16px;
103
+ color: white;
104
+ background-color: rgba(0, 0, 0, 0.5);
105
+ font-weight: bold;
106
+ font-size: 18px;
107
+ transition: 0.3s ease;
108
+ border: none;
109
+ border-radius: 5px;
110
+ display: flex;
111
+ justify-content: center;
112
+ align-items: center;
113
+ z-index: 10;
114
+ }
115
+
116
+ .next {
117
+ right: 0;
118
+ border-radius: 5px 0 0 5px;
119
+ }
120
+
121
+ .prev {
122
+ left: 0;
123
+ border-radius: 0 5px 5px 0;
124
+ }
125
+
126
+ .prev:hover, .next:hover {
127
+ background-color: rgba(0, 0, 0, 0.8);
128
+ transform: scale(1.1);
129
+ }
130
+
131
+ /* Dots container */
132
+ .dots-container {
133
+ display: flex;
134
+ gap: 12px;
135
+ justify-content: center;
136
+ padding: 20px;
137
+ }
138
+
139
+ .dot {
140
+ cursor: pointer;
141
+ height: 15px;
142
+ width: 15px;
143
+ margin: 0 5px;
144
+ background-color: rgba(255, 255, 255, 0.5);
145
+ border-radius: 50%;
146
+ display: inline-block;
147
+ transition: background-color 0.3s ease;
148
+ border: 2px solid white;
149
+ }
150
+
151
+ .dot.active {
152
+ background-color: white;
153
+ }
154
+
155
+ .dot:hover {
156
+ background-color: rgba(255, 255, 255, 0.8);
157
+ }
158
+
159
+ /* Responsive design */
160
+ @media (max-width: 768px) {
161
+ h1 {
162
+ font-size: 2rem;
163
+ }
164
+
165
+ .subtitle {
166
+ font-size: 1rem;
167
+ }
168
+
169
+ .prev, .next {
170
+ width: 40px;
171
+ height: 40px;
172
+ margin-top: -20px;
173
+ font-size: 16px;
174
+ padding: 12px;
175
+ }
176
+
177
+ .slider-wrapper {
178
+ border-radius: 10px;
179
+ }
180
+ }
181
+
182
+ @media (max-width: 480px) {
183
+ .slide-caption {
184
+ font-size: 0.9rem;
185
+ padding: 10px;
186
+ }
187
+
188
+ .dots-container {
189
+ gap: 8px;
190
+ }
191
+
192
+ .dot {
193
+ height: 12px;
194
+ width: 12px;
195
+ margin: 0 3px;
196
+ }
197
+ }
@@ -0,0 +1,126 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{name}} - Table Component</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <h1>Data Table</h1>
12
+ <p class="subtitle">Modern and responsive data table</p>
13
+
14
+ <div class="table-controls">
15
+ <input type="text" id="searchInput" class="search-input" placeholder="Search table...">
16
+ <select id="filterSelect" class="filter-select">
17
+ <option value="">All Status</option>
18
+ <option value="active">Active</option>
19
+ <option value="inactive">Inactive</option>
20
+ <option value="pending">Pending</option>
21
+ </select>
22
+ </div>
23
+
24
+ <div class="table-wrapper">
25
+ <table class="data-table">
26
+ <thead>
27
+ <tr>
28
+ <th>ID</th>
29
+ <th>Name</th>
30
+ <th>Email</th>
31
+ <th>Department</th>
32
+ <th>Status</th>
33
+ <th>Join Date</th>
34
+ <th>Actions</th>
35
+ </tr>
36
+ </thead>
37
+ <tbody id="tableBody">
38
+ <tr>
39
+ <td>#001</td>
40
+ <td>John Anderson</td>
41
+ <td>john@example.com</td>
42
+ <td>Engineering</td>
43
+ <td><span class="status-badge active">Active</span></td>
44
+ <td>2024-01-15</td>
45
+ <td>
46
+ <button class="action-btn edit-btn">Edit</button>
47
+ <button class="action-btn delete-btn">Delete</button>
48
+ </td>
49
+ </tr>
50
+ <tr>
51
+ <td>#002</td>
52
+ <td>Sarah Johnson</td>
53
+ <td>sarah@example.com</td>
54
+ <td>Marketing</td>
55
+ <td><span class="status-badge active">Active</span></td>
56
+ <td>2024-02-20</td>
57
+ <td>
58
+ <button class="action-btn edit-btn">Edit</button>
59
+ <button class="action-btn delete-btn">Delete</button>
60
+ </td>
61
+ </tr>
62
+ <tr>
63
+ <td>#003</td>
64
+ <td>Michael Brown</td>
65
+ <td>michael@example.com</td>
66
+ <td>Sales</td>
67
+ <td><span class="status-badge pending">Pending</span></td>
68
+ <td>2024-03-10</td>
69
+ <td>
70
+ <button class="action-btn edit-btn">Edit</button>
71
+ <button class="action-btn delete-btn">Delete</button>
72
+ </td>
73
+ </tr>
74
+ <tr>
75
+ <td>#004</td>
76
+ <td>Emily Davis</td>
77
+ <td>emily@example.com</td>
78
+ <td>HR</td>
79
+ <td><span class="status-badge inactive">Inactive</span></td>
80
+ <td>2023-12-05</td>
81
+ <td>
82
+ <button class="action-btn edit-btn">Edit</button>
83
+ <button class="action-btn delete-btn">Delete</button>
84
+ </td>
85
+ </tr>
86
+ <tr>
87
+ <td>#005</td>
88
+ <td>David Wilson</td>
89
+ <td>david@example.com</td>
90
+ <td>Engineering</td>
91
+ <td><span class="status-badge active">Active</span></td>
92
+ <td>2024-01-30</td>
93
+ <td>
94
+ <button class="action-btn edit-btn">Edit</button>
95
+ <button class="action-btn delete-btn">Delete</button>
96
+ </td>
97
+ </tr>
98
+ <tr>
99
+ <td>#006</td>
100
+ <td>Lisa Martinez</td>
101
+ <td>lisa@example.com</td>
102
+ <td>Marketing</td>
103
+ <td><span class="status-badge active">Active</span></td>
104
+ <td>2024-02-14</td>
105
+ <td>
106
+ <button class="action-btn edit-btn">Edit</button>
107
+ <button class="action-btn delete-btn">Delete</button>
108
+ </td>
109
+ </tr>
110
+ </tbody>
111
+ </table>
112
+ </div>
113
+
114
+ <div class="table-footer">
115
+ <p id="rowCount">Showing 6 rows</p>
116
+ <div class="pagination">
117
+ <button class="page-btn" onclick="previousPage()">← Previous</button>
118
+ <span id="pageInfo" class="page-info">Page 1 of 1</span>
119
+ <button class="page-btn" onclick="nextPage()">Next →</button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <script src="script.js"></script>
125
+ </body>
126
+ </html>
@@ -0,0 +1,123 @@
1
+ let currentPage = 1;
2
+ const rowsPerPage = 6;
3
+ let allRows = [];
4
+ let filteredRows = [];
5
+
6
+ // Initialize table
7
+ document.addEventListener('DOMContentLoaded', function() {
8
+ allRows = Array.from(document.querySelectorAll('#tableBody tr'));
9
+ filteredRows = [...allRows];
10
+
11
+ // Add event listeners
12
+ document.getElementById('searchInput').addEventListener('keyup', filterTable);
13
+ document.getElementById('filterSelect').addEventListener('change', filterTable);
14
+
15
+ displayTable();
16
+ });
17
+
18
+ // Filter and search table
19
+ function filterTable() {
20
+ const searchInput = document.getElementById('searchInput').value.toLowerCase();
21
+ const filterSelect = document.getElementById('filterSelect').value;
22
+
23
+ filteredRows = allRows.filter(row => {
24
+ const text = row.textContent.toLowerCase();
25
+ const status = row.querySelector('.status-badge');
26
+ const statusValue = status ? status.textContent.trim().toLowerCase() : '';
27
+
28
+ // Search filter
29
+ const matchesSearch = searchInput === '' || text.includes(searchInput);
30
+
31
+ // Status filter
32
+ const matchesStatus = filterSelect === '' || statusValue === filterSelect;
33
+
34
+ return matchesSearch && matchesStatus;
35
+ });
36
+
37
+ currentPage = 1;
38
+ displayTable();
39
+ }
40
+
41
+ // Display table with pagination
42
+ function displayTable() {
43
+ const tableBody = document.getElementById('tableBody');
44
+ const start = (currentPage - 1) * rowsPerPage;
45
+ const end = start + rowsPerPage;
46
+
47
+ // Hide all rows
48
+ allRows.forEach(row => row.classList.add('hidden'));
49
+
50
+ // Show filtered rows
51
+ const visibleRows = filteredRows.slice(start, end);
52
+ visibleRows.forEach(row => row.classList.remove('hidden'));
53
+
54
+ // Update footer
55
+ updateFooter();
56
+ }
57
+
58
+ // Update table footer
59
+ function updateFooter() {
60
+ const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
61
+ const startRow = (currentPage - 1) * rowsPerPage + 1;
62
+ const endRow = Math.min(currentPage * rowsPerPage, filteredRows.length);
63
+
64
+ document.getElementById('rowCount').textContent =
65
+ `Showing ${filteredRows.length === 0 ? 0 : startRow} to ${endRow} of ${filteredRows.length} rows`;
66
+
67
+ document.getElementById('pageInfo').textContent =
68
+ `Page ${filteredRows.length === 0 ? 0 : currentPage} of ${totalPages || 1}`;
69
+
70
+ // Disable/enable pagination buttons
71
+ document.querySelectorAll('.page-btn').forEach(btn => {
72
+ btn.disabled = filteredRows.length === 0;
73
+ });
74
+
75
+ if (btn.textContent.includes('Previous')) {
76
+ btn.disabled = currentPage === 1 || filteredRows.length === 0;
77
+ }
78
+ if (btn.textContent.includes('Next')) {
79
+ btn.disabled = currentPage >= totalPages || filteredRows.length === 0;
80
+ }
81
+ }
82
+
83
+ // Navigation
84
+ function previousPage() {
85
+ if (currentPage > 1) {
86
+ currentPage--;
87
+ displayTable();
88
+ window.scrollTo({ top: 0, behavior: 'smooth' });
89
+ }
90
+ }
91
+
92
+ function nextPage() {
93
+ const totalPages = Math.ceil(filteredRows.length / rowsPerPage);
94
+ if (currentPage < totalPages) {
95
+ currentPage++;
96
+ displayTable();
97
+ window.scrollTo({ top: 0, behavior: 'smooth' });
98
+ }
99
+ }
100
+
101
+ // Button actions
102
+ document.addEventListener('click', function(e) {
103
+ if (e.target.classList.contains('edit-btn')) {
104
+ const row = e.target.closest('tr');
105
+ const id = row.cells[0].textContent;
106
+ alert(`Edit row: ${id}`);
107
+ }
108
+
109
+ if (e.target.classList.contains('delete-btn')) {
110
+ const row = e.target.closest('tr');
111
+ const id = row.cells[0].textContent;
112
+ if (confirm(`Delete row: ${id}?`)) {
113
+ // Remove from allRows
114
+ const index = allRows.indexOf(row);
115
+ if (index > -1) {
116
+ allRows.splice(index, 1);
117
+ }
118
+ // Re-filter
119
+ filterTable();
120
+ alert('Row deleted successfully!');
121
+ }
122
+ }
123
+ });
@@ -0,0 +1,314 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ min-height: 100vh;
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ padding: 20px;
15
+ }
16
+
17
+ .container {
18
+ width: 100%;
19
+ max-width: 1200px;
20
+ background: white;
21
+ border-radius: 15px;
22
+ padding: 30px;
23
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
24
+ }
25
+
26
+ h1 {
27
+ font-size: 2.2rem;
28
+ margin-bottom: 10px;
29
+ color: #333;
30
+ }
31
+
32
+ .subtitle {
33
+ font-size: 1rem;
34
+ color: #666;
35
+ margin-bottom: 25px;
36
+ }
37
+
38
+ /* Table Controls */
39
+ .table-controls {
40
+ display: flex;
41
+ gap: 15px;
42
+ margin-bottom: 25px;
43
+ flex-wrap: wrap;
44
+ }
45
+
46
+ .search-input,
47
+ .filter-select {
48
+ padding: 12px 15px;
49
+ border: 2px solid #e0e0e0;
50
+ border-radius: 8px;
51
+ font-size: 14px;
52
+ transition: all 0.3s ease;
53
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
54
+ }
55
+
56
+ .search-input {
57
+ flex: 1;
58
+ min-width: 200px;
59
+ }
60
+
61
+ .filter-select {
62
+ min-width: 150px;
63
+ cursor: pointer;
64
+ }
65
+
66
+ .search-input:focus,
67
+ .filter-select:focus {
68
+ outline: none;
69
+ border-color: #667eea;
70
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
71
+ }
72
+
73
+ /* Table Wrapper */
74
+ .table-wrapper {
75
+ overflow-x: auto;
76
+ margin-bottom: 20px;
77
+ border-radius: 10px;
78
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
79
+ }
80
+
81
+ .data-table {
82
+ width: 100%;
83
+ border-collapse: collapse;
84
+ background: white;
85
+ }
86
+
87
+ .data-table thead {
88
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
89
+ color: white;
90
+ }
91
+
92
+ .data-table th {
93
+ padding: 16px;
94
+ text-align: left;
95
+ font-weight: 600;
96
+ font-size: 0.95rem;
97
+ text-transform: uppercase;
98
+ letter-spacing: 0.5px;
99
+ }
100
+
101
+ .data-table td {
102
+ padding: 14px 16px;
103
+ border-bottom: 1px solid #f0f0f0;
104
+ color: #333;
105
+ font-size: 0.95rem;
106
+ }
107
+
108
+ .data-table tbody tr {
109
+ transition: all 0.3s ease;
110
+ }
111
+
112
+ .data-table tbody tr:hover {
113
+ background-color: #f9f9f9;
114
+ }
115
+
116
+ .data-table tbody tr:last-child td {
117
+ border-bottom: none;
118
+ }
119
+
120
+ /* Status Badges */
121
+ .status-badge {
122
+ display: inline-block;
123
+ padding: 6px 12px;
124
+ border-radius: 20px;
125
+ font-size: 0.85rem;
126
+ font-weight: 600;
127
+ text-transform: uppercase;
128
+ letter-spacing: 0.5px;
129
+ }
130
+
131
+ .status-badge.active {
132
+ background-color: #d4edda;
133
+ color: #155724;
134
+ }
135
+
136
+ .status-badge.inactive {
137
+ background-color: #f8d7da;
138
+ color: #721c24;
139
+ }
140
+
141
+ .status-badge.pending {
142
+ background-color: #fff3cd;
143
+ color: #856404;
144
+ }
145
+
146
+ /* Action Buttons */
147
+ .action-btn {
148
+ padding: 6px 12px;
149
+ margin-right: 5px;
150
+ border: none;
151
+ border-radius: 5px;
152
+ font-size: 0.85rem;
153
+ font-weight: 600;
154
+ cursor: pointer;
155
+ transition: all 0.3s ease;
156
+ text-transform: uppercase;
157
+ letter-spacing: 0.5px;
158
+ }
159
+
160
+ .edit-btn {
161
+ background-color: #667eea;
162
+ color: white;
163
+ }
164
+
165
+ .edit-btn:hover {
166
+ background-color: #5568d3;
167
+ transform: translateY(-2px);
168
+ box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);
169
+ }
170
+
171
+ .delete-btn {
172
+ background-color: #dc3545;
173
+ color: white;
174
+ }
175
+
176
+ .delete-btn:hover {
177
+ background-color: #c82333;
178
+ transform: translateY(-2px);
179
+ box-shadow: 0 4px 8px rgba(220, 53, 69, 0.3);
180
+ }
181
+
182
+ /* Table Footer */
183
+ .table-footer {
184
+ display: flex;
185
+ justify-content: space-between;
186
+ align-items: center;
187
+ padding-top: 20px;
188
+ border-top: 2px solid #e0e0e0;
189
+ flex-wrap: wrap;
190
+ gap: 15px;
191
+ }
192
+
193
+ #rowCount {
194
+ color: #666;
195
+ font-weight: 500;
196
+ }
197
+
198
+ .pagination {
199
+ display: flex;
200
+ gap: 10px;
201
+ align-items: center;
202
+ }
203
+
204
+ .page-btn {
205
+ padding: 8px 15px;
206
+ background-color: #667eea;
207
+ color: white;
208
+ border: none;
209
+ border-radius: 5px;
210
+ cursor: pointer;
211
+ font-weight: 600;
212
+ transition: all 0.3s ease;
213
+ font-size: 0.9rem;
214
+ }
215
+
216
+ .page-btn:hover {
217
+ background-color: #5568d3;
218
+ transform: translateY(-2px);
219
+ box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);
220
+ }
221
+
222
+ .page-btn:disabled {
223
+ background-color: #ccc;
224
+ cursor: not-allowed;
225
+ transform: none;
226
+ }
227
+
228
+ .page-info {
229
+ color: #666;
230
+ font-weight: 500;
231
+ min-width: 100px;
232
+ text-align: center;
233
+ }
234
+
235
+ /* Hide rows */
236
+ .hidden {
237
+ display: none;
238
+ }
239
+
240
+ /* Responsive Design */
241
+ @media (max-width: 768px) {
242
+ .container {
243
+ padding: 20px;
244
+ }
245
+
246
+ h1 {
247
+ font-size: 1.8rem;
248
+ }
249
+
250
+ .table-controls {
251
+ flex-direction: column;
252
+ }
253
+
254
+ .search-input,
255
+ .filter-select {
256
+ width: 100%;
257
+ }
258
+
259
+ .data-table th,
260
+ .data-table td {
261
+ padding: 10px 8px;
262
+ font-size: 0.85rem;
263
+ }
264
+
265
+ .data-table th {
266
+ font-size: 0.8rem;
267
+ }
268
+
269
+ .action-btn {
270
+ padding: 5px 8px;
271
+ font-size: 0.75rem;
272
+ margin-right: 3px;
273
+ }
274
+
275
+ .table-footer {
276
+ justify-content: center;
277
+ flex-direction: column;
278
+ }
279
+
280
+ .pagination {
281
+ justify-content: center;
282
+ width: 100%;
283
+ }
284
+ }
285
+
286
+ @media (max-width: 480px) {
287
+ .container {
288
+ padding: 15px;
289
+ }
290
+
291
+ h1 {
292
+ font-size: 1.5rem;
293
+ }
294
+
295
+ .subtitle {
296
+ font-size: 0.9rem;
297
+ }
298
+
299
+ .data-table th,
300
+ .data-table td {
301
+ padding: 8px 5px;
302
+ font-size: 0.8rem;
303
+ }
304
+
305
+ .action-btn {
306
+ padding: 4px 6px;
307
+ font-size: 0.7rem;
308
+ }
309
+
310
+ .status-badge {
311
+ padding: 4px 8px;
312
+ font-size: 0.75rem;
313
+ }
314
+ }