railsui 3.2.7 → 3.3.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -1
  3. data/README.md +196 -42
  4. data/app/assets/javascripts/railsui-controllers.js +12 -0
  5. data/app/controllers/railsui/configurations_controller.rb +11 -2
  6. data/app/helpers/railsui/application_helper.rb +12 -0
  7. data/app/javascript/controllers/index.js +3 -31
  8. data/app/javascript/controllers/railsui_anchor_controller.js +4 -3
  9. data/app/javascript/controllers/railsui_auto_expand_text_area_controller.js +1 -1
  10. data/app/javascript/controllers/railsui_canvas_controller.js +1 -1
  11. data/app/javascript/controllers/railsui_code_controller.js +3 -28
  12. data/app/javascript/controllers/railsui_color_controller.js +1 -1
  13. data/app/javascript/controllers/railsui_configuration_controller.js +1 -1
  14. data/app/javascript/controllers/railsui_dialog_controller.js +1 -1
  15. data/app/javascript/controllers/railsui_flash_controller.js +1 -1
  16. data/app/javascript/controllers/railsui_helper_controller.js +1 -1
  17. data/app/javascript/controllers/railsui_loading_controller.js +1 -1
  18. data/app/javascript/controllers/railsui_modal_controller.js +4 -3
  19. data/app/javascript/controllers/railsui_nav_controller.js +4 -3
  20. data/app/javascript/controllers/railsui_pages_controller.js +1 -1
  21. data/app/javascript/controllers/railsui_prevent_controller.js +1 -1
  22. data/app/javascript/controllers/railsui_scroll_controller.js +1 -1
  23. data/app/javascript/controllers/railsui_scroll_spy_controller.js +1 -1
  24. data/app/javascript/controllers/railsui_search_controller.js +1 -1
  25. data/app/javascript/controllers/railsui_smooth_controller.js +1 -1
  26. data/app/javascript/controllers/railsui_snippet_controller.js +1 -1
  27. data/app/views/layouts/railsui/application.html.erb +7 -5
  28. data/app/views/layouts/railsui/fullwidth.html.erb +4 -4
  29. data/app/views/layouts/railsui/landing.html.erb +3 -4
  30. data/app/views/layouts/railsui/routes.html.erb +4 -3
  31. data/app/views/railsui/admin/_form.html.erb +18 -1
  32. data/app/views/railsui/admin/fields/_theme.html.erb +0 -1
  33. data/app/views/railsui/shared/_cdn_dependencies.html.erb +121 -0
  34. data/app/views/railsui/shared/_inline_controllers.html.erb +498 -0
  35. data/app/views/railsui/shared/_snippet.html.erb +23 -1
  36. data/app/views/railsui/themes/hound/forms/_input_group.html.erb +3 -1
  37. data/app/views/railsui/themes/shepherd/authentication/devise/_overview.html.erb +30 -28
  38. data/app/views/railsui/themes/shepherd/authentication/static/_overview.html.erb +8 -8
  39. data/app/views/railsui/themes/shepherd/content/typography/_headings.html.erb +23 -21
  40. data/app/views/railsui/themes/shepherd/forms/_input.html.erb +1 -1
  41. data/guides/CONFIGURATION.md +199 -0
  42. data/guides/MIGRATION_GUIDE.md +220 -0
  43. data/lib/generators/railsui/install/install_generator.rb +124 -38
  44. data/lib/generators/railsui/install/templates/Procfile.dev.build +1 -0
  45. data/lib/generators/railsui/install/templates/Procfile.dev.nobuild +2 -0
  46. data/lib/generators/railsui/install/templates/bin/dev +21 -0
  47. data/lib/generators/railsui/install/templates/themes/corgie/stylesheets/railsui/actiontext.css +0 -1
  48. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui.html.erb +7 -2
  49. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui_admin.html.erb +7 -2
  50. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui_auth.html.erb +6 -2
  51. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/pages/{privacy.html.erb → privacy_policy.html.erb} +1 -1
  52. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/pages/terms.html.erb +2 -2
  53. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/shared/sidebar/_link.html.erb +4 -4
  54. data/lib/generators/railsui/install/templates/themes/hound/stylesheets/railsui/actiontext.css +0 -1
  55. data/lib/generators/railsui/install/templates/themes/hound/views/layouts/rui/railsui.html.erb +6 -2
  56. data/lib/generators/railsui/install/templates/themes/hound/views/layouts/rui/railsui_admin.html.erb +6 -2
  57. data/lib/generators/railsui/install/templates/themes/shepherd/stylesheets/railsui/actiontext.css +0 -1
  58. data/lib/generators/railsui/install/templates/themes/shepherd/views/layouts/rui/railsui.html.erb +6 -2
  59. data/lib/generators/railsui/install/templates/themes/shepherd/views/layouts/rui/railsui_admin.html.erb +6 -2
  60. data/lib/generators/railsui/update/update_generator.rb +40 -4
  61. data/lib/railsui/configuration.rb +116 -15
  62. data/lib/railsui/engine.rb +15 -0
  63. data/lib/railsui/theme_setup.rb +598 -38
  64. data/lib/railsui/version.rb +1 -1
  65. data/lib/railsui.rb +10 -7
  66. data/lib/tasks/install.rake +9 -3
  67. data/lib/tasks/migrate.rake +219 -0
  68. metadata +26 -4
  69. data/.claude/settings.local.json +0 -10
