recycle_bin 1.0.0 → 1.1.1

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.
@@ -1,609 +1,849 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>RecycleBin Dashboard</title>
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <%= csrf_meta_tags %>
7
- <%= csp_meta_tag %>
8
-
9
- <style>
10
- /* Sidekiq-inspired styling */
11
- * {
12
- box-sizing: border-box;
13
- margin: 0;
14
- padding: 0;
15
- }
16
-
17
- body {
18
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
19
- font-size: 14px;
20
- line-height: 1.6;
21
- color: #333;
22
- background-color: #f8f9fa;
23
- }
24
-
25
- /* Header - Sidekiq Style */
26
- .header {
27
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
- color: white;
29
- padding: 0;
30
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
31
- }
32
-
33
- .header-content {
34
- max-width: 1200px;
35
- margin: 0 auto;
36
- display: flex;
37
- align-items: center;
38
- padding: 1rem 2rem;
39
- }
40
-
41
- .logo {
42
- font-size: 1.8rem;
43
- font-weight: bold;
44
- margin-right: 2rem;
45
- display: flex;
46
- align-items: center;
47
- gap: 0.5rem;
48
- }
49
-
50
- .logo .icon {
51
- font-size: 2rem;
52
- }
53
-
54
- .nav {
55
- display: flex;
56
- gap: 0;
57
- flex: 1;
58
- }
59
-
60
- .nav a {
61
- color: rgba(255,255,255,0.9);
62
- text-decoration: none;
63
- padding: 1rem 1.5rem;
64
- border-radius: 6px;
65
- transition: all 0.2s;
66
- font-weight: 500;
67
- position: relative;
68
- }
69
-
70
- .nav a:hover,
71
- .nav a.active {
72
- background: rgba(255,255,255,0.2);
73
- color: white;
74
- }
75
-
76
- .nav a.active::after {
77
- content: '';
78
- position: absolute;
79
- bottom: -1rem;
80
- left: 50%;
81
- transform: translateX(-50%);
82
- width: 0;
83
- height: 0;
84
- border-left: 6px solid transparent;
85
- border-right: 6px solid transparent;
86
- border-bottom: 6px solid #f8f9fa;
87
- }
88
-
89
- /* Main Container */
90
- .container {
91
- max-width: 1200px;
92
- margin: 0 auto;
93
- padding: 2rem;
94
- }
95
-
96
- /* Stats Cards - Sidekiq Style */
97
- .stats-grid {
98
- display: grid;
99
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
100
- gap: 1.5rem;
101
- margin-bottom: 2rem;
102
- }
103
-
104
- .stat-card {
105
- background: white;
106
- padding: 1.5rem;
107
- border-radius: 8px;
108
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
109
- border-left: 4px solid #667eea;
110
- transition: transform 0.2s, box-shadow 0.2s;
111
- }
112
-
113
- .stat-card:hover {
114
- transform: translateY(-2px);
115
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
116
- }
117
-
118
- .stat-number {
119
- font-size: 2rem;
120
- font-weight: bold;
121
- color: #667eea;
122
- margin-bottom: 0.5rem;
123
- }
124
-
125
- .stat-label {
126
- color: #6c757d;
127
- font-size: 0.9rem;
128
- text-transform: uppercase;
129
- letter-spacing: 0.5px;
130
- }
131
-
132
- .stat-change {
133
- font-size: 0.8rem;
134
- margin-top: 0.5rem;
135
- }
136
-
137
- .stat-change.positive {
138
- color: #28a745;
139
- }
140
-
141
- .stat-change.negative {
142
- color: #dc3545;
143
- }
144
-
145
- /* Main Content Card */
146
- .main-card {
147
- background: white;
148
- border-radius: 8px;
149
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
150
- overflow: hidden;
151
- }
152
-
153
- .card-header {
154
- background: #f8f9fa;
155
- padding: 1rem 1.5rem;
156
- border-bottom: 1px solid #dee2e6;
157
- display: flex;
158
- justify-content: space-between;
159
- align-items: center;
160
- }
161
-
162
- .card-title {
163
- font-size: 1.2rem;
164
- font-weight: 600;
165
- color: #495057;
166
- margin: 0;
167
- }
168
-
169
- .card-actions {
170
- display: flex;
171
- gap: 0.5rem;
172
- }
173
-
174
- /* Filters - Sidekiq Style */
175
- .filters {
176
- padding: 1rem 1.5rem;
177
- background: #f8f9fa;
178
- border-bottom: 1px solid #dee2e6;
179
- display: flex;
180
- gap: 1rem;
181
- align-items: center;
182
- flex-wrap: wrap;
183
- }
184
-
185
- .filter-group {
186
- display: flex;
187
- gap: 0.5rem;
188
- align-items: center;
189
- }
190
-
191
- .filter-label {
192
- font-weight: 500;
193
- color: #495057;
194
- }
195
-
196
- /* Buttons - Sidekiq Style */
197
- .btn {
198
- display: inline-flex;
199
- align-items: center;
200
- gap: 0.5rem;
201
- padding: 0.5rem 1rem;
202
- border: none;
203
- border-radius: 6px;
204
- text-decoration: none;
205
- cursor: pointer;
206
- font-size: 0.875rem;
207
- font-weight: 500;
208
- transition: all 0.2s;
209
- text-align: center;
210
- }
211
-
212
- .btn-primary {
213
- background: #667eea;
214
- color: white;
215
- }
216
-
217
- .btn-primary:hover {
218
- background: #5a67d8;
219
- transform: translateY(-1px);
220
- }
221
-
222
- .btn-success {
223
- background: #28a745;
224
- color: white;
225
- }
226
-
227
- .btn-success:hover {
228
- background: #218838;
229
- }
230
-
231
- .btn-danger {
232
- background: #dc3545;
233
- color: white;
234
- }
235
-
236
- .btn-danger:hover {
237
- background: #c82333;
238
- }
239
-
240
- .btn-outline {
241
- background: transparent;
242
- border: 1px solid #dee2e6;
243
- color: #495057;
244
- }
245
-
246
- .btn-outline:hover {
247
- background: #f8f9fa;
248
- }
249
-
250
- .btn-sm {
251
- padding: 0.25rem 0.75rem;
252
- font-size: 0.8rem;
253
- }
254
-
255
- /* Table - Sidekiq Style */
256
- .table-container {
257
- overflow-x: auto;
258
- }
259
-
260
- .table {
261
- width: 100%;
262
- border-collapse: collapse;
263
- font-size: 0.9rem;
264
- }
265
-
266
- .table th {
267
- background: #f8f9fa;
268
- padding: 1rem;
269
- text-align: left;
270
- font-weight: 600;
271
- color: #495057;
272
- border-bottom: 2px solid #dee2e6;
273
- position: sticky;
274
- top: 0;
275
- }
276
-
277
- .table td {
278
- padding: 1rem;
279
- border-bottom: 1px solid #dee2e6;
280
- vertical-align: middle;
281
- }
282
-
283
- .table tr:hover {
284
- background: #f8f9fa;
285
- }
286
-
287
- /* Model Type Badge */
288
- .model-badge {
289
- display: inline-block;
290
- padding: 0.25rem 0.75rem;
291
- background: #667eea;
292
- color: white;
293
- border-radius: 12px;
294
- font-size: 0.8rem;
295
- font-weight: 500;
296
- }
297
-
298
- /* Time Stamps */
299
- .timestamp {
300
- color: #6c757d;
301
- font-size: 0.85rem;
302
- }
303
-
304
- .timestamp-relative {
305
- font-weight: 500;
306
- color: #495057;
307
- }
308
-
309
- /* Empty State */
310
- .empty-state {
311
- text-align: center;
312
- padding: 4rem 2rem;
313
- color: #6c757d;
314
- }
315
-
316
- .empty-icon {
317
- font-size: 4rem;
318
- margin-bottom: 1rem;
319
- opacity: 0.5;
320
- }
321
-
322
- .empty-title {
323
- font-size: 1.5rem;
324
- margin-bottom: 0.5rem;
325
- color: #495057;
326
- }
327
-
328
- .empty-subtitle {
329
- font-size: 1rem;
330
- margin-bottom: 2rem;
331
- }
332
-
333
- /* Bulk Actions */
334
- .bulk-actions {
335
- padding: 1rem 1.5rem;
336
- background: #fff3cd;
337
- border-bottom: 1px solid #ffeaa7;
338
- display: none;
339
- }
340
-
341
- .bulk-actions.show {
342
- display: flex;
343
- justify-content: space-between;
344
- align-items: center;
345
- }
346
-
347
- .bulk-count {
348
- font-weight: 500;
349
- color: #856404;
350
- }
351
-
352
- /* Alerts */
353
- .alert {
354
- padding: 1rem 1.5rem;
355
- margin-bottom: 1rem;
356
- border-radius: 6px;
357
- border-left: 4px solid;
358
- }
359
-
360
- .alert-success {
361
- background: #d4edda;
362
- color: #155724;
363
- border-color: #28a745;
364
- }
365
-
366
- .alert-danger {
367
- background: #f8d7da;
368
- color: #721c24;
369
- border-color: #dc3545;
370
- }
371
-
372
- .alert-info {
373
- background: #d1ecf1;
374
- color: #0c5460;
375
- border-color: #17a2b8;
376
- }
377
-
378
- /* Pagination */
379
- .pagination {
380
- display: flex;
381
- justify-content: center;
382
- align-items: center;
383
- gap: 0.5rem;
384
- padding: 2rem;
385
- }
386
-
387
- .pagination a,
388
- .pagination span {
389
- padding: 0.5rem 1rem;
390
- border: 1px solid #dee2e6;
391
- color: #667eea;
392
- text-decoration: none;
393
- border-radius: 6px;
394
- transition: all 0.2s;
395
- }
396
-
397
- .pagination a:hover {
398
- background: #667eea;
399
- color: white;
400
- }
401
-
402
- .pagination .current {
403
- background: #667eea;
404
- color: white;
405
- border-color: #667eea;
406
- }
407
-
408
- /* Responsive */
409
- @media (max-width: 768px) {
410
- .header-content {
411
- padding: 1rem;
412
- flex-direction: column;
413
- gap: 1rem;
414
- }
415
-
416
- .nav {
417
- width: 100%;
418
- justify-content: center;
419
- }
420
-
421
- .container {
422
- padding: 1rem;
423
- }
424
-
425
- .filters {
426
- flex-direction: column;
427
- align-items: flex-start;
428
- gap: 1rem;
429
- }
430
-
431
- .table th,
432
- .table td {
433
- padding: 0.5rem;
434
- }
435
-
436
- .stats-grid {
437
- grid-template-columns: repeat(2, 1fr);
438
- }
439
-
440
- .card-header {
441
- flex-direction: column;
442
- gap: 1rem;
443
- align-items: flex-start;
444
- }
445
-
446
- .card-actions {
447
- width: 100%;
448
- justify-content: flex-start;
449
- }
450
- }
451
-
452
- /* Stack table cells on very small screens */
453
- @media (max-width: 480px) {
454
- .table thead {
455
- display: none;
456
- }
457
-
458
- .table tr {
459
- display: block;
460
- margin-bottom: 1rem;
461
- background: white;
462
- border-radius: 8px;
463
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
464
- }
465
-
466
- .table td {
467
- display: block;
468
- padding: 0.5rem 1rem;
469
- border: none;
470
- border-bottom: 1px solid #f0f0f0;
471
- }
472
-
473
- .table td:before {
474
- content: attr(data-label) ": ";
475
- font-weight: bold;
476
- color: #495057;
477
- }
478
- }
479
-
480
- /* Loading States */
481
- .loading {
482
- display: inline-block;
483
- width: 20px;
484
- height: 20px;
485
- border: 3px solid #f3f3f3;
486
- border-top: 3px solid #667eea;
487
- border-radius: 50%;
488
- animation: spin 1s linear infinite;
489
- }
490
-
491
- @keyframes spin {
492
- 0% { transform: rotate(0deg); }
493
- 100% { transform: rotate(360deg); }
494
- }
495
-
496
- /* Tooltips */
497
- [data-title] {
498
- position: relative;
499
- cursor: help;
500
- }
501
-
502
- [data-title]:hover::after {
503
- content: attr(data-title);
504
- position: absolute;
505
- bottom: 125%;
506
- left: 50%;
507
- transform: translateX(-50%);
508
- background: #333;
509
- color: white;
510
- padding: 0.5rem;
511
- border-radius: 4px;
512
- font-size: 0.8rem;
513
- white-space: nowrap;
514
- z-index: 1000;
515
- }
516
- </style>
517
-
518
- <!-- Simple JavaScript for interactions -->
519
- <script>
520
- document.addEventListener('DOMContentLoaded', function() {
521
- // Bulk selection functionality
522
- const selectAllCheckbox = document.getElementById('select-all');
523
- const itemCheckboxes = document.querySelectorAll('.item-checkbox');
524
- const bulkActions = document.querySelector('.bulk-actions');
525
- const bulkCount = document.querySelector('.bulk-count');
526
-
527
- function updateBulkActions() {
528
- const checkedBoxes = document.querySelectorAll('.item-checkbox:checked');
529
- if (checkedBoxes.length > 0) {
530
- bulkActions?.classList.add('show');
531
- if (bulkCount) {
532
- bulkCount.textContent = `${checkedBoxes.length} item${checkedBoxes.length > 1 ? 's' : ''} selected`;
533
- }
534
- } else {
535
- bulkActions?.classList.remove('show');
536
- }
537
- }
538
-
539
- if (selectAllCheckbox) {
540
- selectAllCheckbox.addEventListener('change', function() {
541
- itemCheckboxes.forEach(checkbox => {
542
- checkbox.checked = this.checked;
543
- });
544
- updateBulkActions();
545
- });
546
- }
547
-
548
- itemCheckboxes.forEach(checkbox => {
549
- checkbox.addEventListener('change', updateBulkActions);
550
- });
551
-
552
- // Auto-refresh functionality
553
- let autoRefreshInterval;
554
- const autoRefreshCheckbox = document.getElementById('auto-refresh');
555
-
556
- if (autoRefreshCheckbox) {
557
- autoRefreshCheckbox.addEventListener('change', function() {
558
- if (this.checked) {
559
- autoRefreshInterval = setInterval(() => {
560
- window.location.reload();
561
- }, 5000);
562
- } else {
563
- clearInterval(autoRefreshInterval);
564
- }
565
- });
566
- }
567
-
568
- // Confirmation dialogs
569
- document.querySelectorAll('[data-confirm]').forEach(element => {
570
- element.addEventListener('click', function(e) {
571
- if (!confirm(this.dataset.confirm)) {
572
- e.preventDefault();
573
- }
574
- });
575
- });
576
- });
577
- </script>
578
- </head>
579
-
580
- <body>
581
- <div class="header">
582
- <div class="header-content">
583
- <div class="logo">
584
- <span class="icon">🗑️</span>
585
- <span>RecycleBin</span>
586
- </div>
587
-
588
- <nav class="nav">
589
- <%= link_to "Dashboard", recycle_bin.root_path,
590
- class: ("active" if current_page?(recycle_bin.root_path)) %>
591
- <%= link_to "All Items", recycle_bin.trash_index_path,
592
- class: ("active" if current_page?(recycle_bin.trash_index_path)) %>
593
- </nav>
594
- </div>
595
- </div>
596
-
597
- <div class="container">
598
- <% if notice %>
599
- <div class="alert alert-success"><%= notice %></div>
600
- <% end %>
601
-
602
- <% if alert %>
603
- <div class="alert alert-danger"><%= alert %></div>
604
- <% end %>
605
-
606
- <%= yield %>
607
- </div>
608
- </body>
609
- </html>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>RecycleBin Dashboard</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+ <style>
9
+ * {
10
+ box-sizing: border-box;
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
17
+ font-size: 14px;
18
+ line-height: 1.6;
19
+ color: #333;
20
+ background-color: #f8f9fa;
21
+ }
22
+
23
+ /* Header - Sidekiq Style */
24
+ .header {
25
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
26
+ color: white;
27
+ padding: 0;
28
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
29
+ }
30
+
31
+ .header-content {
32
+ max-width: 1200px;
33
+ margin: 0 auto;
34
+ display: flex;
35
+ align-items: center;
36
+ padding: 1rem 2rem;
37
+ }
38
+
39
+ .logo {
40
+ font-size: 1.8rem;
41
+ font-weight: bold;
42
+ margin-right: 2rem;
43
+ display: flex;
44
+ align-items: center;
45
+ gap: 0.4rem;
46
+ }
47
+
48
+ .logo-icon {
49
+ width: 80px;
50
+ height: 80px;
51
+ object-fit: contain;
52
+ }
53
+
54
+ .nav {
55
+ display: flex;
56
+ gap: 0;
57
+ flex: 1;
58
+ }
59
+
60
+ .nav a {
61
+ color: rgba(255,255,255,0.9);
62
+ text-decoration: none;
63
+ padding: 1rem 1.5rem;
64
+ border-radius: 6px;
65
+ transition: all 0.2s;
66
+ font-weight: 500;
67
+ position: relative;
68
+ }
69
+
70
+ .nav a:hover,
71
+ .nav a.active {
72
+ background: rgba(255,255,255,0.2);
73
+ color: white;
74
+ }
75
+
76
+ .nav a.active::after {
77
+ content: '';
78
+ position: absolute;
79
+ bottom: -1rem;
80
+ left: 50%;
81
+ transform: translateX(-50%);
82
+ width: 0;
83
+ height: 0;
84
+ border-left: 6px solid transparent;
85
+ border-right: 6px solid transparent;
86
+ border-bottom: 6px solid #f8f9fa;
87
+ }
88
+
89
+ /* Main Container */
90
+ .container {
91
+ max-width: 1200px;
92
+ margin: 0 auto;
93
+ padding: 2rem;
94
+ }
95
+
96
+ /* Alerts */
97
+ .alert {
98
+ padding: 1rem 1.5rem;
99
+ margin-bottom: 1rem;
100
+ border-radius: 6px;
101
+ border-left: 4px solid;
102
+ }
103
+
104
+ .alert-success {
105
+ background: #d4edda;
106
+ color: #155724;
107
+ border-color: #28a745;
108
+ }
109
+
110
+ .alert-danger {
111
+ background: #f8d7da;
112
+ color: #721c24;
113
+ border-color: #dc3545;
114
+ }
115
+
116
+ .alert-info {
117
+ background: #d1ecf1;
118
+ color: #0c5460;
119
+ border-color: #17a2b8;
120
+ }
121
+
122
+ /* Stats Cards - Sidekiq Style */
123
+ .stats-grid {
124
+ display: grid;
125
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
126
+ gap: 1.5rem;
127
+ margin-bottom: 2rem;
128
+ }
129
+
130
+ .stat-card {
131
+ background: white;
132
+ padding: 1.5rem;
133
+ border-radius: 8px;
134
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
135
+ border-left: 4px solid #667eea;
136
+ transition: transform 0.2s, box-shadow 0.2s;
137
+ }
138
+
139
+ .stat-card:hover {
140
+ transform: translateY(-2px);
141
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
142
+ }
143
+
144
+ .stat-number {
145
+ font-size: 2rem;
146
+ font-weight: bold;
147
+ color: #667eea;
148
+ margin-bottom: 0.5rem;
149
+ }
150
+
151
+ .stat-label {
152
+ color: #6c757d;
153
+ font-size: 0.9rem;
154
+ text-transform: uppercase;
155
+ letter-spacing: 0.5px;
156
+ }
157
+
158
+ .stat-change {
159
+ font-size: 0.8rem;
160
+ margin-top: 0.5rem;
161
+ }
162
+
163
+ .stat-change.positive {
164
+ color: #28a745;
165
+ }
166
+
167
+ .stat-change.negative {
168
+ color: #dc3545;
169
+ }
170
+
171
+ /* Main Content Card */
172
+ .main-card {
173
+ background: white;
174
+ border-radius: 8px;
175
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
176
+ overflow: hidden;
177
+ margin-bottom: 2rem;
178
+ }
179
+
180
+ .card-header {
181
+ background: #f8f9fa;
182
+ padding: 1rem 1.5rem;
183
+ border-bottom: 1px solid #dee2e6;
184
+ display: flex;
185
+ justify-content: space-between;
186
+ align-items: center;
187
+ }
188
+
189
+ .card-title {
190
+ font-size: 1.2rem;
191
+ font-weight: 600;
192
+ color: #495057;
193
+ margin: 0;
194
+ }
195
+
196
+ .card-actions {
197
+ display: flex;
198
+ gap: 0.5rem;
199
+ }
200
+
201
+ /* Filters - Sidekiq Style */
202
+ .filters {
203
+ padding: 1rem 1.5rem;
204
+ background: #f8f9fa;
205
+ border-bottom: 1px solid #dee2e6;
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 1rem;
209
+ align-items: flex-start;
210
+ }
211
+
212
+ .filter-section {
213
+ width: 100%;
214
+ max-width: 400px;
215
+ }
216
+
217
+ .filter-group {
218
+ display: flex;
219
+ gap: 0.5rem;
220
+ align-items: center;
221
+ width: 100%;
222
+ }
223
+
224
+ .filter-label {
225
+ font-weight: 500;
226
+ color: #495057;
227
+ min-width: 100px;
228
+ }
229
+
230
+ .form-control {
231
+ padding: 0.5rem;
232
+ border: 1px solid #dee2e6;
233
+ border-radius: 6px;
234
+ font-size: 0.875rem;
235
+ color: #495057;
236
+ background: white;
237
+ flex: 1;
238
+ max-width: 200px;
239
+ transition: border-color 0.2s;
240
+ }
241
+
242
+ .form-control:focus {
243
+ outline: none;
244
+ border-color: #667eea;
245
+ box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
246
+ }
247
+
248
+ /* Buttons - Sidekiq Style */
249
+ .btn {
250
+ display: inline-flex;
251
+ align-items: center;
252
+ gap: 0.5rem;
253
+ padding: 0.5rem 1rem;
254
+ border: none;
255
+ border-radius: 6px;
256
+ text-decoration: none;
257
+ cursor: pointer;
258
+ font-size: 0.875rem;
259
+ font-weight: 500;
260
+ transition: all 0.2s;
261
+ text-align: center;
262
+ }
263
+
264
+ .btn-primary {
265
+ background: #667eea;
266
+ color: white;
267
+ }
268
+
269
+ .btn-primary:hover {
270
+ background: #5a67d8;
271
+ transform: translateY(-1px);
272
+ }
273
+
274
+ .btn-success {
275
+ background: #28a745;
276
+ color: white;
277
+ }
278
+
279
+ .btn-success:hover {
280
+ background: #218838;
281
+ }
282
+
283
+ .btn-danger {
284
+ background: #dc3545;
285
+ color: white;
286
+ }
287
+
288
+ .btn-danger:hover {
289
+ background: #c82333;
290
+ }
291
+
292
+ .btn-outline {
293
+ background: transparent;
294
+ border: 1px solid #dee2e6;
295
+ color: #495057;
296
+ }
297
+
298
+ .btn-outline:hover {
299
+ background: #f8f9fa;
300
+ }
301
+
302
+ .btn-sm {
303
+ padding: 0.25rem 0.75rem;
304
+ font-size: 0.8rem;
305
+ }
306
+
307
+ /* Table - Sidekiq Style */
308
+ .table-container {
309
+ overflow-x: auto;
310
+ }
311
+
312
+ .table {
313
+ width: 100%;
314
+ border-collapse: collapse;
315
+ font-size: 0.9rem;
316
+ }
317
+
318
+ .table th {
319
+ background: #f8f9fa;
320
+ padding: 1rem;
321
+ text-align: left;
322
+ font-weight: 600;
323
+ color: #495057;
324
+ border-bottom: 2px solid #dee2e6;
325
+ position: sticky;
326
+ top: 0;
327
+ }
328
+
329
+ .table td {
330
+ padding: 1rem;
331
+ border-bottom: 1px solid #dee2e6;
332
+ vertical-align: middle;
333
+ }
334
+
335
+ .table tr:hover {
336
+ background: #f8f9fa;
337
+ }
338
+
339
+ /* Model Type Badge */
340
+ .model-badge {
341
+ display: inline-block;
342
+ padding: 0.25rem 0.75rem;
343
+ background: #667eea;
344
+ color: white;
345
+ border-radius: 12px;
346
+ font-size: 0.8rem;
347
+ font-weight: 500;
348
+ }
349
+
350
+ /* Time Stamps */
351
+ .timestamp {
352
+ color: #6c757d;
353
+ font-size: 0.85rem;
354
+ }
355
+
356
+ /* Empty State */
357
+ .empty-state {
358
+ text-align: center;
359
+ padding: 4rem 2rem;
360
+ color: #6c757d;
361
+ }
362
+
363
+ .empty-icon {
364
+ font-size: 4rem;
365
+ margin-bottom: 1rem;
366
+ opacity: 0.5;
367
+ }
368
+
369
+ .empty-title {
370
+ font-size: 1.5rem;
371
+ margin-bottom: 0.5rem;
372
+ color: #495057;
373
+ }
374
+
375
+ .empty-subtitle {
376
+ font-size: 1rem;
377
+ margin-bottom: 2rem;
378
+ }
379
+
380
+ /* Bulk Actions */
381
+ .bulk-actions {
382
+ padding: 1rem 1.5rem;
383
+ background: #fff3cd;
384
+ border-bottom: 1px solid #ffeaa7;
385
+ display: none;
386
+ justify-content: space-between;
387
+ align-items: center;
388
+ }
389
+
390
+ .bulk-actions.show {
391
+ display: flex;
392
+ }
393
+
394
+ .bulk-count {
395
+ font-weight: 500;
396
+ color: #856404;
397
+ }
398
+
399
+ /* Pagination */
400
+ .pagination-wrapper {
401
+ display: flex;
402
+ flex-direction: column;
403
+ align-items: center;
404
+ gap: 1rem;
405
+ padding: 2rem;
406
+ }
407
+
408
+ .pagination {
409
+ display: flex;
410
+ justify-content: center;
411
+ align-items: center;
412
+ gap: 0.5rem;
413
+ flex-wrap: wrap;
414
+ }
415
+
416
+ .pagination a,
417
+ .pagination span,
418
+ .per-page a,
419
+ .per-page span {
420
+ padding: 0.5rem 1rem;
421
+ border: 1px solid #dee2e6;
422
+ color: #667eea;
423
+ text-decoration: none;
424
+ border-radius: 6px;
425
+ transition: all 0.2s;
426
+ }
427
+
428
+ .pagination a:hover,
429
+ .per-page a:hover {
430
+ background: #667eea;
431
+ color: white;
432
+ }
433
+
434
+ .pagination .current,
435
+ .pagination span.disabled,
436
+ .per-page .current {
437
+ background: #667eea;
438
+ color: white;
439
+ border-color: #667eea;
440
+ }
441
+
442
+ .per-page {
443
+ display: flex;
444
+ align-items: center;
445
+ gap: 0.5rem;
446
+ color: #495057;
447
+ }
448
+
449
+ .per-page span {
450
+ font-size: 0.875rem;
451
+ }
452
+
453
+ .per-page-link {
454
+ /* Inherit styles from .pagination a */
455
+ }
456
+
457
+ /* Responsive */
458
+ @media (max-width: 768px) {
459
+ .header-content {
460
+ padding: 1rem;
461
+ flex-direction: column;
462
+ gap: 1rem;
463
+ }
464
+
465
+ .nav {
466
+ width: 100%;
467
+ justify-content: center;
468
+ }
469
+
470
+ .container {
471
+ padding: 1rem;
472
+ }
473
+
474
+ .filters {
475
+ flex-direction: column;
476
+ align-items: flex-start;
477
+ gap: 1rem;
478
+ }
479
+
480
+ .table th,
481
+ .table td {
482
+ padding: 0.5rem;
483
+ }
484
+
485
+ .stats-grid {
486
+ grid-template-columns: repeat(2, 1fr);
487
+ }
488
+
489
+ .card-header {
490
+ flex-direction: column;
491
+ gap: 1rem;
492
+ align-items: flex-start;
493
+ }
494
+
495
+ .card-actions {
496
+ width: 100%;
497
+ justify-content: flex-start;
498
+ }
499
+ }
500
+
501
+ @media (max-width: 480px) {
502
+ .table thead {
503
+ display: none;
504
+ }
505
+
506
+ .table tr {
507
+ display: block;
508
+ margin-bottom: 1rem;
509
+ background: white;
510
+ border-radius: 8px;
511
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
512
+ }
513
+
514
+ .table td {
515
+ display: block;
516
+ padding: 0.5rem 1rem;
517
+ border: none;
518
+ border-bottom: 1px solid #f0f0f0;
519
+ }
520
+
521
+ .table td:before {
522
+ content: attr(data-label) ": ";
523
+ font-weight: bold;
524
+ color: #495057;
525
+ }
526
+ }
527
+
528
+ /* Loading States */
529
+ .loading {
530
+ display: inline-block;
531
+ width: 20px;
532
+ height: 20px;
533
+ border: 3px solid #f3f3f3;
534
+ border-top: 3px solid #667eea;
535
+ border-radius: 50%;
536
+ animation: spin 1s linear infinite;
537
+ }
538
+
539
+ @keyframes spin {
540
+ 0% { transform: rotate(0deg); }
541
+ 100% { transform: rotate(360deg); }
542
+ }
543
+
544
+ /* Tooltips */
545
+ [data-title] {
546
+ position: relative;
547
+ cursor: help;
548
+ }
549
+
550
+ [data-title]:hover::after {
551
+ content: attr(data-title);
552
+ position: absolute;
553
+ bottom: 125%;
554
+ left: 50%;
555
+ transform: translateX(-50%);
556
+ background: #333;
557
+ color: white;
558
+ padding: 0.5rem;
559
+ border-radius: 4px;
560
+ font-size: 0.8rem;
561
+ white-space: nowrap;
562
+ z-index: 1000;
563
+ }
564
+
565
+ /* Additional Styles for Removed Inline Styles */
566
+ .checkbox-column {
567
+ width: 40px;
568
+ }
569
+
570
+ .back-link {
571
+ margin-bottom: 2rem;
572
+ }
573
+
574
+ .card-body {
575
+ padding: 1.5rem;
576
+ }
577
+
578
+ .field-column {
579
+ width: 30%;
580
+ }
581
+
582
+ .type-column {
583
+ width: 15%;
584
+ }
585
+
586
+ .hidden {
587
+ display: none;
588
+ margin-top: 2rem;
589
+ }
590
+
591
+ .boolean-true {
592
+ color: #28a745;
593
+ font-weight: 500;
594
+ }
595
+
596
+ .boolean-false {
597
+ color: #dc3545;
598
+ font-weight: 500;
599
+ }
600
+
601
+ .numeric {
602
+ font-family: monospace;
603
+ }
604
+
605
+ .pre-wrap {
606
+ white-space: pre-wrap;
607
+ font-family: monospace;
608
+ font-size: 0.85rem;
609
+ overflow-x: auto;
610
+ }
611
+
612
+ .center-content {
613
+ padding: 2rem;
614
+ text-align: center;
615
+ }
616
+
617
+ /* Styles for Associations */
618
+ .association-section {
619
+ margin-bottom: 2rem;
620
+ }
621
+
622
+ .association-grid {
623
+ display: grid;
624
+ gap: 1rem;
625
+ }
626
+
627
+ .association-item {
628
+ display: flex;
629
+ align-items: center;
630
+ padding: 1rem;
631
+ border-radius: 6px;
632
+ border-left: 3px solid #667eea;
633
+ background: #f8f9fa;
634
+ justify-content: space-between;
635
+ }
636
+
637
+ .association-content {
638
+ flex: 1;
639
+ }
640
+
641
+ .deleted-status {
642
+ color: #dc3545;
643
+ }
644
+
645
+ .deleted-badge {
646
+ background: #dc3545;
647
+ }
648
+
649
+ .active-badge {
650
+ background: #28a745;
651
+ }
652
+
653
+ /* Styles for Action History */
654
+ .event-type {
655
+ text-transform: capitalize;
656
+ font-weight: 500;
657
+ color: #667eea;
658
+ }
659
+
660
+ .changeset-details {
661
+ padding: 1rem;
662
+ background: #f8f9fa;
663
+ border-radius: 6px;
664
+ margin-top: 0.5rem;
665
+ }
666
+
667
+ .change-item {
668
+ margin-bottom: 0.5rem;
669
+ }
670
+
671
+ .change-from {
672
+ color: #6c757d;
673
+ }
674
+
675
+ .change-to {
676
+ color: #28a745;
677
+ }
678
+ </style>
679
+ </head>
680
+ <body>
681
+ <div class="header">
682
+ <div class="header-content">
683
+ <div class="logo">
684
+ <img src="https://raw.githubusercontent.com/R95-del/recycle_bin/main/docs/logo.svg"
685
+ alt="RecycleBin Logo"
686
+ class="logo-icon"
687
+ onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';">
688
+ <span class="icon-fallback" style="display:none;">🗑️</span>
689
+ <span>RecycleBin</span>
690
+ </div>
691
+
692
+ <nav class="nav">
693
+ <%= link_to "Dashboard", recycle_bin.root_path,
694
+ class: ("active" if current_page?(recycle_bin.root_path)) %>
695
+ <%= link_to "All Items", recycle_bin.trash_index_path,
696
+ class: ("active" if current_page?(recycle_bin.trash_index_path)) %>
697
+ </nav>
698
+ </div>
699
+ </div>
700
+
701
+ <div class="container">
702
+ <%= render 'recycle_bin/shared/flash_messages' %>
703
+ <%= yield %>
704
+ </div>
705
+
706
+ <script>
707
+ document.addEventListener('DOMContentLoaded', function() {
708
+ // Handle confirmation dialogs and custom method requests
709
+ document.querySelectorAll('[data-confirm], [data-method]').forEach(element => {
710
+ element.addEventListener('click', function(e) {
711
+ // Handle confirmation
712
+ if (this.dataset.confirm && !confirm(this.dataset.confirm)) {
713
+ e.preventDefault();
714
+ return;
715
+ }
716
+
717
+ // Handle custom method (e.g., PATCH, DELETE)
718
+ if (this.dataset.method) {
719
+ e.preventDefault();
720
+
721
+ const method = this.dataset.method.toUpperCase();
722
+ const url = this.href;
723
+ const form = document.createElement('form');
724
+ form.method = 'POST';
725
+ form.action = url;
726
+
727
+ const methodInput = document.createElement('input');
728
+ methodInput.type = 'hidden';
729
+ methodInput.name = '_method';
730
+ methodInput.value = method;
731
+ form.appendChild(methodInput);
732
+
733
+ const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
734
+ const csrfInput = document.createElement('input');
735
+ csrfInput.type = 'hidden';
736
+ csrfInput.name = 'authenticity_token';
737
+ csrfInput.value = csrfToken;
738
+ form.appendChild(csrfInput);
739
+
740
+ document.body.appendChild(form);
741
+ form.submit();
742
+ }
743
+ });
744
+ });
745
+
746
+ // Bulk actions and other interactivity
747
+ updateBulkActions();
748
+
749
+ document.addEventListener('click', function(e) {
750
+ if (e.target.matches('[data-copy]')) {
751
+ const text = e.target.dataset.copy;
752
+ navigator.clipboard.writeText(text).then(() => {
753
+ e.target.textContent = '✓ Copied!';
754
+ setTimeout(() => {
755
+ e.target.textContent = text;
756
+ }, 2000);
757
+ });
758
+ }
759
+ });
760
+
761
+ const autoRefreshCheckbox = document.getElementById('auto-refresh');
762
+ let autoRefreshInterval;
763
+
764
+ if (autoRefreshCheckbox) {
765
+ autoRefreshCheckbox.addEventListener('change', function() {
766
+ if (this.checked) {
767
+ autoRefreshInterval = setInterval(() => {
768
+ window.location.reload();
769
+ }, 5000);
770
+ } else {
771
+ clearInterval(autoRefreshInterval);
772
+ }
773
+ });
774
+ }
775
+ });
776
+
777
+ function toggleSelectAll() {
778
+ const selectAllCheckbox = document.getElementById('select-all');
779
+ const itemCheckboxes = document.querySelectorAll('.item-checkbox');
780
+
781
+ itemCheckboxes.forEach(checkbox => {
782
+ checkbox.checked = selectAllCheckbox.checked;
783
+ });
784
+
785
+ updateBulkActions();
786
+ }
787
+
788
+ function updateBulkActions() {
789
+ const checkedBoxes = document.querySelectorAll('.item-checkbox:checked');
790
+ const bulkActions = document.getElementById('bulk-actions');
791
+ const bulkCount = document.getElementById('bulk-count');
792
+ const selectAllCheckbox = document.getElementById('select-all');
793
+
794
+ if (checkedBoxes.length > 0) {
795
+ bulkActions.classList.add('show');
796
+ bulkCount.textContent = checkedBoxes.length + ' item' + (checkedBoxes.length > 1 ? 's' : '') + ' selected';
797
+ } else {
798
+ bulkActions.classList.remove('show');
799
+ }
800
+
801
+ if (checkedBoxes.length === itemCheckboxes.length && itemCheckboxes.length > 0) {
802
+ selectAllCheckbox.checked = true;
803
+ selectAllCheckbox.indeterminate = false;
804
+ } else if (checkedBoxes.length > 0) {
805
+ selectAllCheckbox.checked = false;
806
+ selectAllCheckbox.indeterminate = true;
807
+ } else {
808
+ selectAllCheckbox.checked = false;
809
+ selectAllCheckbox.indeterminate = false;
810
+ }
811
+ }
812
+
813
+ function handleBulkAction(action) {
814
+ const checkedBoxes = document.querySelectorAll('.item-checkbox:checked');
815
+
816
+ if (checkedBoxes.length === 0) {
817
+ alert('Please select at least one item.');
818
+ return false;
819
+ }
820
+
821
+ const selectedItems = Array.from(checkedBoxes).map(cb => cb.value);
822
+
823
+ let message;
824
+ if (action === 'restore') {
825
+ message = 'Restore ' + checkedBoxes.length + ' selected item' + (checkedBoxes.length > 1 ? 's' : '') + '?';
826
+ } else {
827
+ message = 'Permanently delete ' + checkedBoxes.length + ' selected item' + (checkedBoxes.length > 1 ? 's' : '') + '? This cannot be undone!';
828
+ }
829
+
830
+ if (!confirm(message)) {
831
+ return false;
832
+ }
833
+
834
+ if (action === 'restore') {
835
+ document.getElementById('bulk-restore-items').value = JSON.stringify(selectedItems);
836
+ } else {
837
+ document.getElementById('bulk-destroy-items').value = JSON.stringify(selectedItems);
838
+ }
839
+
840
+ return true;
841
+ }
842
+
843
+ function toggleRawData() {
844
+ const rawData = document.getElementById('raw-data');
845
+ rawData.style.display = rawData.style.display === 'none' ? 'block' : 'none';
846
+ }
847
+ </script>
848
+ </body>
849
+ </html>