glassy_loader 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,360 @@
1
+ @import "./library/themes";
2
+ @import "./library/animations";
3
+
4
+ :root {
5
+ /* Default Next.js Style */
6
+ --glassy-loader-bg: rgba(255, 255, 255, 0.1);
7
+ --glassy-loader-blur: 10px;
8
+ --glassy-loader-border: rgba(255, 255, 255, 0.2);
9
+ --glassy-loader-spinner-color: #000000;
10
+ --glassy-loader-text-color: #171717;
11
+ --glassy-progress-color: #000000;
12
+ --glassy-skeleton-bg: rgba(0, 0, 0, 0.05);
13
+ --glassy-success-color: #22c55e;
14
+ --glassy-error-color: #ef4444;
15
+ }
16
+
17
+ @media (prefers-color-scheme: dark) {
18
+ :root {
19
+ --glassy-loader-bg: rgba(0, 0, 0, 0.3);
20
+ --glassy-loader-spinner-color: #ffffff;
21
+ --glassy-loader-text-color: #ededed;
22
+ --glassy-progress-color: #ffffff;
23
+ --glassy-skeleton-bg: rgba(255, 255, 255, 0.05);
24
+ }
25
+ }
26
+
27
+ /* Theme: Apple (Minimal Blur) */
28
+ .glassy-theme-apple {
29
+ --glassy-loader-bg: rgba(255, 255, 255, 0.4);
30
+ --glassy-loader-blur: 20px;
31
+ --glassy-loader-spinner-color: #86868b;
32
+ }
33
+
34
+ /* Theme: Cyberpunk (Neon) */
35
+ .glassy-theme-cyberpunk {
36
+ --glassy-loader-bg: rgba(13, 2, 33, 0.7);
37
+ --glassy-loader-blur: 5px;
38
+ --glassy-loader-spinner-color: #00ff00;
39
+ --glassy-loader-border: #00ff00;
40
+ --glassy-loader-text-color: #00ff00;
41
+ --glassy-progress-color: #00ff00;
42
+ }
43
+
44
+ /* Liquid Progress Bar (Premium) */
45
+ .glassy-progress--liquid .glassy-progress-bar {
46
+ position: relative;
47
+ overflow: hidden;
48
+ }
49
+
50
+ .glassy-progress--liquid .glassy-progress-bar::after {
51
+ content: "";
52
+ position: absolute;
53
+ top: -50%; left: -50%; width: 200%; height: 200%;
54
+ background: rgba(255, 255, 255, 0.2);
55
+ border-radius: 40%;
56
+ animation: glassy-liquid 2s linear infinite;
57
+ }
58
+
59
+ @keyframes glassy-liquid {
60
+ from { transform: rotate(0deg); }
61
+ to { transform: rotate(360deg); }
62
+ }
63
+
64
+ /* Base Classes */
65
+ .glassy-loader {
66
+ display: flex;
67
+ flex-direction: column;
68
+ align-items: center;
69
+ justify-content: center;
70
+ z-index: 9999;
71
+ background: var(--glassy-loader-bg);
72
+ backdrop-filter: blur(var(--glassy-loader-blur));
73
+ -webkit-backdrop-filter: blur(var(--glassy-loader-blur));
74
+ border: 1px solid var(--glassy-loader-border);
75
+ transition: opacity 0.3s ease;
76
+ opacity: 0;
77
+ }
78
+
79
+ .glassy-loader--full-screen {
80
+ position: fixed;
81
+ top: 0; left: 0;
82
+ width: 100vw; height: 100vh;
83
+ }
84
+
85
+ .glassy-loader--container {
86
+ position: absolute;
87
+ top: 0; left: 0;
88
+ width: 100%; height: 100%;
89
+ }
90
+
91
+ .glassy-loader__spinner-container {
92
+ position: relative;
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: center;
96
+ width: 60px; height: 60px;
97
+ }
98
+
99
+ /* Animations */
100
+
101
+ /* 1. Spin */
102
+ .glassy-anim-spin .glassy-loader__spinner {
103
+ width: 50px; height: 50px;
104
+ border: 3px solid var(--glassy-loader-border);
105
+ border-top-color: var(--glassy-loader-spinner-color);
106
+ border-radius: 50%;
107
+ animation: glassy-spin 1s linear infinite;
108
+ }
109
+
110
+ /* 2. Pulse */
111
+ .glassy-anim-pulse .glassy-loader__spinner {
112
+ width: 40px; height: 40px;
113
+ background: var(--glassy-loader-spinner-color);
114
+ border-radius: 50%;
115
+ animation: glassy-pulse 1.2s ease-in-out infinite;
116
+ }
117
+
118
+ /* 3. Dots */
119
+ .glassy-anim-dots .glassy-loader__spinner {
120
+ width: 12px; height: 12px;
121
+ background: var(--glassy-loader-spinner-color);
122
+ border-radius: 50%;
123
+ box-shadow: 20px 0 var(--glassy-loader-spinner-color), -20px 0 var(--glassy-loader-spinner-color);
124
+ animation: glassy-dots 1s infinite alternate;
125
+ }
126
+
127
+ /* 4. Orbit (Premium) */
128
+ .glassy-anim-orbit .glassy-loader__spinner {
129
+ width: 50px; height: 50px;
130
+ position: relative;
131
+ perspective: 1000px;
132
+ }
133
+
134
+ .glassy-anim-orbit .glassy-loader__spinner::before,
135
+ .glassy-anim-orbit .glassy-loader__spinner::after {
136
+ content: "";
137
+ position: absolute;
138
+ top: 0; left: 0; width: 100%; height: 100%;
139
+ border-radius: 50%;
140
+ border: 2px solid transparent;
141
+ border-top-color: var(--glassy-loader-spinner-color);
142
+ animation: glassy-orbit 1.5s linear infinite;
143
+ }
144
+
145
+ .glassy-anim-orbit .glassy-loader__spinner::after {
146
+ width: 70%; height: 70%; top: 15%; left: 15%;
147
+ border-top-color: var(--glassy-loader-spinner-color);
148
+ animation-duration: 1s;
149
+ animation-direction: reverse;
150
+ opacity: 0.6;
151
+ }
152
+
153
+ @keyframes glassy-orbit {
154
+ 0% { transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg); }
155
+ 100% { transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg); }
156
+ }
157
+
158
+ @keyframes glassy-spin { to { transform: rotate(360deg); } }
159
+ @keyframes glassy-pulse {
160
+ 0%, 100% { transform: scale(1); opacity: 0.6; }
161
+ 50% { transform: scale(1.5); opacity: 0.2; }
162
+ }
163
+ @keyframes glassy-dots {
164
+ 0% { transform: scale(1); opacity: 1; }
165
+ 100% { transform: scale(0.5); opacity: 0.3; }
166
+ }
167
+
168
+ /* State Icons (Success/Error) */
169
+ .glassy-loader__state-icon {
170
+ position: absolute;
171
+ width: 30px; height: 30px;
172
+ display: none;
173
+ align-items: center;
174
+ justify-content: center;
175
+ }
176
+
177
+ .glassy-loader--success .glassy-loader__spinner { display: none; }
178
+ .glassy-loader--success .glassy-loader__state-icon { display: flex; }
179
+ .glassy-loader--success .glassy-loader__state-icon::before {
180
+ content: "✓";
181
+ font-size: 30px;
182
+ color: var(--glassy-success-color);
183
+ font-weight: bold;
184
+ animation: glassy-pop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
185
+ }
186
+
187
+ .glassy-loader--error .glassy-loader__spinner { display: none; }
188
+ .glassy-loader--error .glassy-loader__state-icon { display: flex; }
189
+ .glassy-loader--error .glassy-loader__state-icon::before {
190
+ content: "✕";
191
+ font-size: 30px;
192
+ color: var(--glassy-error-color);
193
+ font-weight: bold;
194
+ animation: glassy-pop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
195
+ }
196
+
197
+ @keyframes glassy-pop {
198
+ 0% { transform: scale(0); opacity: 0; }
199
+ 100% { transform: scale(1); opacity: 1; }
200
+ }
201
+
202
+ /* Progress Bar & Skeletons */
203
+ .glassy-progress-bar-container {
204
+ position: fixed;
205
+ top: 0; left: 0; width: 100%; height: 3px;
206
+ z-index: 10000; display: none;
207
+ }
208
+
209
+ .glassy-progress-bar {
210
+ height: 100%; width: 0%;
211
+ background: var(--glassy-progress-color);
212
+ box-shadow: 0 0 8px var(--glassy-progress-glow, transparent);
213
+ transition: width 0.4s ease;
214
+ }
215
+
216
+ .glassy-skeleton {
217
+ background: var(--glassy-skeleton-bg);
218
+ position: relative; overflow: hidden;
219
+ }
220
+
221
+ .glassy-skeleton::after {
222
+ content: ""; position: absolute; top: 0; left: -150%; width: 150%; height: 100%;
223
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
224
+ animation: glassy-shimmer 2s infinite;
225
+ }
226
+
227
+ @keyframes glassy-shimmer {
228
+ 100% { left: 150%; }
229
+ }
230
+
231
+ /* Skeleton Layouts */
232
+ .glassy-skeleton-layout {
233
+ display: flex;
234
+ flex-direction: column;
235
+ gap: 20px;
236
+ width: 100%;
237
+ }
238
+
239
+ .glassy-skeleton-row {
240
+ display: flex;
241
+ align-items: center;
242
+ gap: 15px;
243
+ }
244
+
245
+ .glassy-skeleton-stack {
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 8px;
249
+ flex: 1;
250
+ }
251
+
252
+ .glassy-skeleton-profile {
253
+ display: flex;
254
+ flex-direction: column;
255
+ align-items: center;
256
+ gap: 12px;
257
+ text-align: center;
258
+ }
259
+
260
+ .glassy-skeleton-grid {
261
+ display: grid;
262
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
263
+ gap: 15px;
264
+ }
265
+
266
+ .glassy-card {
267
+ background: var(--glassy-loader-bg);
268
+ backdrop-filter: blur(var(--glassy-loader-blur));
269
+ border: 1px solid var(--glassy-loader-border);
270
+ border-radius: 12px; padding: 1.5rem;
271
+ }
272
+
273
+ /* Button Loader */
274
+ .glassy-button-loader {
275
+ position: relative;
276
+ overflow: hidden;
277
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
278
+ display: inline-flex;
279
+ align-items: center;
280
+ justify-content: center;
281
+ cursor: pointer;
282
+ border: 1px solid var(--glassy-loader-border);
283
+ background: var(--glassy-loader-bg);
284
+ backdrop-filter: blur(8px);
285
+ padding: 0.5rem 1.5rem;
286
+ border-radius: 8px;
287
+ color: var(--glassy-loader-text-color);
288
+ font-weight: 600;
289
+ }
290
+
291
+ .glassy-button-text {
292
+ transition: opacity 0.3s, transform 0.3s;
293
+ }
294
+
295
+ .glassy-button-spinner-container {
296
+ position: absolute;
297
+ top: 0; left: 0; width: 100%; height: 100%;
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ opacity: 0;
302
+ pointer-events: none;
303
+ transition: opacity 0.3s;
304
+ }
305
+
306
+ .glassy-button-loader.loading .glassy-button-text {
307
+ opacity: 0;
308
+ transform: translateY(-10px);
309
+ }
310
+
311
+ .glassy-button-loader.loading .glassy-button-spinner-container {
312
+ opacity: 1;
313
+ }
314
+
315
+ /* Toast Loader */
316
+ .glassy-toast {
317
+ position: fixed;
318
+ bottom: 2rem; right: 2rem;
319
+ z-index: 10001;
320
+ display: flex;
321
+ align-items: center;
322
+ gap: 1rem;
323
+ padding: 1rem 1.5rem;
324
+ border-radius: 12px;
325
+ border: 1px solid var(--glassy-loader-border);
326
+ background: var(--glassy-loader-bg);
327
+ backdrop-filter: blur(12px);
328
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
329
+ transform: translateY(100px);
330
+ opacity: 0;
331
+ transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.4s;
332
+ }
333
+
334
+ .glassy-toast.show {
335
+ transform: translateY(0);
336
+ opacity: 1;
337
+ }
338
+
339
+ .glassy-toast__loader {
340
+ width: 30px; height: 30px;
341
+ position: relative;
342
+ }
343
+
344
+ .glassy-toast__message {
345
+ font-size: 0.875rem;
346
+ color: var(--glassy-loader-text-color);
347
+ }
348
+
349
+ /* Responsive Scaling */
350
+ @media (max-width: 768px) {
351
+ .glassy-loader {
352
+ transform: scale(0.9);
353
+ }
354
+ }
355
+
356
+ @media (max-width: 480px) {
357
+ .glassy-loader {
358
+ transform: scale(0.8);
359
+ }
360
+ }
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GlassyLoaderHelper
4
+ def glassy_loader_tag(message: nil, full_screen: true, id: "glassy-loader", theme: nil, animation: nil, duration: nil, container: false, size: nil, class_name: nil, spinner_class: nil, delay: nil, min_duration: nil)
5
+ theme ||= GlassyLoader.configuration.theme
6
+ animation ||= GlassyLoader.configuration.animation
7
+ duration ||= GlassyLoader.configuration.duration
8
+
9
+ classes = [
10
+ "glassy-loader",
11
+ "glassy-theme-#{theme}",
12
+ "glassy-anim-#{animation}",
13
+ ("glassy-loader--full-screen" if full_screen && !container),
14
+ ("glassy-loader--container" if container),
15
+ class_name
16
+ ].compact.join(" ")
17
+
18
+ style = ["display: none;"]
19
+ style << "font-size: #{size};" if size
20
+
21
+ data_attributes = {
22
+ duration: duration,
23
+ delay: delay,
24
+ min_duration: min_duration
25
+ }.compact
26
+
27
+ content_tag :div, id: id, class: classes, style: style.join(" "), data: data_attributes, role: "status", aria: { live: "polite", busy: "false" } do
28
+ safe_join([
29
+ content_tag(:div, nil, class: "glassy-loader__spinner-container") do
30
+ case animation.to_s
31
+ when "folding-cube"
32
+ content_tag(:div, nil, class: "glassy-loader__folding-cube") do
33
+ 4.times.map { |i| content_tag(:div, nil, class: "glassy-loader__cube-face face-#{i+1}") }.join.html_safe
34
+ end
35
+ when "infinity"
36
+ content_tag(:svg, class: "glassy-loader__infinity", viewBox: "0 0 256 128") do
37
+ content_tag(:path, nil, class: "glassy-loader__infinity-path", d: "M128 64C128 64 153.962 32 192 32C230.038 32 256 64 256 64C256 64 230.038 96 192 96C153.962 96 128 64 128 64C128 64 102.038 32 64 32C25.9619 32 0 64 0 64C0 64 25.9619 96 64 96C102.038 96 128 64 128 64Z")
38
+ end
39
+ else
40
+ safe_join([
41
+ content_tag(:div, nil, class: ["glassy-loader__spinner", spinner_class].compact.join(" ")),
42
+ content_tag(:div, nil, class: "glassy-loader__state-icon")
43
+ ])
44
+ end
45
+ end,
46
+ (content_tag(:div, message, class: "glassy-loader__message") if message)
47
+ ].compact)
48
+ end
49
+ end
50
+
51
+ def glassy_skeleton_layout(type: :feed, items: 3, theme: nil, staggered: true)
52
+ theme ||= GlassyLoader.configuration.theme
53
+ content_tag :div, class: "glassy-skeleton-layout glassy-skeleton-#{type} glassy-theme-#{theme}" do
54
+ items.times.map do |i|
55
+ delay = staggered ? "#{i * 0.1}s" : "0s"
56
+ case type
57
+ when :feed
58
+ content_tag :div, class: "glassy-skeleton-row", style: "animation-delay: #{delay}" do
59
+ safe_join([
60
+ glassy_skeleton_tag(width: "50px", height: "50px", border_radius: "50%"),
61
+ content_tag(:div, class: "glassy-skeleton-stack") do
62
+ safe_join([
63
+ glassy_skeleton_tag(width: "70%", height: "15px"),
64
+ glassy_skeleton_tag(width: "40%", height: "10px")
65
+ ])
66
+ end
67
+ ])
68
+ end
69
+ when :profile
70
+ content_tag :div, class: "glassy-skeleton-profile", style: "animation-delay: #{delay}" do
71
+ safe_join([
72
+ glassy_skeleton_tag(width: "100px", height: "100px", border_radius: "50%"),
73
+ glassy_skeleton_tag(width: "200px", height: "30px"),
74
+ glassy_skeleton_tag(width: "150px", height: "15px")
75
+ ])
76
+ end
77
+ when :grid
78
+ glassy_skeleton_tag(width: "100%", height: "150px", class_name: "glassy-skeleton-item", theme: theme)
79
+ end
80
+ end.join.html_safe
81
+ end
82
+ end
83
+
84
+ def glassy_button_loader_tag(text, id: nil, class_name: nil, theme: nil, animation: :spin-1)
85
+ theme ||= GlassyLoader.configuration.theme
86
+ content_tag :button, id: id, class: ["glassy-button-loader", "glassy-theme-#{theme}", class_name].compact.join(" ") do
87
+ safe_join([
88
+ content_tag(:span, text, class: "glassy-button-text"),
89
+ content_tag(:div, nil, class: "glassy-button-spinner-container") do
90
+ glassy_loader_tag(id: "#{id}-spinner", animation: animation, full_screen: false, container: true, theme: theme)
91
+ end
92
+ ])
93
+ end
94
+ end
95
+
96
+ def glassy_toast_tag(message, id: "glassy-toast", theme: nil, animation: :dots-1)
97
+ theme ||= GlassyLoader.configuration.theme
98
+ content_tag :div, id: id, class: ["glassy-toast", "glassy-theme-#{theme}"].compact.join(" "), style: "display: none;" do
99
+ safe_join([
100
+ content_tag(:div, nil, class: "glassy-toast__loader") do
101
+ glassy_loader_tag(animation: animation, full_screen: false, container: true, theme: theme)
102
+ end,
103
+ content_tag(:div, message, class: "glassy-toast__message")
104
+ ])
105
+ end
106
+ end
107
+
108
+ def glassy_progress_bar_tag(id: "glassy-progress-bar", theme: nil, liquid: false)
109
+ theme ||= GlassyLoader.configuration.theme
110
+ classes = [
111
+ "glassy-progress-bar-container",
112
+ "glassy-theme-#{theme}",
113
+ ("glassy-progress--liquid" if liquid)
114
+ ].compact.join(" ")
115
+
116
+ content_tag :div, id: id, class: classes do
117
+ content_tag :div, nil, class: "glassy-progress-bar"
118
+ end
119
+ end
120
+
121
+ def glassy_skeleton_tag(width: "100%", height: "20px", border_radius: "4px", class_name: nil, theme: nil)
122
+ theme ||= GlassyLoader.configuration.theme
123
+ content_tag :div, nil,
124
+ class: ["glassy-skeleton", "glassy-theme-#{theme}", class_name].compact.join(" "),
125
+ style: "width: #{width}; height: #{height}; border-radius: #{border_radius};"
126
+ end
127
+
128
+ def glassy_card_tag(id: nil, class_name: nil, theme: nil, &block)
129
+ theme ||= GlassyLoader.configuration.theme
130
+ content_tag :div, id: id, class: ["glassy-card", "glassy-theme-#{theme}", class_name].compact.join(" ") do
131
+ capture(&block) if block_given?
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GlassyLoader
4
+ class Configuration
5
+ attr_accessor :theme, :animation, :duration
6
+
7
+ def initialize
8
+ @theme = :default
9
+ @animation = :spin
10
+ @duration = nil
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GlassyLoader
4
+ class Engine < ::Rails::Engine
5
+ # No isolate_namespace to allow global helper inclusion
6
+
7
+ initializer "glassy_loader.assets" do |app|
8
+ app.config.assets.precompile += %w[glassy_loader/main.css glassy_loader/loader.js]
9
+ end
10
+
11
+ initializer "glassy_loader.helpers" do
12
+ ActiveSupport.on_load(:action_view) do
13
+ require_relative "../../app/helpers/glassy_loader_helper"
14
+ include GlassyLoaderHelper
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GlassyLoader
4
+ VERSION = "1.2.0"
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require_relative "glassy_loader/version"
5
+ require_relative "glassy_loader/configuration"
6
+ require_relative "glassy_loader/engine" if defined?(Rails)
7
+
8
+ module GlassyLoader
9
+ class Error < StandardError; end
10
+
11
+ class << self
12
+ attr_writer :configuration
13
+
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield(configuration)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ module GlassyLoader
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: glassy_loader
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Shiboshree Roy
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: railties
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '6.0'
26
+ description: A production-ready gem providing high-quality glassmorphism loading overlays
27
+ and spinners for Rails applications.
28
+ email:
29
+ - shiboshreeroy169@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - app/assets/javascripts/glassy_loader/loader.js
39
+ - app/assets/stylesheets/glassy_loader/library/_animations.css
40
+ - app/assets/stylesheets/glassy_loader/library/_themes.css
41
+ - app/assets/stylesheets/glassy_loader/main.css
42
+ - app/helpers/glassy_loader_helper.rb
43
+ - lib/glassy_loader.rb
44
+ - lib/glassy_loader/configuration.rb
45
+ - lib/glassy_loader/engine.rb
46
+ - lib/glassy_loader/version.rb
47
+ - sig/glassy_loader.rbs
48
+ homepage: https://github.com/shiboshreeroy/glassy_loader
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ source_code_uri: https://github.com/shiboshreeroy/glassy_loader
53
+ changelog_uri: https://github.com/shiboshreeroy/glassy_loader/blob/main/CHANGELOG.md
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 3.2.0
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 4.0.11
69
+ specification_version: 4
70
+ summary: Premium glassy loading animations for Ruby on Rails.
71
+ test_files: []