@@ -0,0 +1,498 @@
1
+ // railsui-code
2
+ (function() {
3
+ const controller = class extends Stimulus.Controller {
4
+ connect() {
5
+ if (typeof hljs !== 'undefined' && hljs.highlightElement) {
6
+ this.snippetTargets.forEach((el) => {
7
+ if (!el.classList.contains('hljs')) {
8
+ hljs.highlightElement(el)
9
+ }
10
+ })
11
+ }
12
+ }
13
+ }
14
+ controller.targets = ["snippet"]
15
+ Stimulus.application.register("railsui-code", controller)
16
+ })();
17
+
18
+ // railsui-modal
19
+ (function() {
20
+ const controller = class extends Stimulus.Controller {
21
+ connect() {
22
+ if (useTransition) useTransition(this, { element: this.contentTarget })
23
+ if (useClickOutside) useClickOutside(this, { element: this.contentTarget })
24
+ }
25
+ open(event) {
26
+ event.preventDefault()
27
+ this.enableAppearance()
28
+ if (this.toggleTransition) this.toggleTransition()
29
+ }
30
+ close(event) {
31
+ event.preventDefault()
32
+ if (this.leave) this.leave()
33
+ this.disableAppearance()
34
+ }
35
+ clickOutside(event) {
36
+ const action = event.target.dataset.action
37
+ if (action == "click->modal#open" || action == "click->modal#open:prevent") return
38
+ this.close(event)
39
+ }
40
+ closeWithEsc(event) {
41
+ if (event.keyCode === 27 && !this.containerTarget.classList.contains('hidden')) {
42
+ this.close(event)
43
+ }
44
+ }
45
+ enableAppearance() {
46
+ this.containerTarget.classList.add("bg-black/80")
47
+ this.containerTarget.classList.remove('hidden')
48
+ }
49
+ disableAppearance() {
50
+ this.containerTarget.classList.add('hidden')
51
+ this.containerTarget.classList.remove("bg-black/80")
52
+ }
53
+ disconnect() {
54
+ if (this.toggleTransition) this.toggleTransition()
55
+ }
56
+ }
57
+ controller.targets = ['container', 'content']
58
+ Stimulus.application.register("railsui-modal", controller)
59
+ })();
60
+
61
+ // railsui-nav
62
+ (function() {
63
+ const controller = class extends Stimulus.Controller {
64
+ connect() {
65
+ if (useTransition) useTransition(this, { element: this.navTarget })
66
+ }
67
+ toggle() {
68
+ if (this.toggleTransition) this.toggleTransition()
69
+ this.swapIcon()
70
+ }
71
+ disconnect() {
72
+ if (this.leave) this.leave()
73
+ }
74
+ swapIcon() {
75
+ this.menuBarsTarget.classList.toggle('hidden')
76
+ this.menuCrossTarget.classList.toggle('hidden')
77
+ }
78
+ }
79
+ controller.targets = ['nav', 'menuBars', 'menuCross']
80
+ Stimulus.application.register("railsui-nav", controller)
81
+ })();
82
+
83
+ // railsui-prevent
84
+ Stimulus.application.register("railsui-prevent", class extends Stimulus.Controller {
85
+ prevent(event) { event.preventDefault() }
86
+ });
87
+
88
+ // railsui-loading
89
+ Stimulus.application.register("railsui-loading", class extends Stimulus.Controller {
90
+ load() { this.element.classList.add("opacity-50", "pointer-events-none") }
91
+ });
92
+
93
+ // railsui-flash
94
+ Stimulus.application.register("railsui-flash", class extends Stimulus.Controller {
95
+ connect() {
96
+ if (this.element) setTimeout(() => { this.element.remove() }, 4000)
97
+ }
98
+ });
99
+
100
+ // railsui-pages
101
+ (function() {
102
+ const controller = class extends Stimulus.Controller {
103
+ checkAll() {
104
+ const checkAllCheckbox = this.checkboxTargets[0]
105
+ const checkboxes = this.checkboxTargets.slice(1)
106
+ checkboxes.forEach((checkbox) => { checkbox.checked = !checkbox.checked })
107
+ checkAllCheckbox.checked = checkboxes.every((checkbox) => checkbox.checked)
108
+ }
109
+ }
110
+ controller.targets = ["checkbox"]
111
+ Stimulus.application.register("railsui-pages", controller)
112
+ })();
113
+
114
+ // railsui-search
115
+ (function() {
116
+ const controller = class extends Stimulus.Controller {
117
+ connect() {
118
+ this.currentResults = this.resultListTarget.innerHTML
119
+ }
120
+ search(event) {
121
+ this.filterList(event)
122
+ }
123
+ clear(event) {
124
+ event.target.value = ""
125
+ this._resetList()
126
+ }
127
+ filterList(event) {
128
+ this.resultTargets.forEach((result) => {
129
+ if (result.dataset.searchRouteValue.includes(event.target.value)) {
130
+ result.style.cssText = "display: block !important"
131
+ } else {
132
+ result.style.cssText = "display: none !important"
133
+ }
134
+ })
135
+ }
136
+ _resetList() {
137
+ this.resultListTarget.innerHTML = this.currentResults
138
+ }
139
+ }
140
+ controller.targets = ["result", "form", "resultList"]
141
+ Stimulus.application.register("railsui-search", controller)
142
+ })();
143
+
144
+ // railsui-snippet
145
+ (function() {
146
+ const controller = class extends Stimulus.Controller {
147
+ get ACTIVE_CLASSES() {
148
+ return ["bg-white", "px-3", "py-1.5", "rounded-md", "shadow", "flex", "items-center",
149
+ "justify-center", "gap-2", "text-[13px]", "font-semibold", "focus:ring-4",
150
+ "focus:ring-blue-600", "group", "dark:bg-neutral-800/90", "dark:text-neutral-100",
151
+ "dark:focus:ring-blue-600/50", "dark:text-neutral-300"]
152
+ }
153
+ get INACTIVE_CLASSES() {
154
+ return ["bg-transparent", "px-3", "py-1.5", "rounded-md", "shadow-none", "flex",
155
+ "items-center", "justify-center", "gap-2", "text-[13px]", "font-semibold", "dark:text-neutral-300"]
156
+ }
157
+ togglePreview(event) {
158
+ event.preventDefault()
159
+ this.toggle("preview")
160
+ }
161
+ toggleCode(event) {
162
+ event.preventDefault()
163
+ this.toggle("code")
164
+ this.highlightCode()
165
+ }
166
+ toggle(target) {
167
+ const activeClasses = this.ACTIVE_CLASSES
168
+ const inactiveClasses = this.INACTIVE_CLASSES
169
+ if (target === "preview") {
170
+ if (!this.previewTarget.classList.contains("hidden")) return
171
+ this.previewTarget.classList.toggle("hidden")
172
+ this.codeTarget.classList.add("hidden")
173
+ this.previewBtnTarget.className = ""
174
+ this.codeBtnTarget.className = ""
175
+ activeClasses.forEach((cls) => this.previewBtnTarget.classList.add(cls))
176
+ inactiveClasses.forEach((cls) => this.codeBtnTarget.classList.add(cls))
177
+ } else if (target === "code") {
178
+ if (!this.codeTarget.classList.contains("hidden")) return
179
+ this.codeTarget.classList.toggle("hidden")
180
+ this.previewTarget.classList.add("hidden")
181
+ this.previewBtnTarget.className = ""
182
+ this.codeBtnTarget.className = ""
183
+ activeClasses.forEach((cls) => this.codeBtnTarget.classList.add(cls))
184
+ inactiveClasses.forEach((cls) => this.previewBtnTarget.classList.add(cls))
185
+ }
186
+ }
187
+ highlightCode() {
188
+ if (typeof hljs !== 'undefined' && this.hasCodeTarget) {
189
+ const codeElements = this.codeTarget.querySelectorAll('pre code')
190
+ codeElements.forEach((el) => {
191
+ if (!el.classList.contains('hljs')) {
192
+ hljs.highlightElement(el)
193
+ }
194
+ })
195
+ }
196
+ }
197
+ }
198
+ controller.targets = ["preview", "previewBtn", "code", "codeBtn"]
199
+ Stimulus.application.register("railsui-snippet", controller)
200
+ })();
201
+
202
+ // railsui-canvas
203
+ Stimulus.application.register("railsui-canvas", class extends Stimulus.Controller {
204
+ connect() {
205
+ if (!this.element) return
206
+ var c = this.element, ctx = c.getContext("2d"), cw = (c.width = window.innerWidth),
207
+ ch = (c.height = window.innerHeight), points = [], tick = 0,
208
+ opt = { count: 5, range: { x: 40, y: 80 }, duration: { min: 40, max: 100 },
209
+ thickness: 0, strokeColor: "transparent", level: 0.65, curved: true },
210
+ rand = (min, max) => Math.floor(Math.random() * (max - min + 1) + min),
211
+ ease = (t, b, c, d) => {
212
+ if ((t /= d / 2) < 1) return (c / 2) * t * t + b
213
+ return (-c / 2) * (--t * (t - 2) - 1) + b
214
+ }
215
+ ctx.lineJoin = "round"; ctx.lineWidth = opt.thickness; ctx.strokeStyle = opt.strokeColor
216
+ var Point = function (config) {
217
+ this.anchorX = config.x; this.anchorY = config.y; this.x = config.x; this.y = config.y
218
+ this.setTarget()
219
+ }
220
+ Point.prototype.setTarget = function () {
221
+ this.initialX = this.x; this.initialY = this.y
222
+ this.targetX = this.anchorX + rand(0, opt.range.x * 2) - opt.range.x
223
+ this.targetY = this.anchorY + rand(0, opt.range.y * 2) - opt.range.y
224
+ this.tick = 0; this.duration = rand(opt.duration.min, opt.duration.max)
225
+ }
226
+ Point.prototype.update = function () {
227
+ var dx = this.targetX - this.x, dy = this.targetY - this.y, dist = Math.sqrt(dx * dx + dy * dy)
228
+ if (Math.abs(dist) <= 0) {
229
+ this.setTarget()
230
+ } else {
231
+ var t = this.tick, b = this.initialY, c = this.targetY - this.initialY, d = this.duration
232
+ this.y = ease(t, b, c, d); b = this.initialX; c = this.targetX - this.initialX; d = this.duration
233
+ this.x = ease(t, b, c, d); this.tick++
234
+ }
235
+ }
236
+ Point.prototype.render = function () {
237
+ ctx.beginPath(); ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false); ctx.fillStyle = "#000"; ctx.fill()
238
+ }
239
+ var updatePoints = () => { var i = points.length; while (i--) points[i].update() }
240
+ var renderShape = () => {
241
+ ctx.beginPath(); var pointCount = points.length; ctx.moveTo(points[0].x, points[0].y)
242
+ for (var i = 0; i < pointCount - 1; i++) {
243
+ var c = (points[i].x + points[i + 1].x) / 2, d = (points[i].y + points[i + 1].y) / 2
244
+ ctx.quadraticCurveTo(points[i].x, points[i].y, c, d)
245
+ }
246
+ ctx.lineTo(-opt.range.x - opt.thickness, ch + opt.thickness)
247
+ ctx.lineTo(cw + opt.range.x + opt.thickness, ch + opt.thickness); ctx.closePath()
248
+ var gradient = ctx.createLinearGradient(20, 300, 240, 0)
249
+ gradient.addColorStop(1, "#27272a"); gradient.addColorStop(0.05, "#18181b")
250
+ ctx.fillStyle = gradient; ctx.fill(); ctx.stroke()
251
+ }
252
+ var clear = () => ctx.clearRect(0, 0, cw, ch)
253
+ var loop = () => { window.requestAnimFrame(loop, c); tick++; clear(); updatePoints(); renderShape() }
254
+ var i = opt.count + 2, spacing = (cw + opt.range.x * 2) / (opt.count - 1)
255
+ while (i--) points.push(new Point({ x: spacing * (i - 1) - opt.range.x, y: ch - ch * opt.level }))
256
+ window.requestAnimFrame = (() => {
257
+ return window.requestAnimationFrame || window.webkitRequestAnimationFrame ||
258
+ window.mozRequestAnimationFrame || window.oRequestAnimationFrame ||
259
+ window.msRequestAnimationFrame || ((a) => window.setTimeout(a, 1e3 / 60))
260
+ })()
261
+ loop()
262
+ }
263
+ });
264
+
265
+ // railsui-scroll
266
+ (function() {
267
+ const controller = class extends Stimulus.Controller {
268
+ connect() {
269
+ if (this.hasScrollitemTarget) {
270
+ let scrollpos = localStorage.getItem("scrollpos")
271
+ if (scrollpos) this.scrollitemTarget.scrollTo(0, scrollpos)
272
+
273
+ window.onbeforeunload = () => {
274
+ localStorage.setItem("scrollpos", this.scrollitemTarget.scrollTop)
275
+ }
276
+ }
277
+
278
+ if (this.hasLauncherTarget) {
279
+ window.addEventListener('scroll', () => {
280
+ if (window.scrollY >= 800) {
281
+ this.launcherTarget.classList.remove('hidden')
282
+ } else {
283
+ this.launcherTarget.classList.add('hidden')
284
+ }
285
+ })
286
+ }
287
+ }
288
+ scrollToTop(event) {
289
+ event.preventDefault()
290
+ window.scrollTo({ top: 0, behavior: 'smooth' })
291
+ }
292
+ }
293
+ controller.targets = ["scrollitem", "launcher"]
294
+ Stimulus.application.register("railsui-scroll", controller)
295
+ })();
296
+
297
+ // railsui-scroll-spy
298
+ (function() {
299
+ const controller = class extends Stimulus.Controller {
300
+ connect() {
301
+ if (this.hasScrollContainerTarget) {
302
+ this.scrollHandler = this.scrollHandler.bind(this)
303
+ this.scrollContainerTarget.addEventListener("scroll", this.scrollHandler)
304
+ }
305
+ }
306
+ disconnect() {
307
+ this.scrollContainerTarget.removeEventListener("scroll", this.scrollHandler)
308
+ }
309
+ scrollHandler() {
310
+ const scrollPosition = this.scrollContainerTarget.scrollTop
311
+
312
+ this.linkTargets.forEach((link) => {
313
+ const targetId = link.getAttribute("href")
314
+ if (!targetId) return
315
+
316
+ const targetElement = document.querySelector(targetId)
317
+ if (targetElement) {
318
+ const targetPosition = targetElement.offsetTop
319
+ const targetHeight = targetElement.offsetHeight
320
+
321
+ if (scrollPosition >= targetPosition && scrollPosition < targetPosition + targetHeight) {
322
+ this.activateLink(link)
323
+ } else {
324
+ this.deactivateLink(link)
325
+ }
326
+ }
327
+ })
328
+ }
329
+ activateLink(link) {
330
+ const activeClasses = this.activeClassValue.split(" ")
331
+ activeClasses.forEach((className) => link.classList.add(className))
332
+
333
+ const inactiveClasses = this.inactiveClassValue.split(" ")
334
+ inactiveClasses.forEach((className) => link.classList.remove(className))
335
+ }
336
+ deactivateLink(link) {
337
+ const activeClasses = this.activeClassValue.split(" ")
338
+ activeClasses.forEach((className) => link.classList.remove(className))
339
+
340
+ const inactiveClasses = this.inactiveClassValue.split(" ")
341
+ inactiveClasses.forEach((className) => link.classList.add(className))
342
+ }
343
+ }
344
+ controller.targets = ["link", "scrollContainer"]
345
+ controller.values = { activeClass: String, inactiveClass: String }
346
+ Stimulus.application.register("railsui-scroll-spy", controller)
347
+ })();
348
+
349
+ // railsui-smooth
350
+ Stimulus.application.register("railsui-smooth", class extends Stimulus.Controller {
351
+ scroll(event) {
352
+ event.preventDefault()
353
+ const target = document.querySelector(event.currentTarget.hash)
354
+ if (target) {
355
+ target.scrollIntoView({ behavior: "smooth" })
356
+ const href = event.currentTarget.getAttribute("href")
357
+ if (href) history.pushState({}, "", href)
358
+ }
359
+ }
360
+ });
361
+
362
+ // railsui-toggle (empty placeholder - full version available as railsui-toggle-external from railsui-stimulus)
363
+ Stimulus.application.register("railsui-toggle", class extends Stimulus.Controller {});
364
+
365
+ // railsui-dialog
366
+ (function() {
367
+ const controller = class extends Stimulus.Controller {
368
+ launch(event) {
369
+ event.preventDefault()
370
+ this.dialogTarget.showModal()
371
+ }
372
+ cancel(event) {
373
+ event.preventDefault()
374
+ this.dialogTarget.close()
375
+ }
376
+ perform() {
377
+ this.buttonTarget.textContent = "Processing..."
378
+ this.buttonTarget.classList.add("opacity-50", "pointer-events-none")
379
+ this.cancelTarget.classList.add("hidden")
380
+ }
381
+ }
382
+ controller.targets = ["dialog", "button", "cancel"]
383
+ Stimulus.application.register("railsui-dialog", controller)
384
+ })();
385
+
386
+ // railsui-anchor
387
+ (function() {
388
+ const controller = class extends Stimulus.Controller {
389
+ copy(event) {
390
+ event.preventDefault()
391
+ navigator.clipboard.writeText(this.urlValue + `#${this.element.id}`)
392
+ }
393
+ }
394
+ controller.values = { url: String }
395
+ Stimulus.application.register("railsui-anchor", controller)
396
+ })();
397
+
398
+ // railsui-helper
399
+ (function() {
400
+ const controller = class extends Stimulus.Controller {
401
+ togglePath(event) {
402
+ event.preventDefault()
403
+ this.extensionTargets.forEach(t => { t.textContent = this.pathValue })
404
+ }
405
+ toggleUrl(event) {
406
+ event.preventDefault()
407
+ this.extensionTargets.forEach(t => { t.textContent = this.urlValue })
408
+ }
409
+ }
410
+ controller.targets = ["extension"]
411
+ controller.values = { path: String, url: String }
412
+ Stimulus.application.register("railsui-helper", controller)
413
+ })();
414
+
415
+ // railsui-configuration
416
+ (function() {
417
+ const controller = class extends Stimulus.Controller {
418
+ initialize() {
419
+ const urlParams = new URLSearchParams(window.location.search)
420
+ if (urlParams.get("update") === "true") {
421
+ setTimeout(() => {
422
+ this.removeURLParameter("update")
423
+ window.location.reload()
424
+ }, 3000)
425
+ }
426
+ }
427
+ connect() {
428
+ this.toggleLoader()
429
+ }
430
+ saveChanges(event) {
431
+ event.preventDefault()
432
+ this.savingTarget.classList.add("config-loader--active")
433
+ document.body.classList.add("overflow-hidden")
434
+ this.submitTarget.setAttribute("disabled", true)
435
+ this.element.submit()
436
+ }
437
+ toggleLoader() {
438
+ this.savingTarget.classList.remove("config-loader--active")
439
+ document.body.classList.remove("overflow-hidden")
440
+ }
441
+ removeURLParameter(param) {
442
+ const url = new URL(window.location.href)
443
+ url.searchParams.delete(param)
444
+ window.history.replaceState({}, "", url)
445
+ }
446
+ }
447
+ controller.targets = ["submit", "submitContainer", "saving"]
448
+ Stimulus.application.register("railsui-configuration", controller)
449
+ })();
450
+
451
+ // railsui-auto-expand-text-area
452
+ Stimulus.application.register("railsui-auto-expand-text-area", class extends Stimulus.Controller {
453
+ expand() {
454
+ this.element.style.height = `${this.element.scrollHeight + 2}px`
455
+ if (this.element.scrollHeight > 60) {
456
+ this.element.classList.remove("rounded-full")
457
+ this.element.classList.add("rounded-lg")
458
+ } else {
459
+ this.resetTextarea()
460
+ }
461
+ if (this.element.value.trim() === "") {
462
+ this.resetTextarea()
463
+ }
464
+ }
465
+ resetTextarea() {
466
+ this.element.style.height = "auto"
467
+ this.element.classList.add("rounded-full")
468
+ this.element.classList.remove("rounded-lg")
469
+ }
470
+ });
471
+
472
+ // ============================================================================
473
+ // External Controllers from railsui-stimulus package
474
+ // https://github.com/getrailsui/railsui-stimulus
475
+ // ============================================================================
476
+ // These controllers are loaded as ES modules after Stimulus is initialized.
477
+ // Note: railsui-modal-external and railsui-toggle-external are renamed to
478
+ // avoid conflicts with inline versions above.
479
+ if (typeof window.railsuiStimulusLoaded === 'undefined') {
480
+ window.railsuiStimulusLoaded = true;
481
+ import('https://unpkg.com/railsui-stimulus@1.1.2/dist/railsui-stimulus.module.js').then(module => {
482
+ Stimulus.application.register("railsui-clipboard", module.RailsuiClipboard);
483
+ Stimulus.application.register("railsui-count-up", module.RailsuiCountUp);
484
+ Stimulus.application.register("railsui-combobox", module.RailsuiCombobox);
485
+ Stimulus.application.register("railsui-date-range-picker", module.RailsuiDateRangePicker);
486
+ Stimulus.application.register("railsui-dropdown", module.RailsuiDropdown);
487
+ Stimulus.application.register("railsui-modal-external", module.RailsuiModal);
488
+ Stimulus.application.register("railsui-password-toggle", module.RailsuiPasswordToggle);
489
+ Stimulus.application.register("railsui-range", module.RailsuiRange);
490
+ Stimulus.application.register("railsui-read-more", module.RailsuiReadMore);
491
+ Stimulus.application.register("railsui-select-all", module.RailsuiSelectAll);
492
+ Stimulus.application.register("railsui-tabs", module.RailsuiTabs);
493
+ Stimulus.application.register("railsui-toast", module.RailsuiToast);
494
+ Stimulus.application.register("railsui-toggle-external", module.RailsuiToggle);
495
+ Stimulus.application.register("railsui-tooltip", module.RailsuiTooltip);
496
+ });
497
+ }
498
+
@@ -8,7 +8,29 @@
8
8
  css_content = yield :css
