recycle_bin 1.0.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.
@@ -0,0 +1,609 @@
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>