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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -2
- data/Gemfile +3 -3
- data/README.md +95 -9
- data/app/controllers/recycle_bin/trash_controller.rb +120 -24
- data/app/views/{layouts/recycle_bin/application.html.erb → recycle_bin/layouts/recycle_bin.html.erb} +849 -609
- data/app/views/recycle_bin/shared/_error_messages.html.erb +10 -0
- data/app/views/recycle_bin/shared/_flash_messages.html.erb +6 -0
- data/app/views/recycle_bin/trash/_action_history.html.erb +71 -0
- data/app/views/recycle_bin/trash/_associations.html.erb +46 -0
- data/app/views/recycle_bin/trash/_filters.html.erb +17 -0
- data/app/views/recycle_bin/trash/_item.html.erb +24 -0
- data/app/views/recycle_bin/trash/_pagination.html.erb +75 -0
- data/app/views/recycle_bin/trash/_stats.html.erb +32 -0
- data/app/views/recycle_bin/trash/index.html.erb +48 -217
- data/app/views/recycle_bin/trash/show.html.erb +60 -215
- data/docs/index.html +928 -0
- data/docs/logo.svg +71 -0
- data/lib/recycle_bin/version.rb +1 -1
- data/lib/recycle_bin.rb +69 -3
- data/recycle_bin.gemspec +4 -4
- metadata +18 -14
- data/app/views/layouts/recycle_bin/recycle_bin/application.html.erb +0 -266
- data/app/views/layouts/recycle_bin/recycle_bin/trash/index.html.erb +0 -133
- data/app/views/layouts/recycle_bin/recycle_bin/trash/show.html.erb +0 -175
data/docs/index.html
ADDED
@@ -0,0 +1,928 @@
|
|
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>RecycleBin - Elegant Soft Delete for Rails</title>
|
7
|
+
<meta name="description" content="A simple and elegant soft delete solution for Rails applications with a beautiful web interface to manage your deleted records.">
|
8
|
+
|
9
|
+
<!-- Favicon -->
|
10
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🗑️</text></svg>">
|
11
|
+
|
12
|
+
<!-- Fonts -->
|
13
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
14
|
+
|
15
|
+
<!-- Syntax highlighting -->
|
16
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
|
17
|
+
|
18
|
+
<style>
|
19
|
+
:root {
|
20
|
+
--primary: #667eea;
|
21
|
+
--primary-dark: #5a67d8;
|
22
|
+
--secondary: #764ba2;
|
23
|
+
--success: #28a745;
|
24
|
+
--danger: #dc3545;
|
25
|
+
--warning: #ffc107;
|
26
|
+
--info: #17a2b8;
|
27
|
+
--light: #f8f9fa;
|
28
|
+
--dark: #343a40;
|
29
|
+
--gray-100: #f8f9fa;
|
30
|
+
--gray-200: #e9ecef;
|
31
|
+
--gray-300: #dee2e6;
|
32
|
+
--gray-400: #ced4da;
|
33
|
+
--gray-500: #adb5bd;
|
34
|
+
--gray-600: #6c757d;
|
35
|
+
--gray-700: #495057;
|
36
|
+
--gray-800: #343a40;
|
37
|
+
--gray-900: #212529;
|
38
|
+
}
|
39
|
+
|
40
|
+
* {
|
41
|
+
margin: 0;
|
42
|
+
padding: 0;
|
43
|
+
box-sizing: border-box;
|
44
|
+
}
|
45
|
+
|
46
|
+
body {
|
47
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
48
|
+
line-height: 1.6;
|
49
|
+
color: var(--gray-800);
|
50
|
+
background: #ffffff;
|
51
|
+
}
|
52
|
+
|
53
|
+
/* Header */
|
54
|
+
.header {
|
55
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
56
|
+
color: white;
|
57
|
+
padding: 1rem 0;
|
58
|
+
position: sticky;
|
59
|
+
top: 0;
|
60
|
+
z-index: 1000;
|
61
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
62
|
+
}
|
63
|
+
|
64
|
+
.nav-container {
|
65
|
+
max-width: 1200px;
|
66
|
+
margin: 0 auto;
|
67
|
+
padding: 0 2rem;
|
68
|
+
display: flex;
|
69
|
+
justify-content: space-between;
|
70
|
+
align-items: center;
|
71
|
+
}
|
72
|
+
|
73
|
+
.logo {
|
74
|
+
display: flex;
|
75
|
+
align-items: center;
|
76
|
+
gap: 0.5rem;
|
77
|
+
font-size: 1.5rem;
|
78
|
+
font-weight: 700;
|
79
|
+
text-decoration: none;
|
80
|
+
color: white;
|
81
|
+
}
|
82
|
+
|
83
|
+
.nav-menu {
|
84
|
+
display: flex;
|
85
|
+
gap: 2rem;
|
86
|
+
list-style: none;
|
87
|
+
}
|
88
|
+
|
89
|
+
.nav-menu a {
|
90
|
+
color: rgba(255,255,255,0.9);
|
91
|
+
text-decoration: none;
|
92
|
+
font-weight: 500;
|
93
|
+
transition: color 0.2s;
|
94
|
+
}
|
95
|
+
|
96
|
+
.nav-menu a:hover {
|
97
|
+
color: white;
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Hero Section */
|
101
|
+
.hero {
|
102
|
+
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
103
|
+
color: white;
|
104
|
+
padding: 6rem 0;
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
|
108
|
+
.hero-container {
|
109
|
+
max-width: 1200px;
|
110
|
+
margin: 0 auto;
|
111
|
+
padding: 0 2rem;
|
112
|
+
}
|
113
|
+
|
114
|
+
.hero h1 {
|
115
|
+
font-size: 3.5rem;
|
116
|
+
font-weight: 700;
|
117
|
+
margin-bottom: 1rem;
|
118
|
+
background: linear-gradient(45deg, #ffffff, #e2e8f0);
|
119
|
+
-webkit-background-clip: text;
|
120
|
+
-webkit-text-fill-color: transparent;
|
121
|
+
background-clip: text;
|
122
|
+
}
|
123
|
+
|
124
|
+
.hero p {
|
125
|
+
font-size: 1.25rem;
|
126
|
+
margin-bottom: 2rem;
|
127
|
+
opacity: 0.9;
|
128
|
+
max-width: 600px;
|
129
|
+
margin-left: auto;
|
130
|
+
margin-right: auto;
|
131
|
+
}
|
132
|
+
|
133
|
+
.hero-buttons {
|
134
|
+
display: flex;
|
135
|
+
gap: 1rem;
|
136
|
+
justify-content: center;
|
137
|
+
flex-wrap: wrap;
|
138
|
+
}
|
139
|
+
|
140
|
+
.btn {
|
141
|
+
display: inline-flex;
|
142
|
+
align-items: center;
|
143
|
+
gap: 0.5rem;
|
144
|
+
padding: 0.75rem 2rem;
|
145
|
+
border: none;
|
146
|
+
border-radius: 8px;
|
147
|
+
text-decoration: none;
|
148
|
+
font-weight: 600;
|
149
|
+
font-size: 1rem;
|
150
|
+
transition: all 0.2s;
|
151
|
+
cursor: pointer;
|
152
|
+
}
|
153
|
+
|
154
|
+
.btn-primary {
|
155
|
+
background: white;
|
156
|
+
color: var(--primary);
|
157
|
+
}
|
158
|
+
|
159
|
+
.btn-primary:hover {
|
160
|
+
background: var(--gray-100);
|
161
|
+
transform: translateY(-2px);
|
162
|
+
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
|
163
|
+
}
|
164
|
+
|
165
|
+
.btn-outline {
|
166
|
+
background: transparent;
|
167
|
+
color: white;
|
168
|
+
border: 2px solid rgba(255,255,255,0.3);
|
169
|
+
}
|
170
|
+
|
171
|
+
.btn-outline:hover {
|
172
|
+
background: rgba(255,255,255,0.1);
|
173
|
+
border-color: white;
|
174
|
+
}
|
175
|
+
|
176
|
+
/* Container */
|
177
|
+
.container {
|
178
|
+
max-width: 1200px;
|
179
|
+
margin: 0 auto;
|
180
|
+
padding: 0 2rem;
|
181
|
+
}
|
182
|
+
|
183
|
+
/* Sections */
|
184
|
+
.section {
|
185
|
+
padding: 5rem 0;
|
186
|
+
}
|
187
|
+
|
188
|
+
.section-alt {
|
189
|
+
background: var(--gray-100);
|
190
|
+
}
|
191
|
+
|
192
|
+
.section-title {
|
193
|
+
text-align: center;
|
194
|
+
font-size: 2.5rem;
|
195
|
+
font-weight: 700;
|
196
|
+
margin-bottom: 3rem;
|
197
|
+
color: var(--gray-800);
|
198
|
+
}
|
199
|
+
|
200
|
+
.section-subtitle {
|
201
|
+
text-align: center;
|
202
|
+
font-size: 1.125rem;
|
203
|
+
color: var(--gray-600);
|
204
|
+
margin-bottom: 4rem;
|
205
|
+
max-width: 600px;
|
206
|
+
margin-left: auto;
|
207
|
+
margin-right: auto;
|
208
|
+
}
|
209
|
+
|
210
|
+
/* Features Grid */
|
211
|
+
.features-grid {
|
212
|
+
display: grid;
|
213
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
214
|
+
gap: 2rem;
|
215
|
+
margin-top: 3rem;
|
216
|
+
}
|
217
|
+
|
218
|
+
.feature-card {
|
219
|
+
background: white;
|
220
|
+
padding: 2rem;
|
221
|
+
border-radius: 12px;
|
222
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
223
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
224
|
+
border: 1px solid var(--gray-200);
|
225
|
+
}
|
226
|
+
|
227
|
+
.feature-card:hover {
|
228
|
+
transform: translateY(-4px);
|
229
|
+
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
230
|
+
}
|
231
|
+
|
232
|
+
.feature-icon {
|
233
|
+
font-size: 2.5rem;
|
234
|
+
margin-bottom: 1rem;
|
235
|
+
}
|
236
|
+
|
237
|
+
.feature-title {
|
238
|
+
font-size: 1.25rem;
|
239
|
+
font-weight: 600;
|
240
|
+
margin-bottom: 0.5rem;
|
241
|
+
color: var(--gray-800);
|
242
|
+
}
|
243
|
+
|
244
|
+
.feature-desc {
|
245
|
+
color: var(--gray-600);
|
246
|
+
}
|
247
|
+
|
248
|
+
/* Code blocks */
|
249
|
+
.code-block {
|
250
|
+
background: var(--gray-900);
|
251
|
+
border-radius: 8px;
|
252
|
+
padding: 1.5rem;
|
253
|
+
margin: 1.5rem 0;
|
254
|
+
overflow-x: auto;
|
255
|
+
}
|
256
|
+
|
257
|
+
.code-block pre {
|
258
|
+
color: #e2e8f0;
|
259
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
260
|
+
margin: 0;
|
261
|
+
}
|
262
|
+
|
263
|
+
/* Installation Steps */
|
264
|
+
.install-steps {
|
265
|
+
display: grid;
|
266
|
+
gap: 2rem;
|
267
|
+
margin-top: 3rem;
|
268
|
+
}
|
269
|
+
|
270
|
+
.install-step {
|
271
|
+
background: white;
|
272
|
+
border-radius: 12px;
|
273
|
+
padding: 2rem;
|
274
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
275
|
+
border-left: 4px solid var(--primary);
|
276
|
+
}
|
277
|
+
|
278
|
+
.step-number {
|
279
|
+
display: inline-flex;
|
280
|
+
align-items: center;
|
281
|
+
justify-content: center;
|
282
|
+
width: 2rem;
|
283
|
+
height: 2rem;
|
284
|
+
background: var(--primary);
|
285
|
+
color: white;
|
286
|
+
border-radius: 50%;
|
287
|
+
font-weight: 700;
|
288
|
+
margin-right: 1rem;
|
289
|
+
}
|
290
|
+
|
291
|
+
.step-title {
|
292
|
+
font-size: 1.25rem;
|
293
|
+
font-weight: 600;
|
294
|
+
margin-bottom: 1rem;
|
295
|
+
display: flex;
|
296
|
+
align-items: center;
|
297
|
+
}
|
298
|
+
|
299
|
+
/* Stats */
|
300
|
+
.stats-grid {
|
301
|
+
display: grid;
|
302
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
303
|
+
gap: 2rem;
|
304
|
+
margin: 3rem 0;
|
305
|
+
}
|
306
|
+
|
307
|
+
.stat-card {
|
308
|
+
background: white;
|
309
|
+
padding: 2rem;
|
310
|
+
border-radius: 12px;
|
311
|
+
text-align: center;
|
312
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
313
|
+
border: 1px solid var(--gray-200);
|
314
|
+
}
|
315
|
+
|
316
|
+
.stat-number {
|
317
|
+
font-size: 2.5rem;
|
318
|
+
font-weight: 700;
|
319
|
+
color: var(--primary);
|
320
|
+
margin-bottom: 0.5rem;
|
321
|
+
}
|
322
|
+
|
323
|
+
.stat-label {
|
324
|
+
color: var(--gray-600);
|
325
|
+
font-weight: 500;
|
326
|
+
}
|
327
|
+
|
328
|
+
/* Team Section */
|
329
|
+
.team-grid {
|
330
|
+
display: grid;
|
331
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
332
|
+
gap: 2rem;
|
333
|
+
margin-top: 3rem;
|
334
|
+
}
|
335
|
+
|
336
|
+
.team-member {
|
337
|
+
background: white;
|
338
|
+
padding: 2rem;
|
339
|
+
border-radius: 12px;
|
340
|
+
text-align: center;
|
341
|
+
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
342
|
+
border: 1px solid var(--gray-200);
|
343
|
+
transition: transform 0.2s;
|
344
|
+
}
|
345
|
+
|
346
|
+
.team-member:hover {
|
347
|
+
transform: translateY(-4px);
|
348
|
+
}
|
349
|
+
|
350
|
+
.member-avatar {
|
351
|
+
width: 80px;
|
352
|
+
height: 80px;
|
353
|
+
border-radius: 50%;
|
354
|
+
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
355
|
+
display: flex;
|
356
|
+
align-items: center;
|
357
|
+
justify-content: center;
|
358
|
+
font-size: 2rem;
|
359
|
+
color: white;
|
360
|
+
margin: 0 auto 1rem;
|
361
|
+
}
|
362
|
+
|
363
|
+
.member-name {
|
364
|
+
font-size: 1.25rem;
|
365
|
+
font-weight: 600;
|
366
|
+
margin-bottom: 0.5rem;
|
367
|
+
}
|
368
|
+
|
369
|
+
.member-role {
|
370
|
+
color: var(--gray-600);
|
371
|
+
margin-bottom: 1rem;
|
372
|
+
}
|
373
|
+
|
374
|
+
.member-links {
|
375
|
+
display: flex;
|
376
|
+
justify-content: center;
|
377
|
+
gap: 1rem;
|
378
|
+
}
|
379
|
+
|
380
|
+
.member-links a {
|
381
|
+
color: var(--primary);
|
382
|
+
text-decoration: none;
|
383
|
+
font-weight: 500;
|
384
|
+
}
|
385
|
+
|
386
|
+
/* Footer */
|
387
|
+
.footer {
|
388
|
+
background: var(--gray-900);
|
389
|
+
color: white;
|
390
|
+
padding: 3rem 0 1rem;
|
391
|
+
}
|
392
|
+
|
393
|
+
.footer-content {
|
394
|
+
display: grid;
|
395
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
396
|
+
gap: 2rem;
|
397
|
+
margin-bottom: 2rem;
|
398
|
+
}
|
399
|
+
|
400
|
+
.footer-section h3 {
|
401
|
+
margin-bottom: 1rem;
|
402
|
+
color: white;
|
403
|
+
}
|
404
|
+
|
405
|
+
.footer-section ul {
|
406
|
+
list-style: none;
|
407
|
+
}
|
408
|
+
|
409
|
+
.footer-section ul li {
|
410
|
+
margin-bottom: 0.5rem;
|
411
|
+
}
|
412
|
+
|
413
|
+
.footer-section a {
|
414
|
+
color: var(--gray-400);
|
415
|
+
text-decoration: none;
|
416
|
+
transition: color 0.2s;
|
417
|
+
}
|
418
|
+
|
419
|
+
.footer-section a:hover {
|
420
|
+
color: white;
|
421
|
+
}
|
422
|
+
|
423
|
+
.footer-bottom {
|
424
|
+
border-top: 1px solid var(--gray-700);
|
425
|
+
padding-top: 2rem;
|
426
|
+
text-align: center;
|
427
|
+
color: var(--gray-400);
|
428
|
+
}
|
429
|
+
|
430
|
+
/* Responsive */
|
431
|
+
@media (max-width: 768px) {
|
432
|
+
.nav-menu {
|
433
|
+
display: none;
|
434
|
+
}
|
435
|
+
|
436
|
+
.hero h1 {
|
437
|
+
font-size: 2.5rem;
|
438
|
+
}
|
439
|
+
|
440
|
+
.hero-buttons {
|
441
|
+
flex-direction: column;
|
442
|
+
align-items: center;
|
443
|
+
}
|
444
|
+
|
445
|
+
.features-grid {
|
446
|
+
grid-template-columns: 1fr;
|
447
|
+
}
|
448
|
+
|
449
|
+
.container {
|
450
|
+
padding: 0 1rem;
|
451
|
+
}
|
452
|
+
|
453
|
+
.section {
|
454
|
+
padding: 3rem 0;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
/* Animations */
|
459
|
+
@keyframes fadeInUp {
|
460
|
+
from {
|
461
|
+
opacity: 0;
|
462
|
+
transform: translateY(30px);
|
463
|
+
}
|
464
|
+
to {
|
465
|
+
opacity: 1;
|
466
|
+
transform: translateY(0);
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
470
|
+
.fade-in-up {
|
471
|
+
animation: fadeInUp 0.6s ease-out;
|
472
|
+
}
|
473
|
+
|
474
|
+
/* Scrollbar */
|
475
|
+
::-webkit-scrollbar {
|
476
|
+
width: 8px;
|
477
|
+
}
|
478
|
+
|
479
|
+
::-webkit-scrollbar-track {
|
480
|
+
background: var(--gray-200);
|
481
|
+
}
|
482
|
+
|
483
|
+
::-webkit-scrollbar-thumb {
|
484
|
+
background: var(--primary);
|
485
|
+
border-radius: 4px;
|
486
|
+
}
|
487
|
+
|
488
|
+
::-webkit-scrollbar-thumb:hover {
|
489
|
+
background: var(--primary-dark);
|
490
|
+
}
|
491
|
+
</style>
|
492
|
+
</head>
|
493
|
+
<body>
|
494
|
+
<!-- Header -->
|
495
|
+
<header class="header">
|
496
|
+
<div class="nav-container">
|
497
|
+
<a href="#" class="logo">
|
498
|
+
<span>🗑️</span>
|
499
|
+
<span>RecycleBin</span>
|
500
|
+
</a>
|
501
|
+
<nav>
|
502
|
+
<ul class="nav-menu">
|
503
|
+
<li><a href="#features">Features</a></li>
|
504
|
+
<li><a href="#installation">Installation</a></li>
|
505
|
+
<li><a href="#documentation">Docs</a></li>
|
506
|
+
<li><a href="#team">Team</a></li>
|
507
|
+
<li><a href="https://github.com/R95-del/recycle_bin">GitHub</a></li>
|
508
|
+
</ul>
|
509
|
+
</nav>
|
510
|
+
</div>
|
511
|
+
</header>
|
512
|
+
|
513
|
+
<!-- Hero Section -->
|
514
|
+
<section class="hero">
|
515
|
+
<div class="hero-container">
|
516
|
+
<h1 class="fade-in-up">RecycleBin</h1>
|
517
|
+
<p class="fade-in-up">A simple and elegant soft delete solution for Rails applications with a beautiful web interface to manage your deleted records.</p>
|
518
|
+
<div class="hero-buttons fade-in-up">
|
519
|
+
<a href="#installation" class="btn btn-primary">
|
520
|
+
<span>🚀</span>
|
521
|
+
Get Started
|
522
|
+
</a>
|
523
|
+
<a href="https://github.com/R95-del/recycle_bin" class="btn btn-outline">
|
524
|
+
<span>📂</span>
|
525
|
+
View on GitHub
|
526
|
+
</a>
|
527
|
+
</div>
|
528
|
+
</div>
|
529
|
+
</section>
|
530
|
+
|
531
|
+
<!-- Stats Section -->
|
532
|
+
<section class="section">
|
533
|
+
<div class="container">
|
534
|
+
<div class="stats-grid">
|
535
|
+
<div class="stat-card">
|
536
|
+
<div class="stat-number">1.1.1</div>
|
537
|
+
<div class="stat-label">Latest Version</div>
|
538
|
+
</div>
|
539
|
+
<div class="stat-card">
|
540
|
+
<div class="stat-number">Rails 6+</div>
|
541
|
+
<div class="stat-label">Compatible</div>
|
542
|
+
</div>
|
543
|
+
<div class="stat-card">
|
544
|
+
<div class="stat-number">MIT</div>
|
545
|
+
<div class="stat-label">License</div>
|
546
|
+
</div>
|
547
|
+
<div class="stat-card">
|
548
|
+
<div class="stat-number">Ruby 2.7+</div>
|
549
|
+
<div class="stat-label">Requirement</div>
|
550
|
+
</div>
|
551
|
+
</div>
|
552
|
+
</div>
|
553
|
+
</section>
|
554
|
+
|
555
|
+
<!-- Features Section -->
|
556
|
+
<section id="features" class="section section-alt">
|
557
|
+
<div class="container">
|
558
|
+
<h2 class="section-title">Why Choose RecycleBin?</h2>
|
559
|
+
<p class="section-subtitle">
|
560
|
+
Built specifically for Rails developers who need a reliable, beautiful soft delete solution with zero complexity.
|
561
|
+
</p>
|
562
|
+
|
563
|
+
<div class="features-grid">
|
564
|
+
<div class="feature-card">
|
565
|
+
<div class="feature-icon">🗑️</div>
|
566
|
+
<h3 class="feature-title">Soft Delete Made Simple</h3>
|
567
|
+
<p class="feature-desc">Records are marked as deleted instead of being permanently removed. Easy to include in any ActiveRecord model.</p>
|
568
|
+
</div>
|
569
|
+
|
570
|
+
<div class="feature-card">
|
571
|
+
<div class="feature-icon">🎨</div>
|
572
|
+
<h3 class="feature-title">Beautiful Web Interface</h3>
|
573
|
+
<p class="feature-desc">Responsive dashboard inspired by Sidekiq's design. View, filter, and manage deleted items with an elegant UI.</p>
|
574
|
+
</div>
|
575
|
+
|
576
|
+
<div class="feature-card">
|
577
|
+
<div class="feature-icon">⚡</div>
|
578
|
+
<h3 class="feature-title">High Performance</h3>
|
579
|
+
<p class="feature-desc">Efficient pagination and lazy loading. Handles 5000+ deleted records without breaking a sweat.</p>
|
580
|
+
</div>
|
581
|
+
|
582
|
+
<div class="feature-card">
|
583
|
+
<div class="feature-icon">🔧</div>
|
584
|
+
<h3 class="feature-title">Easy Setup</h3>
|
585
|
+
<p class="feature-desc">Rails generators automate the entire setup. Add soft delete to any model in under 2 minutes.</p>
|
586
|
+
</div>
|
587
|
+
|
588
|
+
<div class="feature-card">
|
589
|
+
<div class="feature-icon">📊</div>
|
590
|
+
<h3 class="feature-title">Bulk Operations</h3>
|
591
|
+
<p class="feature-desc">Select and restore/delete multiple items at once. Filter by model type, time, and more.</p>
|
592
|
+
</div>
|
593
|
+
|
594
|
+
<div class="feature-card">
|
595
|
+
<div class="feature-icon">🔒</div>
|
596
|
+
<h3 class="feature-title">Configurable Access</h3>
|
597
|
+
<p class="feature-desc">Built-in authorization support. Restrict access to admins only or use custom authorization logic.</p>
|
598
|
+
</div>
|
599
|
+
</div>
|
600
|
+
</div>
|
601
|
+
</section>
|
602
|
+
|
603
|
+
<!-- Installation Section -->
|
604
|
+
<section id="installation" class="section">
|
605
|
+
<div class="container">
|
606
|
+
<h2 class="section-title">Quick Installation</h2>
|
607
|
+
<p class="section-subtitle">
|
608
|
+
Get RecycleBin running in your Rails app in just a few steps.
|
609
|
+
</p>
|
610
|
+
|
611
|
+
<div class="install-steps">
|
612
|
+
<div class="install-step">
|
613
|
+
<h3 class="step-title">
|
614
|
+
<span class="step-number">1</span>
|
615
|
+
Add to Gemfile
|
616
|
+
</h3>
|
617
|
+
<p>Add RecycleBin to your Rails application:</p>
|
618
|
+
<div class="code-block">
|
619
|
+
<pre><code class="language-ruby"># Gemfile
|
620
|
+
gem 'recycle_bin', '~> 1.1'</code></pre>
|
621
|
+
</div>
|
622
|
+
<div class="code-block">
|
623
|
+
<pre><code class="language-bash">$ bundle install</code></pre>
|
624
|
+
</div>
|
625
|
+
</div>
|
626
|
+
|
627
|
+
<div class="install-step">
|
628
|
+
<h3 class="step-title">
|
629
|
+
<span class="step-number">2</span>
|
630
|
+
Run Install Generator
|
631
|
+
</h3>
|
632
|
+
<p>Generate configuration and routes:</p>
|
633
|
+
<div class="code-block">
|
634
|
+
<pre><code class="language-bash">$ rails generate recycle_bin:install</code></pre>
|
635
|
+
</div>
|
636
|
+
</div>
|
637
|
+
|
638
|
+
<div class="install-step">
|
639
|
+
<h3 class="step-title">
|
640
|
+
<span class="step-number">3</span>
|
641
|
+
Add deleted_at Column
|
642
|
+
</h3>
|
643
|
+
<p>For each model you want to soft delete:</p>
|
644
|
+
<div class="code-block">
|
645
|
+
<pre><code class="language-bash">$ rails generate recycle_bin:add_deleted_at User
|
646
|
+
$ rails generate recycle_bin:add_deleted_at Post
|
647
|
+
$ rails db:migrate</code></pre>
|
648
|
+
</div>
|
649
|
+
</div>
|
650
|
+
|
651
|
+
<div class="install-step">
|
652
|
+
<h3 class="step-title">
|
653
|
+
<span class="step-number">4</span>
|
654
|
+
Include the Module
|
655
|
+
</h3>
|
656
|
+
<p>Add soft delete capability to your models:</p>
|
657
|
+
<div class="code-block">
|
658
|
+
<pre><code class="language-ruby">class User < ApplicationRecord
|
659
|
+
include RecycleBin::SoftDeletable
|
660
|
+
end
|
661
|
+
|
662
|
+
class Post < ApplicationRecord
|
663
|
+
include RecycleBin::SoftDeletable
|
664
|
+
end</code></pre>
|
665
|
+
</div>
|
666
|
+
</div>
|
667
|
+
|
668
|
+
<div class="install-step">
|
669
|
+
<h3 class="step-title">
|
670
|
+
<span class="step-number">5</span>
|
671
|
+
Start Using!
|
672
|
+
</h3>
|
673
|
+
<p>Your soft delete system is ready:</p>
|
674
|
+
<div class="code-block">
|
675
|
+
<pre><code class="language-ruby"># Soft delete a record
|
676
|
+
user = User.find(1)
|
677
|
+
user.destroy # Goes to trash
|
678
|
+
|
679
|
+
# Visit /recycle_bin to manage deleted items
|
680
|
+
# Restore from code: user.restore</code></pre>
|
681
|
+
</div>
|
682
|
+
</div>
|
683
|
+
</div>
|
684
|
+
</div>
|
685
|
+
</section>
|
686
|
+
|
687
|
+
<!-- Documentation Section -->
|
688
|
+
<section id="documentation" class="section section-alt">
|
689
|
+
<div class="container">
|
690
|
+
<h2 class="section-title">Documentation & Examples</h2>
|
691
|
+
|
692
|
+
<div class="features-grid">
|
693
|
+
<div class="feature-card">
|
694
|
+
<div class="feature-icon">📚</div>
|
695
|
+
<h3 class="feature-title">Full README</h3>
|
696
|
+
<p class="feature-desc">Complete documentation with examples, configuration options, and troubleshooting guide.</p>
|
697
|
+
<a href="https://github.com/R95-del/recycle_bin/blob/main/README.md" class="btn btn-primary" style="margin-top: 1rem;">Read Docs</a>
|
698
|
+
</div>
|
699
|
+
|
700
|
+
<div class="feature-card">
|
701
|
+
<div class="feature-icon">🔄</div>
|
702
|
+
<h3 class="feature-title">Changelog</h3>
|
703
|
+
<p class="feature-desc">Track all updates, new features, and improvements across versions.</p>
|
704
|
+
<a href="https://github.com/R95-del/recycle_bin/blob/main/CHANGELOG.md" class="btn btn-primary" style="margin-top: 1rem;">View Changes</a>
|
705
|
+
</div>
|
706
|
+
|
707
|
+
<div class="feature-card">
|
708
|
+
<div class="feature-icon">🐛</div>
|
709
|
+
<h3 class="feature-title">Issue Tracker</h3>
|
710
|
+
<p class="feature-desc">Report bugs, request features, or get help from the community.</p>
|
711
|
+
<a href="https://github.com/R95-del/recycle_bin/issues" class="btn btn-primary" style="margin-top: 1rem;">Report Issue</a>
|
712
|
+
</div>
|
713
|
+
</div>
|
714
|
+
|
715
|
+
<div style="margin-top: 3rem;">
|
716
|
+
<h3 style="font-size: 2rem; margin-bottom: 2rem; text-align: center;">Quick Reference</h3>
|
717
|
+
|
718
|
+
<div class="code-block">
|
719
|
+
<pre><code class="language-ruby"># Basic Usage
|
720
|
+
user = User.create(name: "John Doe")
|
721
|
+
user.destroy # Soft delete
|
722
|
+
user.deleted? # => true
|
723
|
+
user.restore # Bring back
|
724
|
+
user.destroy! # Permanent delete
|
725
|
+
|
726
|
+
# Querying
|
727
|
+
User.all # Active records only (default scope)
|
728
|
+
User.deleted # Deleted records only
|
729
|
+
User.with_deleted # All records including deleted
|
730
|
+
User.restore(123) # Restore by ID
|
731
|
+
|
732
|
+
# Configuration
|
733
|
+
RecycleBin.configure do |config|
|
734
|
+
config.items_per_page = 50
|
735
|
+
config.authorize_with do |controller|
|
736
|
+
controller.current_user&.admin?
|
737
|
+
end
|
738
|
+
end</code></pre>
|
739
|
+
</div>
|
740
|
+
</div>
|
741
|
+
</div>
|
742
|
+
</section>
|
743
|
+
|
744
|
+
<!-- Team Section -->
|
745
|
+
<section id="team" class="section">
|
746
|
+
<div class="container">
|
747
|
+
<h2 class="section-title">Meet the Team</h2>
|
748
|
+
<p class="section-subtitle">
|
749
|
+
Built with ❤️ by Rails developers for the Rails community.
|
750
|
+
</p>
|
751
|
+
|
752
|
+
<div class="team-grid">
|
753
|
+
<div class="team-member">
|
754
|
+
<div class="member-avatar">RS</div>
|
755
|
+
<h3 class="member-name">Rishi Somani</h3>
|
756
|
+
<p class="member-role">Core Developer</p>
|
757
|
+
<div class="member-links">
|
758
|
+
<a href="mailto:somani.rishi81@gmail.com">Email</a>
|
759
|
+
<a href="https://github.com/R95-del">GitHub</a>
|
760
|
+
<a href="https://rubygems.org/profiles/Rishi07">Ruby-Gems</a>
|
761
|
+
</div>
|
762
|
+
</div>
|
763
|
+
|
764
|
+
<div class="team-member">
|
765
|
+
<div class="member-avatar">SJ</div>
|
766
|
+
<h3 class="member-name">Shobhit Jain</h3>
|
767
|
+
<p class="member-role">Core Developer</p>
|
768
|
+
<div class="member-links">
|
769
|
+
<a href="mailto:shobhjain09@gmail.com">Email</a>
|
770
|
+
<a href="https://github.com/ShobhitS7">GitHub</a>
|
771
|
+
<a href="https://rubygems.org/profiles/shobhits7">Ruby-Gems</a>
|
772
|
+
</div>
|
773
|
+
</div>
|
774
|
+
|
775
|
+
<div class="team-member">
|
776
|
+
<div class="member-avatar">RA</div>
|
777
|
+
<h3 class="member-name">Raghav Agrawal</h3>
|
778
|
+
<p class="member-role">Core Developer</p>
|
779
|
+
<div class="member-links">
|
780
|
+
<a href="mailto:raghavagrawal019@gmail.com">Email</a>
|
781
|
+
<a href="https://github.com/RaghavAgr">GitHub</a>
|
782
|
+
<a href="https://rubygems.org/profiles/RaghavAgr">Ruby-Gems</a>
|
783
|
+
</div>
|
784
|
+
</div>
|
785
|
+
</div>
|
786
|
+
</div>
|
787
|
+
</section>
|
788
|
+
|
789
|
+
<!-- Footer -->
|
790
|
+
<footer class="footer">
|
791
|
+
<div class="container">
|
792
|
+
<div class="footer-content">
|
793
|
+
<div class="footer-section">
|
794
|
+
<h3>RecycleBin</h3>
|
795
|
+
<p style="color: var(--gray-400); margin-bottom: 1rem;">
|
796
|
+
Elegant soft delete solution for Rails applications.
|
797
|
+
</p>
|
798
|
+
<p style="color: var(--gray-400);">
|
799
|
+
Made with ❤️ for the Rails community.
|
800
|
+
</p>
|
801
|
+
</div>
|
802
|
+
|
803
|
+
<div class="footer-section">
|
804
|
+
<h3>Documentation</h3>
|
805
|
+
<ul>
|
806
|
+
<li><a href="https://github.com/R95-del/recycle_bin/blob/main/README.md">Getting Started</a></li>
|
807
|
+
<li><a href="https://github.com/R95-del/recycle_bin/blob/main/CHANGELOG.md">Changelog</a></li>
|
808
|
+
<li><a href="https://github.com/R95-del/recycle_bin/wiki">Wiki</a></li>
|
809
|
+
<li><a href="https://github.com/R95-del/recycle_bin/issues">Support</a></li>
|
810
|
+
</ul>
|
811
|
+
</div>
|
812
|
+
|
813
|
+
<div class="footer-section">
|
814
|
+
<h3>Project</h3>
|
815
|
+
<ul>
|
816
|
+
<li><a href="https://github.com/R95-del/recycle_bin">Source Code</a></li>
|
817
|
+
<li><a href="https://github.com/R95-del/recycle_bin/issues">Bug Reports</a></li>
|
818
|
+
<li><a href="https://github.com/R95-del/recycle_bin/blob/main/LICENSE.txt">License (MIT)</a></li>
|
819
|
+
<li><a href="https://rubygems.org/gems/recycle_bin">RubyGems</a></li>
|
820
|
+
</ul>
|
821
|
+
</div>
|
822
|
+
|
823
|
+
<div class="footer-section">
|
824
|
+
<h3>Community</h3>
|
825
|
+
<ul>
|
826
|
+
<li><a href="https://github.com/R95-del/recycle_bin/discussions">Discussions</a></li>
|
827
|
+
<li><a href="https://github.com/R95-del/recycle_bin/pulls">Contribute</a></li>
|
828
|
+
<li><a href="https://github.com/R95-del/recycle_bin/blob/main/README.md#contributing-🤝">Contributing Guide</a></li>
|
829
|
+
</ul>
|
830
|
+
</div>
|
831
|
+
</div>
|
832
|
+
|
833
|
+
<div class="footer-bottom">
|
834
|
+
<p>© 2025 RecycleBin. Licensed under MIT License.</p>
|
835
|
+
<p style="margin-top: 0.5rem;">
|
836
|
+
Version 1.1.1 •
|
837
|
+
<a href="https://github.com/R95-del/recycle_bin/tags" style="color: var(--primary);">View Releases</a>
|
838
|
+
</p>
|
839
|
+
</div>
|
840
|
+
</div>
|
841
|
+
</footer>
|
842
|
+
|
843
|
+
<!-- Syntax highlighting -->
|
844
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
|
845
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
846
|
+
|
847
|
+
<!-- Smooth scrolling -->
|
848
|
+
<script>
|
849
|
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
850
|
+
anchor.addEventListener('click', function (e) {
|
851
|
+
e.preventDefault();
|
852
|
+
const target = document.querySelector(this.getAttribute('href'));
|
853
|
+
if (target) {
|
854
|
+
target.scrollIntoView({
|
855
|
+
behavior: 'smooth',
|
856
|
+
block: 'start'
|
857
|
+
});
|
858
|
+
}
|
859
|
+
});
|
860
|
+
});
|
861
|
+
|
862
|
+
// Animate elements on scroll
|
863
|
+
const observerOptions = {
|
864
|
+
threshold: 0.1,
|
865
|
+
rootMargin: '0px 0px -50px 0px'
|
866
|
+
};
|
867
|
+
|
868
|
+
const observer = new IntersectionObserver(function(entries) {
|
869
|
+
entries.forEach(entry => {
|
870
|
+
if (entry.isIntersecting) {
|
871
|
+
entry.target.classList.add('fade-in-up');
|
872
|
+
}
|
873
|
+
});
|
874
|
+
}, observerOptions);
|
875
|
+
|
876
|
+
// Observe all feature cards and install steps
|
877
|
+
document.querySelectorAll('.feature-card, .install-step, .team-member').forEach(el => {
|
878
|
+
observer.observe(el);
|
879
|
+
});
|
880
|
+
|
881
|
+
// Add copy functionality to code blocks
|
882
|
+
document.querySelectorAll('.code-block').forEach(block => {
|
883
|
+
const copyButton = document.createElement('button');
|
884
|
+
copyButton.textContent = 'Copy';
|
885
|
+
copyButton.style.cssText = `
|
886
|
+
position: absolute;
|
887
|
+
top: 1rem;
|
888
|
+
right: 1rem;
|
889
|
+
background: var(--primary);
|
890
|
+
color: white;
|
891
|
+
border: none;
|
892
|
+
padding: 0.5rem 1rem;
|
893
|
+
border-radius: 4px;
|
894
|
+
font-size: 0.875rem;
|
895
|
+
cursor: pointer;
|
896
|
+
opacity: 0;
|
897
|
+
transition: opacity 0.2s;
|
898
|
+
`;
|
899
|
+
|
900
|
+
block.style.position = 'relative';
|
901
|
+
block.appendChild(copyButton);
|
902
|
+
|
903
|
+
block.addEventListener('mouseenter', () => {
|
904
|
+
copyButton.style.opacity = '1';
|
905
|
+
});
|
906
|
+
|
907
|
+
block.addEventListener('mouseleave', () => {
|
908
|
+
copyButton.style.opacity = '0';
|
909
|
+
});
|
910
|
+
|
911
|
+
copyButton.addEventListener('click', () => {
|
912
|
+
const code = block.querySelector('code').textContent;
|
913
|
+
navigator.clipboard.writeText(code).then(() => {
|
914
|
+
copyButton.textContent = 'Copied!';
|
915
|
+
setTimeout(() => {
|
916
|
+
copyButton.textContent = 'Copy';
|
917
|
+
}, 2000);
|
918
|
+
});
|
919
|
+
});
|
920
|
+
});
|
921
|
+
|
922
|
+
// Mobile menu toggle (if needed in future)
|
923
|
+
const mobileMenuToggle = () => {
|
924
|
+
// Add mobile menu functionality here if needed
|
925
|
+
};
|
926
|
+
</script>
|
927
|
+
</body>
|
928
|
+
</html>
|