9
9
  %>
10
10
 
11
- <div data-controller="railsui-code" class="mt-5 mb-8 first:mt-0 last:mb-0 bg-gradient-to-br from-neutral-700 to-neutral-800 rounded-lg overflow-clip dark:border dark:border-neutral-700 selection:bg-neutral-300/90 selection:text-neutral-800 relative scrollbar border-transparent" x-data="{ active: '<%= local_assigns[:active_tab] %>' }">
11
+ <div data-controller="railsui-code" class="mt-5 mb-8 first:mt-0 last:mb-0 bg-gradient-to-br from-neutral-700 to-neutral-800 rounded-lg overflow-clip dark:border dark:border-neutral-700 selection:bg-neutral-300/90 selection:text-neutral-800 relative scrollbar border-transparent" x-data="{ active: '<%= local_assigns[:active_tab] %>' }" x-init="
12
+ // Highlight visible code on load
13
+ setTimeout(() => {
14
+ const codeElements = $el.querySelectorAll('pre code');
15
+ codeElements.forEach(el => {
16
+ if (el.offsetParent !== null && typeof hljs !== 'undefined' && !el.classList.contains('hljs')) {
17
+ hljs.highlightElement(el);
18
+ }
19
+ });
20
+ }, 100);
21
+
22
+ // Watch for tab changes and highlight new code
23
+ $watch('active', () => {
24
+ setTimeout(() => {
25
+ const codeElements = $el.querySelectorAll('pre code');
26
+ codeElements.forEach(el => {
27
+ if (el.offsetParent !== null && typeof hljs !== 'undefined' && !el.classList.contains('hljs')) {
28
+ hljs.highlightElement(el);
29
+ }
30
+ });
31
+ }, 50);
32
+ });
33
+ ">
12
34
  <div class="bg-neutral-800">
