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/logo.svg
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">
|
2
|
+
<defs>
|
3
|
+
<!-- Gradient for the main container -->
|
4
|
+
<linearGradient id="containerGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
5
|
+
<stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
|
6
|
+
<stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
|
7
|
+
</linearGradient>
|
8
|
+
|
9
|
+
<!-- Gradient for the lid -->
|
10
|
+
<linearGradient id="lidGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
11
|
+
<stop offset="0%" style="stop-color:#8b9cf7;stop-opacity:1" />
|
12
|
+
<stop offset="100%" style="stop-color:#667eea;stop-opacity:1" />
|
13
|
+
</linearGradient>
|
14
|
+
|
15
|
+
<!-- Shadow filter -->
|
16
|
+
<filter id="dropShadow" x="-50%" y="-50%" width="200%" height="200%">
|
17
|
+
<feDropShadow dx="3" dy="6" stdDeviation="4" flood-color="rgba(0,0,0,0.3)"/>
|
18
|
+
</filter>
|
19
|
+
|
20
|
+
<!-- Glow effect -->
|
21
|
+
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
22
|
+
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
|
23
|
+
<feMerge>
|
24
|
+
<feMergeNode in="coloredBlur"/>
|
25
|
+
<feMergeNode in="SourceGraphic"/>
|
26
|
+
</feMerge>
|
27
|
+
</filter>
|
28
|
+
</defs>
|
29
|
+
|
30
|
+
<!-- Background circle -->
|
31
|
+
<circle cx="100" cy="100" r="95" fill="url(#containerGradient)" filter="url(#dropShadow)" opacity="0.1"/>
|
32
|
+
|
33
|
+
<!-- Main trash bin body -->
|
34
|
+
<rect x="60" y="80" width="80" height="90" rx="8" ry="8" fill="url(#containerGradient)" filter="url(#dropShadow)"/>
|
35
|
+
|
36
|
+
<!-- Trash bin lid -->
|
37
|
+
<rect x="50" y="70" width="100" height="12" rx="6" ry="6" fill="url(#lidGradient)" filter="url(#dropShadow)"/>
|
38
|
+
|
39
|
+
<!-- Lid handle -->
|
40
|
+
<rect x="90" y="55" width="20" height="8" rx="4" ry="4" fill="url(#lidGradient)"/>
|
41
|
+
<rect x="95" y="63" width="10" height="12" fill="url(#lidGradient)"/>
|
42
|
+
|
43
|
+
<!-- Vertical lines on trash bin -->
|
44
|
+
<line x1="80" y1="90" x2="80" y2="155" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-linecap="round"/>
|
45
|
+
<line x1="100" y1="90" x2="100" y2="155" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-linecap="round"/>
|
46
|
+
<line x1="120" y1="90" x2="120" y2="155" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-linecap="round"/>
|
47
|
+
|
48
|
+
<!-- Restore arrow (curved arrow indicating recovery) -->
|
49
|
+
<g transform="translate(130, 40)" filter="url(#glow)">
|
50
|
+
<path d="M 0 15 Q 10 5 20 15 Q 15 10 15 20" stroke="#28a745" stroke-width="3" fill="none" stroke-linecap="round"/>
|
51
|
+
<polygon points="12,18 18,18 15,24" fill="#28a745"/>
|
52
|
+
</g>
|
53
|
+
|
54
|
+
<!-- Floating particles (representing restored items) -->
|
55
|
+
<circle cx="45" cy="50" r="3" fill="#28a745" opacity="0.7">
|
56
|
+
<animate attributeName="cy" values="50;45;50" dur="2s" repeatCount="indefinite"/>
|
57
|
+
</circle>
|
58
|
+
<circle cx="155" cy="60" r="2" fill="#ffc107" opacity="0.8">
|
59
|
+
<animate attributeName="cy" values="60;55;60" dur="1.5s" repeatCount="indefinite"/>
|
60
|
+
<animate attributeName="opacity" values="0.8;0.4;0.8" dur="1.5s" repeatCount="indefinite"/>
|
61
|
+
</circle>
|
62
|
+
<circle cx="40" cy="120" r="2.5" fill="#17a2b8" opacity="0.6">
|
63
|
+
<animate attributeName="cy" values="120;115;120" dur="2.5s" repeatCount="indefinite"/>
|
64
|
+
</circle>
|
65
|
+
|
66
|
+
<!-- Subtle highlight on the bin -->
|
67
|
+
<rect x="62" y="82" width="15" height="60" rx="4" ry="4" fill="rgba(255,255,255,0.2)"/>
|
68
|
+
|
69
|
+
<!-- Brand text (small) -->
|
70
|
+
<text x="100" y="190" text-anchor="middle" font-family="Inter, sans-serif" font-size="14" font-weight="600" fill="url(#containerGradient)">RecycleBin</text>
|
71
|
+
</svg>
|
data/lib/recycle_bin/version.rb
CHANGED
data/lib/recycle_bin.rb
CHANGED
@@ -26,13 +26,15 @@ module RecycleBin
|
|
26
26
|
configuration || (self.configuration = Configuration.new)
|
27
27
|
end
|
28
28
|
|
29
|
-
#
|
29
|
+
# Improved stats for better performance
|
30
30
|
def self.stats
|
31
31
|
return {} unless defined?(Rails) && Rails.application
|
32
32
|
|
33
33
|
{
|
34
34
|
deleted_items: count_deleted_items,
|
35
|
-
models_with_soft_delete: models_with_soft_delete
|
35
|
+
models_with_soft_delete: models_with_soft_delete,
|
36
|
+
deleted_today: count_deleted_items_today,
|
37
|
+
deleted_this_week: count_deleted_items_this_week
|
36
38
|
}
|
37
39
|
end
|
38
40
|
|
@@ -47,6 +49,28 @@ module RecycleBin
|
|
47
49
|
0
|
48
50
|
end
|
49
51
|
|
52
|
+
def self.count_deleted_items_today
|
53
|
+
total = 0
|
54
|
+
models_with_soft_delete.each do |model_name|
|
55
|
+
total += count_deleted_items_for_model_since(model_name, 1.day.ago)
|
56
|
+
end
|
57
|
+
total
|
58
|
+
rescue StandardError => e
|
59
|
+
log_debug_message("Error counting today's deleted items: #{e.message}")
|
60
|
+
0
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.count_deleted_items_this_week
|
64
|
+
total = 0
|
65
|
+
models_with_soft_delete.each do |model_name|
|
66
|
+
total += count_deleted_items_for_model_since(model_name, 1.week.ago)
|
67
|
+
end
|
68
|
+
total
|
69
|
+
rescue StandardError => e
|
70
|
+
log_debug_message("Error counting this week's deleted items: #{e.message}")
|
71
|
+
0
|
72
|
+
end
|
73
|
+
|
50
74
|
def self.count_deleted_items_for_model(model_name)
|
51
75
|
model = model_name.constantize
|
52
76
|
model.respond_to?(:deleted) ? model.deleted.count : 0
|
@@ -55,6 +79,18 @@ module RecycleBin
|
|
55
79
|
0
|
56
80
|
end
|
57
81
|
|
82
|
+
def self.count_deleted_items_for_model_since(model_name, since_time)
|
83
|
+
model = model_name.constantize
|
84
|
+
if model.respond_to?(:deleted)
|
85
|
+
model.deleted.where('deleted_at >= ?', since_time).count
|
86
|
+
else
|
87
|
+
0
|
88
|
+
end
|
89
|
+
rescue StandardError => e
|
90
|
+
log_debug_message("Error counting deleted items for #{model_name} since #{since_time}: #{e.message}")
|
91
|
+
0
|
92
|
+
end
|
93
|
+
|
58
94
|
def self.models_with_soft_delete
|
59
95
|
return [] unless rails_application_available?
|
60
96
|
|
@@ -97,14 +133,44 @@ module RecycleBin
|
|
97
133
|
Rails.logger.debug(message) if defined?(Rails) && Rails.logger
|
98
134
|
end
|
99
135
|
|
136
|
+
# Get all deleted items across all models (for advanced queries)
|
137
|
+
def self.all_deleted_items(limit: nil, offset: nil, order_by: :deleted_at, order_direction: :desc)
|
138
|
+
all_items = []
|
139
|
+
|
140
|
+
models_with_soft_delete.each do |model_name|
|
141
|
+
model = model_name.constantize
|
142
|
+
if model.respond_to?(:deleted)
|
143
|
+
items = model.deleted.to_a
|
144
|
+
all_items.concat(items)
|
145
|
+
end
|
146
|
+
rescue StandardError => e
|
147
|
+
log_debug_message("Error loading deleted items for #{model_name}: #{e.message}")
|
148
|
+
end
|
149
|
+
|
150
|
+
# Sort items
|
151
|
+
sorted_items = all_items.sort_by { |item| item.send(order_by) }
|
152
|
+
sorted_items.reverse! if order_direction == :desc
|
153
|
+
|
154
|
+
# Apply offset and limit
|
155
|
+
sorted_items = sorted_items.drop(offset) if offset&.positive?
|
156
|
+
|
157
|
+
sorted_items = sorted_items.first(limit) if limit&.positive?
|
158
|
+
|
159
|
+
sorted_items
|
160
|
+
rescue StandardError => e
|
161
|
+
log_debug_message("Error getting all deleted items: #{e.message}")
|
162
|
+
[]
|
163
|
+
end
|
164
|
+
|
100
165
|
# Configuration class for RecycleBin
|
101
166
|
class Configuration
|
102
167
|
attr_accessor :enable_web_interface, :items_per_page, :ui_theme,
|
103
|
-
:auto_cleanup_after, :current_user_method
|
168
|
+
:auto_cleanup_after, :current_user_method, :max_items_per_page
|
104
169
|
|
105
170
|
def initialize
|
106
171
|
@enable_web_interface = true
|
107
172
|
@items_per_page = 25
|
173
|
+
@max_items_per_page = 1000
|
108
174
|
@ui_theme = 'default'
|
109
175
|
@auto_cleanup_after = nil
|
110
176
|
@current_user_method = :current_user
|
data/recycle_bin.gemspec
CHANGED
@@ -29,12 +29,12 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.require_paths = ['lib']
|
30
30
|
|
31
31
|
# Runtime dependencies - Use pessimistic version constraints
|
32
|
-
spec.
|
32
|
+
spec.add_dependency 'rails', '>= 6.0', '< 9.0'
|
33
33
|
|
34
|
-
# Development dependencies
|
34
|
+
# Development dependencies - FIXED to match Gemfile
|
35
35
|
spec.add_development_dependency 'factory_bot_rails', '~> 6.2'
|
36
|
-
spec.add_development_dependency 'rspec-rails', '~> 6.0'
|
37
|
-
spec.add_development_dependency 'sqlite3', '~> 2.1'
|
36
|
+
spec.add_development_dependency 'rspec-rails', '>= 6.0' # Changed from '~> 6.0'
|
37
|
+
spec.add_development_dependency 'sqlite3', '~> 2.0' # Changed from '~> 2.1'
|
38
38
|
|
39
39
|
# Gem metadata with distinct URIs
|
40
40
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recycle_bin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rishi Somani
|
8
8
|
- Shobhit Jain
|
9
9
|
- Raghav Agrawal
|
10
|
-
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2025-05-
|
12
|
+
date: 2025-05-26 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rails
|
@@ -50,14 +49,14 @@ dependencies:
|
|
50
49
|
name: rspec-rails
|
51
50
|
requirement: !ruby/object:Gem::Requirement
|
52
51
|
requirements:
|
53
|
-
- - "
|
52
|
+
- - ">="
|
54
53
|
- !ruby/object:Gem::Version
|
55
54
|
version: '6.0'
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
57
|
version_requirements: !ruby/object:Gem::Requirement
|
59
58
|
requirements:
|
60
|
-
- - "
|
59
|
+
- - ">="
|
61
60
|
- !ruby/object:Gem::Version
|
62
61
|
version: '6.0'
|
63
62
|
- !ruby/object:Gem::Dependency
|
@@ -66,14 +65,14 @@ dependencies:
|
|
66
65
|
requirements:
|
67
66
|
- - "~>"
|
68
67
|
- !ruby/object:Gem::Version
|
69
|
-
version: '2.
|
68
|
+
version: '2.0'
|
70
69
|
type: :development
|
71
70
|
prerelease: false
|
72
71
|
version_requirements: !ruby/object:Gem::Requirement
|
73
72
|
requirements:
|
74
73
|
- - "~>"
|
75
74
|
- !ruby/object:Gem::Version
|
76
|
-
version: '2.
|
75
|
+
version: '2.0'
|
77
76
|
description: RecycleBin provides soft delete functionality with a user-friendly trash/recycle
|
78
77
|
bin interface for any Rails application. Easily restore deleted records with a simple
|
79
78
|
web interface.
|
@@ -93,13 +92,20 @@ files:
|
|
93
92
|
- app/controllers/recycle_bin/application_controller.rb
|
94
93
|
- app/controllers/recycle_bin/trash_controller.rb
|
95
94
|
- app/helpers/recycle_bin/application_helper.rb
|
96
|
-
- app/views/layouts/recycle_bin
|
97
|
-
- app/views/
|
98
|
-
- app/views/
|
99
|
-
- app/views/
|
95
|
+
- app/views/recycle_bin/layouts/recycle_bin.html.erb
|
96
|
+
- app/views/recycle_bin/shared/_error_messages.html.erb
|
97
|
+
- app/views/recycle_bin/shared/_flash_messages.html.erb
|
98
|
+
- app/views/recycle_bin/trash/_action_history.html.erb
|
99
|
+
- app/views/recycle_bin/trash/_associations.html.erb
|
100
|
+
- app/views/recycle_bin/trash/_filters.html.erb
|
101
|
+
- app/views/recycle_bin/trash/_item.html.erb
|
102
|
+
- app/views/recycle_bin/trash/_pagination.html.erb
|
103
|
+
- app/views/recycle_bin/trash/_stats.html.erb
|
100
104
|
- app/views/recycle_bin/trash/index.html.erb
|
101
105
|
- app/views/recycle_bin/trash/show.html.erb
|
102
106
|
- config/routes.rb
|
107
|
+
- docs/index.html
|
108
|
+
- docs/logo.svg
|
103
109
|
- lib/generators/recycle_bin/add_deleted_at/add_deleted_at_generator.rb
|
104
110
|
- lib/generators/recycle_bin/add_deleted_at/templates/add_deleted_at_migration.rb.erb
|
105
111
|
- lib/generators/recycle_bin/install/install_generator.rb
|
@@ -122,7 +128,6 @@ metadata:
|
|
122
128
|
bug_tracker_uri: https://github.com/R95-del/recycle_bin/issues
|
123
129
|
documentation_uri: https://github.com/R95-del/recycle_bin/blob/main/README.md
|
124
130
|
wiki_uri: https://github.com/R95-del/recycle_bin/wiki
|
125
|
-
post_install_message:
|
126
131
|
rdoc_options: []
|
127
132
|
require_paths:
|
128
133
|
- lib
|
@@ -137,8 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
142
|
- !ruby/object:Gem::Version
|
138
143
|
version: '0'
|
139
144
|
requirements: []
|
140
|
-
rubygems_version: 3.
|
141
|
-
signing_key:
|
145
|
+
rubygems_version: 3.6.6
|
142
146
|
specification_version: 4
|
143
147
|
summary: Soft delete and trash management for Ruby on Rails applications
|
144
148
|
test_files: []
|
@@ -1,266 +0,0 @@
|
|
1
|
-
|
2
|
-
<!DOCTYPE html>
|
3
|
-
<html>
|
4
|
-
<head>
|
5
|
-
<title>Recycle Bin</title>
|
6
|
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
7
|
-
<%= csrf_meta_tags %>
|
8
|
-
<%= csp_meta_tag %>
|
9
|
-
|
10
|
-
<style>
|
11
|
-
/* Simple, clean CSS for V1 MVP */
|
12
|
-
* {
|
13
|
-
box-sizing: border-box;
|
14
|
-
margin: 0;
|
15
|
-
padding: 0;
|
16
|
-
}
|
17
|
-
|
18
|
-
body {
|
19
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
20
|
-
line-height: 1.6;
|
21
|
-
color: #333;
|
22
|
-
background-color: #f8f9fa;
|
23
|
-
}
|
24
|
-
|
25
|
-
.container {
|
26
|
-
max-width: 1200px;
|
27
|
-
margin: 0 auto;
|
28
|
-
padding: 0 20px;
|
29
|
-
}
|
30
|
-
|
31
|
-
/* Header */
|
32
|
-
.header {
|
33
|
-
background: #fff;
|
34
|
-
border-bottom: 1px solid #dee2e6;
|
35
|
-
padding: 1rem 0;
|
36
|
-
margin-bottom: 2rem;
|
37
|
-
}
|
38
|
-
|
39
|
-
.header h1 {
|
40
|
-
color: #495057;
|
41
|
-
font-size: 1.5rem;
|
42
|
-
display: flex;
|
43
|
-
align-items: center;
|
44
|
-
gap: 0.5rem;
|
45
|
-
}
|
46
|
-
|
47
|
-
.header .trash-icon {
|
48
|
-
font-size: 1.8rem;
|
49
|
-
}
|
50
|
-
|
51
|
-
/* Navigation */
|
52
|
-
.nav {
|
53
|
-
margin-top: 1rem;
|
54
|
-
}
|
55
|
-
|
56
|
-
.nav a {
|
57
|
-
color: #6c757d;
|
58
|
-
text-decoration: none;
|
59
|
-
margin-right: 1.5rem;
|
60
|
-
padding: 0.5rem 0;
|
61
|
-
border-bottom: 2px solid transparent;
|
62
|
-
transition: all 0.2s;
|
63
|
-
}
|
64
|
-
|
65
|
-
.nav a:hover,
|
66
|
-
.nav a.active {
|
67
|
-
color: #495057;
|
68
|
-
border-bottom-color: #007bff;
|
69
|
-
}
|
70
|
-
|
71
|
-
/* Cards */
|
72
|
-
.card {
|
73
|
-
background: #fff;
|
74
|
-
border-radius: 8px;
|
75
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
76
|
-
padding: 1.5rem;
|
77
|
-
margin-bottom: 1rem;
|
78
|
-
}
|
79
|
-
|
80
|
-
/* Buttons */
|
81
|
-
.btn {
|
82
|
-
display: inline-block;
|
83
|
-
padding: 0.5rem 1rem;
|
84
|
-
border: none;
|
85
|
-
border-radius: 4px;
|
86
|
-
text-decoration: none;
|
87
|
-
cursor: pointer;
|
88
|
-
font-size: 0.875rem;
|
89
|
-
transition: all 0.2s;
|
90
|
-
}
|
91
|
-
|
92
|
-
.btn-primary {
|
93
|
-
background: #007bff;
|
94
|
-
color: white;
|
95
|
-
}
|
96
|
-
|
97
|
-
.btn-primary:hover {
|
98
|
-
background: #0056b3;
|
99
|
-
}
|
100
|
-
|
101
|
-
.btn-success {
|
102
|
-
background: #28a745;
|
103
|
-
color: white;
|
104
|
-
}
|
105
|
-
|
106
|
-
.btn-success:hover {
|
107
|
-
background: #1e7e34;
|
108
|
-
}
|
109
|
-
|
110
|
-
.btn-danger {
|
111
|
-
background: #dc3545;
|
112
|
-
color: white;
|
113
|
-
}
|
114
|
-
|
115
|
-
.btn-danger:hover {
|
116
|
-
background: #c82333;
|
117
|
-
}
|
118
|
-
|
119
|
-
.btn-sm {
|
120
|
-
padding: 0.25rem 0.75rem;
|
121
|
-
font-size: 0.8rem;
|
122
|
-
}
|
123
|
-
|
124
|
-
/* Tables */
|
125
|
-
.table {
|
126
|
-
width: 100%;
|
127
|
-
border-collapse: collapse;
|
128
|
-
background: #fff;
|
129
|
-
border-radius: 8px;
|
130
|
-
overflow: hidden;
|
131
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
132
|
-
}
|
133
|
-
|
134
|
-
.table th,
|
135
|
-
.table td {
|
136
|
-
padding: 1rem;
|
137
|
-
text-align: left;
|
138
|
-
border-bottom: 1px solid #dee2e6;
|
139
|
-
}
|
140
|
-
|
141
|
-
.table th {
|
142
|
-
background: #f8f9fa;
|
143
|
-
font-weight: 600;
|
144
|
-
color: #495057;
|
145
|
-
}
|
146
|
-
|
147
|
-
.table tr:hover {
|
148
|
-
background: #f8f9fa;
|
149
|
-
}
|
150
|
-
|
151
|
-
/* Stats */
|
152
|
-
.stats {
|
153
|
-
display: grid;
|
154
|
-
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
155
|
-
gap: 1rem;
|
156
|
-
margin-bottom: 2rem;
|
157
|
-
}
|
158
|
-
|
159
|
-
.stat-card {
|
160
|
-
background: #fff;
|
161
|
-
padding: 1.5rem;
|
162
|
-
border-radius: 8px;
|
163
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
164
|
-
text-align: center;
|
165
|
-
}
|
166
|
-
|
167
|
-
.stat-number {
|
168
|
-
font-size: 2rem;
|
169
|
-
font-weight: bold;
|
170
|
-
color: #007bff;
|
171
|
-
}
|
172
|
-
|
173
|
-
.stat-label {
|
174
|
-
color: #6c757d;
|
175
|
-
font-size: 0.875rem;
|
176
|
-
margin-top: 0.5rem;
|
177
|
-
}
|
178
|
-
|
179
|
-
/* Empty state */
|
180
|
-
.empty-state {
|
181
|
-
text-align: center;
|
182
|
-
padding: 4rem 2rem;
|
183
|
-
color: #6c757d;
|
184
|
-
}
|
185
|
-
|
186
|
-
.empty-state-icon {
|
187
|
-
font-size: 4rem;
|
188
|
-
margin-bottom: 1rem;
|
189
|
-
}
|
190
|
-
|
191
|
-
/* Responsive */
|
192
|
-
@media (max-width: 768px) {
|
193
|
-
.container {
|
194
|
-
padding: 0 15px;
|
195
|
-
}
|
196
|
-
|
197
|
-
.table {
|
198
|
-
font-size: 0.875rem;
|
199
|
-
}
|
200
|
-
|
201
|
-
.table th,
|
202
|
-
.table td {
|
203
|
-
padding: 0.75rem 0.5rem;
|
204
|
-
}
|
205
|
-
|
206
|
-
.btn {
|
207
|
-
font-size: 0.8rem;
|
208
|
-
padding: 0.4rem 0.8rem;
|
209
|
-
}
|
210
|
-
}
|
211
|
-
|
212
|
-
/* Alerts */
|
213
|
-
.alert {
|
214
|
-
padding: 0.75rem 1rem;
|
215
|
-
margin-bottom: 1rem;
|
216
|
-
border-radius: 4px;
|
217
|
-
}
|
218
|
-
|
219
|
-
.alert-success {
|
220
|
-
background: #d4edda;
|
221
|
-
color: #155724;
|
222
|
-
border: 1px solid #c3e6cb;
|
223
|
-
}
|
224
|
-
|
225
|
-
.alert-danger {
|
226
|
-
background: #f8d7da;
|
227
|
-
color: #721c24;
|
228
|
-
border: 1px solid #f5c6cb;
|
229
|
-
}
|
230
|
-
|
231
|
-
.alert-info {
|
232
|
-
background: #d1ecf1;
|
233
|
-
color: #0c5460;
|
234
|
-
border: 1px solid #bee5eb;
|
235
|
-
}
|
236
|
-
</style>
|
237
|
-
</head>
|
238
|
-
|
239
|
-
<body>
|
240
|
-
<div class="header">
|
241
|
-
<div class="container">
|
242
|
-
<h1>
|
243
|
-
<span class="trash-icon">🗑️</span>
|
244
|
-
Recycle Bin
|
245
|
-
</h1>
|
246
|
-
<nav class="nav">
|
247
|
-
<%= link_to "All Items", recycle_bin.trash_index_path,
|
248
|
-
class: ("active" if current_page?(recycle_bin.trash_index_path)) %>
|
249
|
-
<%= link_to "Statistics", "#", class: "disabled" %>
|
250
|
-
</nav>
|
251
|
-
</div>
|
252
|
-
</div>
|
253
|
-
|
254
|
-
<div class="container">
|
255
|
-
<% if notice %>
|
256
|
-
<div class="alert alert-success"><%= notice %></div>
|
257
|
-
<% end %>
|
258
|
-
|
259
|
-
<% if alert %>
|
260
|
-
<div class="alert alert-danger"><%= alert %></div>
|
261
|
-
<% end %>
|
262
|
-
|
263
|
-
<%= yield %>
|
264
|
-
</div>
|
265
|
-
</body>
|
266
|
-
</html>
|