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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 11b64a3ac54fffda9abe80e4f0fbd0a047c6f4231609ae10ad36d06a0e1b69a0
4
+ data.tar.gz: 0e2fdc86d23dace9beb09ee02a44a84fb4070067a59f41a0516b136cab7d09f1
5
+ SHA512:
6
+ metadata.gz: c6034f62ca424e96314ee79ebf93c8193fda0447c5473c37c5fd28de734888ca0c50cff05f8691d05970b745958668fa903134141bcbef453788e7506b505fe0
7
+ data.tar.gz: 96e8c865533349801e356f7e8035989e8b4eb799a2c7a8c2e6efb7a9da2802e5aaf2bb39324273648139204305f6d4463a717266c466712b9740258cae4e8fdc
data/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.2.0] - 2026-06-03
9
+
10
+ ### Added
11
+ - **Button Loaders:** New `glassy_button_loader_tag` helper for premium inline loading states.
12
+ - **Glassy Toasts:** New `glassy_toast_tag` helper for background process notifications.
13
+ - **Staggered Animations:** Automatic entrance delays for skeleton layouts (`staggered: true`).
14
+ - **New JS Methods:** Added `showToast()`, `hideToast()`, and `toggleButton()` to the API.
15
+ - **UI/UX Polish:** Enhanced blur transitions and smoother entrance keyframes for all components.
16
+
17
+ ## [1.1.0] - 2026-06-03
18
+
19
+ ### Added
20
+ - **Skeleton Layouts:** Professional presets for `feed`, `profile`, and `grid` patterns.
21
+ - **UX Polish:** Added `delay` and `min_duration` to prevent loading flickers.
22
+ - **Accessibility:** Native ARIA roles, `aria-busy`, and `aria-live` support.
23
+ - **Interactive Mode:** New `initInteractive()` JS method for mouse-reactive 3D tilt effects.
24
+ - **Direct Progress Control:** New `updateProgress()` JS method for manual progress bar updates.
25
+ - **Responsive Scaling:** Automatic scaling for tablets and mobile devices.
26
+ - **Production Ready:** Stabilized API and comprehensive documentation.
27
+
28
+ ## [0.5.0] - 2026-06-03
29
+
30
+ ### Added
31
+ - **Massive Animation Library:** Added 110+ premium loading animations across 5 categories.
32
+ - **Premium Theme Library:** Added 20+ designer themes (`apple`, `gold`, `ocean`, etc.).
33
+ - **Tailwind CSS Integration:** Full compatibility with Tailwind classes.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 shiboshreeroy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # GlassyLoader 💎
2
+
3
+ **Professional Loading UI Suite for Ruby on Rails**
4
+ *Developed by Shiboshree Roy*
5
+
6
+ ---
7
+
8
+ GlassyLoader is a premium Ruby on Rails gem providing an elite collection of **110+ glassmorphism animations** and **20+ designer themes**. Built for high-end production applications, it combines sophisticated design (Next.js, Apple, Luxury Mesh) with realistic UX patterns (Flicker Prevention, ARIA Accessibility).
9
+
10
+ ## 🚀 Key Features
11
+
12
+ - 💎 **110+ Animations:** From classic spinners to 3D `folding-cube` and `infinity` loops.
13
+ - 🌌 **Designer Themes:** Pro themes including `apple`, `cyberpunk`, `midnight-gold`, and `liquid-mesh`.
14
+ - ðŸĶī **Realistic Skeletons:** One-line layout presets for `feed`, `profile`, and `grid`.
15
+ - âģ **UX Pro Patterns:** Built-in `delay` and `min_duration` to eliminate loading flickers.
16
+ - 🌑 **Adaptive Theming:** Native support for Dark/Light mode and system preferences.
17
+ - ðŸ“ą **Mobile Optimized:** Fully responsive scaling and touch-friendly interaction.
18
+ - ðŸ–ą **Interactive 3D Tilt:** Mouse-reactive glass elements for an ultra-premium feel.
19
+ - 🔘 **Button Loaders:** Integrated loading states for buttons and forms.
20
+ - ⚡ **Staggered Skeletons:** Organic entrance animations for multi-item layouts.
21
+ - 🍞 **Glassy Toasts:** High-end background loading notifications.
22
+
23
+ ---
24
+
25
+ ## 🛠 Installation
26
+
27
+ Add this line to your application's Gemfile:
28
+
29
+ ```ruby
30
+ gem 'glassy_loader'
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ ```bash
36
+ $ bundle install
37
+ ```
38
+
39
+ ### Include Assets
40
+
41
+ In your `application.css`:
42
+ ```css
43
+ /*= require glassy_loader/main */
44
+ ```
45
+
46
+ In your `application.js`:
47
+ ```javascript
48
+ //= require glassy_loader/loader
49
+ ```
50
+
51
+ ---
52
+
53
+ ## ⚙ïļ Global Configuration
54
+
55
+ Set your project-wide defaults in `config/initializers/glassy_loader.rb`:
56
+
57
+ ```ruby
58
+ GlassyLoader.configure do |config|
59
+ config.theme = :apple # Options: :glassy, :apple, :cyberpunk, :midnight_gold, :liquid_mesh...
60
+ config.animation = :spin-1 # Options: :spin-1..30, :dots-1..30, :pulse-1..22, :folding_cube...
61
+ config.duration = nil # Default auto-hide time in seconds
62
+ end
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 📖 Usage Guide
68
+
69
+ ### 1. The Pro Loader (Flicker-Free)
70
+ The most realistic way to load data. It waits 200ms before showing (skipping ultra-fast requests) and ensures it stays visible for at least 800ms to be readable.
71
+
72
+ ```erb
73
+ <%= glassy_loader_tag id: "main-loader", delay: 0.2, min_duration: 0.8, theme: :apple %>
74
+ ```
75
+
76
+ ### 2. Luxury Mesh & Premium Animations
77
+ For high-end landing pages or dashboards.
78
+
79
+ ```erb
80
+ <!-- 3D Folding Cube with Animated Mesh Background -->
81
+ <%= glassy_loader_tag animation: :folding_cube, theme: :liquid_mesh, message: "INITIALIZING..." %>
82
+
83
+ <!-- SVG Infinity Ribbon with Deep Gold Theme -->
84
+ <%= glassy_loader_tag animation: :infinity, theme: :midnight_gold %>
85
+ ```
86
+
87
+ ### 3. Professional Skeleton Layouts
88
+ Use realistic placeholders that match your content structure to improve perceived performance.
89
+
90
+ ```erb
91
+ <!-- Feed Pattern (Avatar + Stacked Lines) -->
92
+ <%= glassy_skeleton_layout type: :feed, items: 3 %>
93
+
94
+ <!-- Profile Pattern (Large Avatar + Centered Text) -->
95
+ <%= glassy_skeleton_layout type: :profile %>
96
+
97
+ <!-- Grid Pattern -->
98
+ <%= glassy_skeleton_layout type: :grid, items: 6 %>
99
+
100
+ ### 4. Premium UI/UX Components
101
+
102
+ #### Glassy Button Loader
103
+ Perfect for "Submit" or "Buy Now" buttons.
104
+ ```erb
105
+ <%= glassy_button_loader_tag "Confirm Payment", id: "pay-btn", theme: :gold %>
106
+ ```
107
+ ```javascript
108
+ // Toggle loading state
109
+ GlassyLoader.toggleButton('pay-btn', true);
110
+ ```
111
+
112
+ #### Glassy Loading Toast
113
+ For non-intrusive background tasks (syncing, uploading).
114
+ ```erb
115
+ <%= glassy_toast_tag "Uploading 4 files...", id: "upload-toast", theme: :apple %>
116
+ ```
117
+ ```javascript
118
+ // Show with auto-hide duration (in seconds)
119
+ GlassyLoader.showToast('upload-toast', { duration: 5 });
120
+ ```
121
+
122
+ ---
123
+
124
+ ---
125
+
126
+ ## ðŸ•đ JavaScript API
127
+
128
+ Control your loaders programmatically for advanced workflows.
129
+
130
+ ### Visibility & States
131
+ ```javascript
132
+ // Show with 3D tilt effect enabled
133
+ GlassyLoader.show('my-loader');
134
+ GlassyLoader.initInteractive('my-loader');
135
+
136
+ // Morph to Success state (shows checkmark + message)
137
+ GlassyLoader.success('my-loader', 'Payment Complete!');
138
+
139
+ // Morph to Error state (shows cross + message)
140
+ GlassyLoader.error('my-loader', 'Transaction Failed');
141
+ ```
142
+
143
+ ### Progress Bar Control
144
+ ```javascript
145
+ // Automatic randomized progress (YouTube style)
146
+ GlassyLoader.startProgress('main-progress-bar');
147
+
148
+ // Direct manual update (Real-world data streams)
149
+ GlassyLoader.updateProgress('main-progress-bar', 75);
150
+
151
+ // Complete and hide
152
+ GlassyLoader.stopProgress('main-progress-bar');
153
+ ```
154
+
155
+ ---
156
+
157
+ ## ðŸŽĻ Themes Reference
158
+
159
+ | Theme | Vibe | Key Features |
160
+ | :--- | :--- | :--- |
161
+ | `:apple` | Minimalist | High blur (25px), soft white/gray. |
162
+ | `:cyberpunk` | Tech/Neon | Neon green, high contrast, hard edges. |
163
+ | `:midnight_gold` | Luxury | Mesh radial gradients, amber & gold accents. |
164
+ | `:liquid_mesh` | Living UI | Animated shifting gradients, ultra-modern. |
165
+ | `:holographic` | Creative | Multi-color shimmer, vibrant. |
166
+
167
+ ---
168
+
169
+ ## 📜 License & Credits
170
+
171
+ - **Developer:** Shiboshree Roy
172
+ - **License:** The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
173
+
174
+ For bug reports or feature requests, please visit the [GitHub Repository](https://github.com/shiboshreeroy/glassy_loader).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,224 @@
1
+ window.GlassyLoader = {
2
+ _timers: {},
3
+ _startTimes: {},
4
+
5
+ // Overlay Loader
6
+ show: function(id = 'glassy-loader', options = {}) {
7
+ const el = document.getElementById(id);
8
+ if (!el) return;
9
+
10
+ const delay = parseFloat(options.delay || el.getAttribute('data-delay') || 0);
11
+ const minDuration = parseFloat(options.minDuration || el.getAttribute('data-min-duration') || 0);
12
+
13
+ // Prevent flicker: Wait 'delay' before showing
14
+ this._timers[id + '_delay'] = setTimeout(() => {
15
+ el.classList.remove('glassy-loader--success', 'glassy-loader--error');
16
+ el.style.display = 'flex';
17
+ el.setAttribute('aria-busy', 'true');
18
+
19
+ requestAnimationFrame(() => {
20
+ el.style.opacity = '1';
21
+ });
22
+
23
+ this._startTimes[id] = Date.now();
24
+
25
+ // Handle auto-hide duration
26
+ const duration = options.duration || el.getAttribute('data-duration');
27
+ if (duration) {
28
+ this._timers[id + '_duration'] = setTimeout(() => {
29
+ this.hide(id);
30
+ }, parseFloat(duration) * 1000);
31
+ }
32
+ }, delay * 1000);
33
+ },
34
+
35
+ hide: function(id = 'glassy-loader') {
36
+ const el = document.getElementById(id);
37
+ if (!el) return;
38
+
39
+ // Clear pending show delay
40
+ clearTimeout(this._timers[id + '_delay']);
41
+
42
+ const startTime = this._startTimes[id];
43
+ const minDuration = parseFloat(el.getAttribute('data-min-duration') || 0) * 1000;
44
+ const elapsed = startTime ? Date.now() - startTime : 0;
45
+ const remaining = Math.max(0, minDuration - elapsed);
46
+
47
+ // Ensure it stays visible for at least minDuration
48
+ setTimeout(() => {
49
+ el.style.opacity = '0';
50
+ el.setAttribute('aria-busy', 'false');
51
+ setTimeout(() => {
52
+ el.style.display = 'none';
53
+ el.classList.remove('glassy-loader--success', 'glassy-loader--error');
54
+ }, 300);
55
+ }, remaining);
56
+ },
57
+
58
+ success: function(id = 'glassy-loader', message = null) {
59
+ const el = document.getElementById(id);
60
+ if (el) {
61
+ el.classList.remove('glassy-loader--error');
62
+ el.classList.add('glassy-loader--success');
63
+ if (message) {
64
+ const msgEl = el.querySelector('.glassy-loader__message');
65
+ if (msgEl) msgEl.textContent = message;
66
+ }
67
+ setTimeout(() => this.hide(id), 2000);
68
+ }
69
+ },
70
+
71
+ error: function(id = 'glassy-loader', message = null) {
72
+ const el = document.getElementById(id);
73
+ if (el) {
74
+ el.classList.remove('glassy-loader--success');
75
+ el.classList.add('glassy-loader--error');
76
+ if (message) {
77
+ const msgEl = el.querySelector('.glassy-loader__message');
78
+ if (msgEl) msgEl.textContent = message;
79
+ }
80
+ setTimeout(() => this.hide(id), 3000);
81
+ }
82
+ },
83
+
84
+ // YouTube-style Progress Bar
85
+ _progressInterval: null,
86
+
87
+ startProgress: function(id = 'glassy-progress-bar') {
88
+ const container = document.getElementById(id);
89
+ if (!container) return;
90
+
91
+ const bar = container.querySelector('.glassy-progress-bar');
92
+ if (!bar) return;
93
+
94
+ container.style.display = 'block';
95
+ container.setAttribute('aria-busy', 'true');
96
+ bar.style.width = '0%';
97
+ bar.style.opacity = '1';
98
+
99
+ let width = 0;
100
+ if (this._progressInterval) clearInterval(this._progressInterval);
101
+
102
+ this._progressInterval = setInterval(() => {
103
+ if (width >= 90) {
104
+ clearInterval(this._progressInterval);
105
+ } else {
106
+ width += Math.random() * 5;
107
+ bar.style.width = width + '%';
108
+ }
109
+ }, 200);
110
+ },
111
+
112
+ updateProgress: function(id = 'glassy-progress-bar', percentage) {
113
+ const container = document.getElementById(id);
114
+ if (!container) return;
115
+ const bar = container.querySelector('.glassy-progress-bar');
116
+ if (!bar) return;
117
+
118
+ clearInterval(this._progressInterval);
119
+ container.style.display = 'block';
120
+ bar.style.width = percentage + '%';
121
+ if (percentage >= 100) setTimeout(() => this.stopProgress(id), 200);
122
+ },
123
+
124
+ // Toast Control
125
+ showToast: function(id = 'glassy-toast', options = {}) {
126
+ const el = document.getElementById(id);
127
+ if (!el) return;
128
+ el.style.display = 'flex';
129
+ requestAnimationFrame(() => {
130
+ el.classList.add('show');
131
+ });
132
+
133
+ if (options.duration) {
134
+ setTimeout(() => this.hideToast(id), options.duration * 1000);
135
+ }
136
+ },
137
+
138
+ hideToast: function(id = 'glassy-toast') {
139
+ const el = document.getElementById(id);
140
+ if (!el) return;
141
+ el.classList.remove('show');
142
+ setTimeout(() => {
143
+ el.style.display = 'none';
144
+ }, 400);
145
+ },
146
+
147
+ // Button Control
148
+ toggleButton: function(id, isLoading = true) {
149
+ const el = document.getElementById(id);
150
+ if (!el) return;
151
+ const spinner = el.querySelector('.glassy-loader');
152
+
153
+ if (isLoading) {
154
+ el.classList.add('loading');
155
+ el.disabled = true;
156
+ if (spinner) this.show(spinner.id);
157
+ } else {
158
+ el.classList.remove('loading');
159
+ el.disabled = false;
160
+ if (spinner) this.hide(spinner.id);
161
+ }
162
+ },
163
+
164
+ // Interactive Effects
165
+ initInteractive: function(id = 'glassy-loader') {
166
+ const el = document.getElementById(id);
167
+ if (!el) return;
168
+
169
+ el.addEventListener('mousemove', (e) => {
170
+ const { left, top, width, height } = el.getBoundingClientRect();
171
+ const x = (e.clientX - left) / width - 0.5;
172
+ const y = (e.clientY - top) / height - 0.5;
173
+
174
+ const spinner = el.querySelector('.glassy-loader__spinner-container');
175
+ if (spinner) {
176
+ spinner.style.transform = `rotateY(${x * 20}deg) rotateX(${y * -20}deg)`;
177
+ }
178
+ });
179
+
180
+ el.addEventListener('mouseleave', () => {
181
+ const spinner = el.querySelector('.glassy-loader__spinner-container');
182
+ if (spinner) spinner.style.transform = 'rotateY(0) rotateX(0)';
183
+ });
184
+ },
185
+
186
+ stopProgress: function(id = 'glassy-progress-bar') {
187
+ const container = document.getElementById(id);
188
+ if (!container) return;
189
+
190
+ const bar = container.querySelector('.glassy-progress-bar');
191
+ if (!bar) return;
192
+
193
+ clearInterval(this._progressInterval);
194
+ bar.style.width = '100%';
195
+
196
+ setTimeout(() => {
197
+ bar.style.opacity = '0';
198
+ container.setAttribute('aria-busy', 'false');
199
+ setTimeout(() => {
200
+ container.style.display = 'none';
201
+ bar.style.width = '0%';
202
+ }, 400);
203
+ }, 300);
204
+ }
205
+ };
206
+
207
+ // Turbo integration
208
+ document.addEventListener("turbo:before-visit", function() {
209
+ if (document.getElementById('glassy-loader-auto')) {
210
+ GlassyLoader.show('glassy-loader-auto');
211
+ }
212
+ if (document.getElementById('glassy-progress-bar-auto')) {
213
+ GlassyLoader.startProgress('glassy-progress-bar-auto');
214
+ }
215
+ });
216
+
217
+ document.addEventListener("turbo:load", function() {
218
+ if (document.getElementById('glassy-loader-auto')) {
219
+ GlassyLoader.hide('glassy-loader-auto');
220
+ }
221
+ if (document.getElementById('glassy-progress-bar-auto')) {
222
+ GlassyLoader.stopProgress('glassy-progress-bar-auto');
223
+ }
224
+ });