13
35
  <ul class="flex items-center justify-start space-x-2 border-b border-neutral-700 px-3">
14
36
  <% if content_for?(:html) %>
@@ -122,6 +122,8 @@
122
122
  <%% end %>
123
123
  <% end %>
124
124
 
125
+ <%= render_snippet %>
126
+ <% end %>
125
127
  <% end %>
126
128
  </div>
127
129
 
@@ -270,7 +272,7 @@
270
272
  <%%= f.label :website, class: "form-label" %>
271
273
  <div class="relative">
272
274
  <div class="absolute left-px border-r border-slate-300 top-px bg-slate-100 dark:bg-slate-700/80 dark:border-slate-700 dark:text-slate-200 h-[40px] text-base rounded-l-lg flex items-center justify-center px-3 text-slate-700 select-none">https://</div>
273
- <%%= f.text_field :website, class: "form-input pl-[90px]" placeholder: "example.com" "aria-label":"Website" %>
275
+ <%%= f.text_field :website, class: "form-input pl-[90px]", placeholder: "example.com", "aria-label": "Website" %>
274
276
  </div>
275
277
  </div>
276
278
  <%% end %>
@@ -13,7 +13,7 @@
13
13
  <li><%= link_to("Sign up", systems_authentication_devise_signup_path) %></li>
14
14
  <li><%= link_to("Sign in", systems_authentication_devise_signin_path) %></li>
15
15
  <li><%= link_to("Change password", systems_authentication_devise_change_password_path) %></li>
16
- <li><%= link_to("Reset password", path: systems_authentication_devise_reset_password_path) %></li>
16
+ <li><%= link_to("Reset password", systems_authentication_devise_reset_password_path) %></li>
17
17
  <li><%= link_to("Confirmation", systems_authentication_devise_confirmation_path) %></li>
18
18
  <li><%= link_to("Edit account", systems_authentication_devise_edit_path) %></li>
19
19
  <li><%= link_to("Unlock", systems_authentication_devise_unlocks_path) %></li>
@@ -94,7 +94,7 @@
94
94
  <% content_for :erb, flush: true do %>
95
95
  <%%= render "devise/auth_layout" do %>
96
96
  <!-- Add or yield form content here -->
97
- <%%% end %>
97
+ <%% end %>
98
98
  <% end %>
99
99
 
100
100
  <%= render_snippet(active_tab: "erb") %>
@@ -112,9 +112,9 @@
112
112
 
113
113
  <% content_for :erb, flush: true do %>
114
114
  <!-- app/views/devise/shared/_links -->
115
- <%#- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
116
- <%#= link_to "Forgot your password?", new_password_path(resource_name) %>
117
- <%# end %>
115
+ <%%#- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
116
+ <%%#= link_to "Forgot your password?", new_password_path(resource_name) %>
117
+ <%%# end %>
118
118
 
119
119
  <%% if devise_mapping.confirmable? && controller_name != 'confirmations' %>
120
120
  <div class="prose prose-sm prose-zinc dark:prose-invert py-3 text-center">
@@ -127,7 +127,6 @@
127
127
  <%%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
128
128
  </div>
129
129
  <%% end %>
130
-
131
130
  <% end %>
132
131
 
133
132
 
@@ -187,37 +186,40 @@
187
186
 
188
187
  <div id="auth-error-messages" class="py-6">
189
188
  <%= render layout: example, locals: { heading: "_error_messages partial" } do %>
190
- <div class="prose prose-neutral dark:prose-invert mb-6">
191
- <p>By default Rails UI copies over a pre-styled error partial made to work out of the box and save you time during development. This file is called <code>_error_messages.html.erb</code>.</p>
189
+ <div class="prose prose-neutral dark:prose-invert mb-6">
190
+ <p>By default Rails UI copies over a pre-styled error partial made to work out of the box and save you time during development. This file is called <code>_error_messages.html.erb</code>.</p>
192
191
 
193
- <p>The <%= theme_name.humanize %> theme leverages this partial for all form error rendering to keep the error/validation handling experience consistent.</p>
192
+ <p>The <%= theme_name.humanize %> theme leverages this partial for all form error rendering to keep the error/validation handling experience consistent.</p>
194
193
 
195
- <p>You may optionally swap the default Devise error_messages partial for this one.</p>
196
- </div>
194
+ <p>You may optionally swap the default Devise error_messages partial for this one.</p>
195
+ </div>
197
196
 
198
- <%= render preview 'zinc' do %>
197
+ <%= render preview 'zinc' do %>
199
198
  <div class="bg-primary-50/50 text-primary-700 sm:px-9 sm:py-6 px-6 py-6 rounded-lg mb-6 dark:bg-primary-400/10 dark:border dark:border-primary-400/20 dark:text-primary-50 text-sm" role="alert">
200
199
  <p class="font-semibold font-heading">1 error prohibited this post from being saved:</p>
201
200
  <ul class="list-disc mt-3 ml-4">
202
201
  <li>Title must exist</li>
203
202
  </ul>
204
203
  </div>
205
- <% end %>
204
+ <% end %>
206
205
 
207
- <% content_for :example, flush: true do %>
208
- <%= content_for :erb, flush: true do %>
206
+ <% content_for :example, flush: true do %>
207
+ <%= content_for :erb, flush: true do %>
209
208
  <!-- app/views/rui/shared/_error_messages.html.erb -->
210
209
  <%% if resource.errors.any? %>
211
- <div class="bg-primary-50/50 text-primary-700 sm:px-9 sm:py-6 px-6 py-6 rounded-lg mb-6 dark:bg-primary-400/10 dark:border dark:border-primary-400/20 dark:text-primary-50 text-sm" role="alert">
212
- <p class="font-semibold font-heading"><%%= pluralize(resource.errors.count, "error") %> prohibited this post from being saved:</p>
213
- <ul class="list-disc mt-3 ml-4">
214
- <%% resource.errors.each do |error| %>
215
- <li><%%= error.full_message %></li>
210
+ <div class="bg-primary-50/50 text-primary-700 sm:px-9 sm:py-6 px-6 py-6 rounded-lg mb-6 dark:bg-primary-400/10 dark:border dark:border-primary-400/20 dark:text-primary-50 text-sm" role="alert">
211
+ <p class="font-semibold font-heading"><%%= pluralize(resource.errors.count, "error") %> prohibited this post from being saved:</p>
212
+ <ul class="list-disc mt-3 ml-4">
213
+ <%% resource.errors.each do |error| %>
214
+ <li><%%= error.full_message %></li>
216
215
  <%% end %>
217
216
  </ul>
218
217
  </div>
219
218
  <%% end %>
220
- <% end %>
219
+ <% end %>
220
+
221
+ <%= render_snippet active_tab: :erb %>
222
+ <% end %>
221
223
 
222
224
  <% end %>
223
225
  </div>
@@ -225,11 +227,11 @@
225
227
  <%= system_pagination(prev_path: systems_components_tooltip_path, prev_text: "Tooltip", next_path: systems_authentication_devise_signup_path, next_text: "Sign up") %>
226
228
 
227
229
  <%= content_for :component_nav do %>
228
- <%= render layout: "railsui/shared/component_nav", locals: { title: "On this page" } do %>
229
- <%= component_link "Prerequisites", "#auth-prerequisites" %>
230
- <%= component_link "Main layout", "#auth-global-layout" %>
231
- <%= component_link "Links partial", "#auth-links-partial" %>
232
- <%= component_link "OmniAuth", "#auth-omniauth-ui" %>
233
- <%= component_link "Error messages", "#auth-error-messages" %>
234
- <% end %>
230
+ <%= render layout: "railsui/shared/component_nav", locals: { title: "On this page" } do %>
231
+ <%= component_link "Prerequisites", "#auth-prerequisites" %>
232
+ <%= component_link "Main layout", "#auth-global-layout" %>
233
+ <%= component_link "Links partial", "#auth-links-partial" %>
234
+ <%= component_link "OmniAuth", "#auth-omniauth-ui" %>
235
+ <%= component_link "Error messages", "#auth-error-messages" %>
236
+ <% end %>
235
237
  <% end %>