glib-web 4.39.1 → 4.40.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 +4 -4
- data/app/controllers/glib/api_docs_controller.rb +145 -0
- data/app/helpers/glib/json_ui/abstract_builder.rb +16 -0
- data/app/helpers/glib/json_ui/action_builder/dialogs.rb +4 -0
- data/app/helpers/glib/json_ui/list_builders.rb +2 -0
- data/app/helpers/glib/json_ui/page_helper.rb +6 -0
- data/app/helpers/glib/json_ui/view_builder/fields.rb +554 -34
- data/app/helpers/glib/json_ui/view_builder/panels.rb +455 -12
- data/app/helpers/glib/json_ui/view_builder.rb +1 -1
- data/app/views/glib/api_docs/component.json.jbuilder +215 -0
- data/app/views/glib/api_docs/index.json.jbuilder +103 -0
- data/app/views/glib/api_docs/show.json.jbuilder +111 -0
- data/app/views/json_ui/garage/lists/edit_actions.json.jbuilder +96 -66
- data/app/views/json_ui/garage/lists/edit_mode.json.jbuilder +58 -41
- data/app/views/json_ui/garage/lists/templating.json.jbuilder +68 -44
- data/app/views/json_ui/garage/panels/timeline.json.jbuilder +82 -73
- data/app/views/json_ui/garage/test_page/lifecycle.json.jbuilder +3 -0
- data/app/views/json_ui/garage/views/markdowns.json.jbuilder +2 -0
- data/config/routes.rb +4 -0
- data/lib/glib/rubocop/cops/test_name_parentheses.rb +33 -0
- data/lib/glib/rubocop.rb +1 -0
- data/lib/glib/snapshot.rb +75 -17
- data/lib/tasks/docs.rake +59 -0
- metadata +12 -6
|
@@ -2,16 +2,57 @@ require 'js_regex'
|
|
|
2
2
|
|
|
3
3
|
class Glib::JsonUi::ViewBuilder
|
|
4
4
|
module Panels
|
|
5
|
+
# Form panel for collecting user input and submitting data.
|
|
6
|
+
#
|
|
7
|
+
# A form panel automatically handles CSRF tokens, form validation, and data submission.
|
|
8
|
+
# It supports nested associations and dynamic field groups.
|
|
9
|
+
#
|
|
10
|
+
# @example Basic form with text field
|
|
11
|
+
# panel.panels_form url: users_path, method: :post do |form|
|
|
12
|
+
# form.fields_text prop: :name, label: 'Full Name'
|
|
13
|
+
# form.fields_email prop: :email
|
|
14
|
+
# form.fields_submit text: 'Create User'
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# @example Form with model binding
|
|
18
|
+
# panel.panels_form model: @user, autoValidate: true do |form|
|
|
19
|
+
# form.fields_text prop: :name # Automatically gets label from I18n
|
|
20
|
+
# form.fields_email prop: :email
|
|
21
|
+
# form.fields_submit text: 'Save'
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# @example Form with onChange callback
|
|
25
|
+
# panel.panels_form url: products_path, onChange: ->(action) do
|
|
26
|
+
# action.http_get url: preview_product_path, silent: true
|
|
27
|
+
# end do |form|
|
|
28
|
+
# form.fields_select prop: :category_id, options: @categories
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# @see https://guides.rubyonrails.org/form_helpers.html Rails Form Helpers
|
|
5
32
|
class Form < View
|
|
6
33
|
attr_reader :model_name # See Panels::Form.field_name
|
|
7
34
|
attr_reader :_autoValidate
|
|
8
35
|
attr_reader :disable_dirty_check
|
|
9
36
|
attr_accessor :current_dynamic_group
|
|
10
37
|
|
|
38
|
+
# Action called when form is submitted successfully.
|
|
39
|
+
# Receives form data and can trigger navigation, dialogs, etc.
|
|
11
40
|
action :onSubmit
|
|
41
|
+
|
|
42
|
+
# Action called whenever any form field value changes.
|
|
43
|
+
# Useful for real-time previews or dependent field updates.
|
|
12
44
|
action :onChange
|
|
45
|
+
|
|
46
|
+
# Similar to onChange but triggers a page reload with new data.
|
|
47
|
+
# Use this when field changes require server-side processing.
|
|
13
48
|
action :onChangeAndLoad
|
|
49
|
+
|
|
50
|
+
# Custom parameter name for form data when submitting.
|
|
51
|
+
# By default, uses the model name as the parameter namespace.
|
|
14
52
|
string :paramNameForFormData
|
|
53
|
+
|
|
54
|
+
# If true, form submission will not use AJAX (full page reload).
|
|
55
|
+
# Set to true for file downloads or when you need full page refresh.
|
|
15
56
|
bool :local
|
|
16
57
|
|
|
17
58
|
def autoValidate(autoValidate)
|
|
@@ -265,28 +306,87 @@ class Glib::JsonUi::ViewBuilder
|
|
|
265
306
|
end
|
|
266
307
|
end
|
|
267
308
|
|
|
309
|
+
# List panel for displaying scrollable collections of items.
|
|
310
|
+
#
|
|
311
|
+
# Lists can display data in various formats (cards, rows, etc.) with support for
|
|
312
|
+
# pagination, infinite scrolling, and drag-and-drop reordering.
|
|
313
|
+
#
|
|
314
|
+
# @example Basic list with items
|
|
315
|
+
# panel.panels_list width: 'matchParent', firstSection: ->(section) do
|
|
316
|
+
# section.header childViews: ->(header) do
|
|
317
|
+
# header.h2 text: 'Products'
|
|
318
|
+
# end
|
|
319
|
+
# @products.each do |product|
|
|
320
|
+
# section.row childViews: ->(row) do
|
|
321
|
+
# row.label text: product.name
|
|
322
|
+
# row.label text: product.price
|
|
323
|
+
# end
|
|
324
|
+
# end
|
|
325
|
+
# end
|
|
326
|
+
#
|
|
327
|
+
# @example List with pagination
|
|
328
|
+
# panel.panels_list \
|
|
329
|
+
# nextPage: { url: products_path(page: @page + 1) },
|
|
330
|
+
# prevPage: { url: products_path(page: @page - 1) },
|
|
331
|
+
# firstSection: ->(section) do
|
|
332
|
+
# # ... items
|
|
333
|
+
# end
|
|
334
|
+
#
|
|
335
|
+
# @example Responsive grid list
|
|
336
|
+
# panel.panels_list responsiveCols: 3, firstSection: ->(section) do
|
|
337
|
+
# @images.each do |image|
|
|
338
|
+
# section.row childViews: ->(row) do
|
|
339
|
+
# row.image url: image.url
|
|
340
|
+
# end
|
|
341
|
+
# end
|
|
342
|
+
# end
|
|
268
343
|
class List < View
|
|
269
|
-
#
|
|
344
|
+
# Prefix for field names when list is used in edit mode.
|
|
345
|
+
# Setting this turns the list into an editable collection.
|
|
270
346
|
string :fieldPrefix
|
|
271
347
|
|
|
272
|
-
#
|
|
348
|
+
# Field name for editable title in list items.
|
|
349
|
+
# Enables inline editing of item titles.
|
|
273
350
|
string :fieldTitleName
|
|
351
|
+
|
|
352
|
+
# Field name for editable subtitle in list items.
|
|
274
353
|
string :fieldSubtitleName
|
|
354
|
+
|
|
355
|
+
# Field name for editable sub-subtitle in list items.
|
|
275
356
|
string :fieldSubsubtitleName
|
|
276
357
|
|
|
277
|
-
#
|
|
278
|
-
# deprecated
|
|
358
|
+
# Conditional check values for "check all" / "uncheck all" functionality.
|
|
359
|
+
# @deprecated Use custom checkbox handling instead
|
|
279
360
|
hash :fieldCheckValueIf
|
|
280
361
|
|
|
362
|
+
# Phoenix WebSocket configuration for real-time updates.
|
|
281
363
|
hash :phoenixSocket
|
|
282
364
|
# hash :actionCable
|
|
283
365
|
|
|
366
|
+
# Configuration for next page in pagination.
|
|
367
|
+
# Provide a hash with :url key pointing to the next page.
|
|
368
|
+
# @example { url: products_path(page: @page + 1) }
|
|
284
369
|
hash :nextPage
|
|
370
|
+
|
|
371
|
+
# Configuration for previous page in pagination.
|
|
372
|
+
# Provide a hash with :url key pointing to the previous page.
|
|
285
373
|
hash :prevPage
|
|
374
|
+
|
|
375
|
+
# Action triggered when user scrolls to the top of the list.
|
|
376
|
+
# Useful for pull-to-refresh functionality.
|
|
286
377
|
action :onScrollToTop
|
|
378
|
+
|
|
379
|
+
# Action triggered when user scrolls to the bottom of the list.
|
|
380
|
+
# Useful for infinite scrolling / load more functionality.
|
|
287
381
|
action :onScrollToBottom
|
|
288
382
|
|
|
383
|
+
# Number of columns for responsive grid layout.
|
|
384
|
+
# Items will be arranged in a grid with this many columns.
|
|
385
|
+
# @example responsiveCols: 3
|
|
289
386
|
int :responsiveCols
|
|
387
|
+
|
|
388
|
+
# Configuration for drag-and-drop reordering support.
|
|
389
|
+
# @example dragSupport: { onDrop: { action: 'http/post', url: reorder_path } }
|
|
290
390
|
hash :dragSupport
|
|
291
391
|
|
|
292
392
|
def firstSection(block)
|
|
@@ -310,7 +410,11 @@ class Glib::JsonUi::ViewBuilder
|
|
|
310
410
|
singleton_array :styleClass, :styleClasses
|
|
311
411
|
array :events
|
|
312
412
|
views :childViews
|
|
313
|
-
|
|
413
|
+
# Controls which end(s) of the timeline line to truncate.
|
|
414
|
+
# @see https://vuetifyjs.com/en/api/v-timeline/#props-truncate-line Vuetify Timeline truncateLine
|
|
415
|
+
enum :truncateLine, options: [:start, :end, :both]
|
|
416
|
+
enum :side, options: [:start, :end]
|
|
417
|
+
enum :direction, options: [:horizontal, :vertical]
|
|
314
418
|
end
|
|
315
419
|
|
|
316
420
|
# deprecated
|
|
@@ -445,82 +549,421 @@ class Glib::JsonUi::ViewBuilder
|
|
|
445
549
|
end
|
|
446
550
|
end
|
|
447
551
|
|
|
552
|
+
# Scrollable container panel for content that exceeds viewport height.
|
|
553
|
+
#
|
|
554
|
+
# Scroll panels automatically add scrollbars when content overflows.
|
|
555
|
+
# This is the most common container for page content.
|
|
556
|
+
#
|
|
557
|
+
# @example Basic scrollable content
|
|
558
|
+
# page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
|
|
559
|
+
# scroll.h1 text: 'Welcome'
|
|
560
|
+
# scroll.p text: 'Long content here...'
|
|
561
|
+
# end
|
|
448
562
|
class Scroll < View
|
|
563
|
+
# Child components to display inside the scroll container.
|
|
564
|
+
# Provide a block that receives the view builder for adding content.
|
|
449
565
|
views :childViews
|
|
450
566
|
end
|
|
451
567
|
|
|
568
|
+
# Split panel for creating multi-column layouts with fixed side panels.
|
|
569
|
+
#
|
|
570
|
+
# Split panels divide the horizontal space into left, center, and right sections.
|
|
571
|
+
# The center section expands to fill available space, while side sections
|
|
572
|
+
# maintain their content width.
|
|
573
|
+
#
|
|
574
|
+
# @example Two-column layout
|
|
575
|
+
# panel.panels_split width: 'matchParent', content: ->(content) do
|
|
576
|
+
# content.left childViews: ->(left) do
|
|
577
|
+
# left.button text: 'Menu'
|
|
578
|
+
# end
|
|
579
|
+
# content.center childViews: ->(center) do
|
|
580
|
+
# center.h1 text: 'Main Content', width: 'matchParent'
|
|
581
|
+
# end
|
|
582
|
+
# end
|
|
583
|
+
#
|
|
584
|
+
# @example Three-column layout with alignment
|
|
585
|
+
# panel.panels_split width: 'matchParent', align: 'middle', content: ->(content) do
|
|
586
|
+
# content.left childViews: ->(left) do
|
|
587
|
+
# left.button text: 'Back'
|
|
588
|
+
# end
|
|
589
|
+
# content.center childViews: ->(center) do
|
|
590
|
+
# center.label text: 'Page Title'
|
|
591
|
+
# end
|
|
592
|
+
# content.right childViews: ->(right) do
|
|
593
|
+
# right.button text: 'Save'
|
|
594
|
+
# end
|
|
595
|
+
# end
|
|
596
|
+
#
|
|
597
|
+
# @see app/views/json_ui/garage/panels/split.json.jbuilder Garage examples
|
|
452
598
|
class Split < View
|
|
453
599
|
# def content(block)
|
|
454
600
|
# block.call page.split_content_builder
|
|
455
601
|
# end
|
|
456
|
-
|
|
602
|
+
|
|
603
|
+
# Vertical alignment of content within the split panel.
|
|
604
|
+
# Aligns items to top, middle, or bottom of the panel height.
|
|
605
|
+
# @example align: 'middle'
|
|
606
|
+
enum :align, options: [:top, :middle, :bottom]
|
|
607
|
+
|
|
608
|
+
# Content builder for defining left, center, and right sections.
|
|
609
|
+
# Use content.left, content.center, or content.right to define each section.
|
|
457
610
|
panels_builder :content, :left, :center, :right
|
|
458
611
|
end
|
|
459
612
|
|
|
613
|
+
# Responsive grid panel using Vuetify's 12-column grid system.
|
|
614
|
+
#
|
|
615
|
+
# Responsive panels automatically adjust layout based on screen size.
|
|
616
|
+
# Use panels_column children to define grid columns with breakpoint-specific sizing.
|
|
617
|
+
#
|
|
618
|
+
# @example Responsive two-column layout
|
|
619
|
+
# panel.panels_responsive width: 'matchParent', childViews: ->(responsive) do
|
|
620
|
+
# responsive.panels_column lg: { cols: 8 }, xs: { cols: 12 }, childViews: ->(col) do
|
|
621
|
+
# col.h1 text: 'Main Content'
|
|
622
|
+
# end
|
|
623
|
+
# responsive.panels_column lg: { cols: 4 }, xs: { cols: 12 }, childViews: ->(col) do
|
|
624
|
+
# col.h2 text: 'Sidebar'
|
|
625
|
+
# end
|
|
626
|
+
# end
|
|
627
|
+
#
|
|
628
|
+
# @example With hover effect
|
|
629
|
+
# panel.panels_responsive \
|
|
630
|
+
# styleClasses: ['card'],
|
|
631
|
+
# hoverViews: ->(hover) { hover.label text: 'Click me!' },
|
|
632
|
+
# onClick: ->(action) { action.windows_open url: product_path(@product) },
|
|
633
|
+
# childViews: ->(panel) do
|
|
634
|
+
# panel.h3 text: @product.name
|
|
635
|
+
# end
|
|
636
|
+
#
|
|
637
|
+
# @see https://vuetifyjs.com/en/components/grids/ Vuetify Grid Documentation
|
|
638
|
+
# @see app/views/json_ui/garage/panels/responsive.json.jbuilder Garage examples
|
|
460
639
|
class Responsive < View
|
|
640
|
+
# Child components to display in the responsive grid.
|
|
641
|
+
# Typically contains panels_column components.
|
|
461
642
|
views :childViews
|
|
462
|
-
|
|
643
|
+
|
|
644
|
+
# Horizontal alignment of child columns.
|
|
645
|
+
# @example align: 'center'
|
|
646
|
+
enum :align, options: [:left, :center, :right]
|
|
647
|
+
|
|
648
|
+
# Action triggered when the panel is clicked.
|
|
649
|
+
# Makes the entire responsive panel clickable.
|
|
463
650
|
action :onClick
|
|
651
|
+
|
|
652
|
+
# Views to display when hovering over the panel.
|
|
653
|
+
# Useful for showing tooltips or preview content on mouse hover.
|
|
464
654
|
views :hoverViews
|
|
465
655
|
|
|
466
|
-
# Experimental
|
|
656
|
+
# Experimental: Additional panel sections for complex layouts.
|
|
657
|
+
# @note These are experimental features
|
|
467
658
|
panels_builder :accessory, :header, :footer
|
|
468
659
|
end
|
|
469
660
|
|
|
661
|
+
# Grid column for use within panels_responsive containers.
|
|
662
|
+
#
|
|
663
|
+
# Columns use Vuetify's 12-column grid system where you specify how many columns
|
|
664
|
+
# (out of 12) this component should occupy at different breakpoints.
|
|
665
|
+
#
|
|
666
|
+
# Breakpoints (from smallest to largest):
|
|
667
|
+
# - xs: < 600px (mobile phones)
|
|
668
|
+
# - sm: 600px - 960px (tablets)
|
|
669
|
+
# - md: 960px - 1264px (small laptops)
|
|
670
|
+
# - lg: 1264px - 1904px (desktops)
|
|
671
|
+
# - xl: 1904px - 2560px (large desktops)
|
|
672
|
+
# - xxl: > 2560px (ultra-wide displays)
|
|
673
|
+
#
|
|
674
|
+
# @example Responsive column that changes width at different screen sizes
|
|
675
|
+
# responsive.panels_column \
|
|
676
|
+
# lg: { cols: 4 }, # 4/12 = 1/3 width on large screens
|
|
677
|
+
# md: { cols: 6 }, # 6/12 = 1/2 width on medium screens
|
|
678
|
+
# xs: { cols: 12 }, # 12/12 = full width on mobile
|
|
679
|
+
# childViews: ->(col) do
|
|
680
|
+
# col.h3 text: 'Card Title'
|
|
681
|
+
# end
|
|
682
|
+
#
|
|
683
|
+
# @example Column with responsive padding and ordering
|
|
684
|
+
# responsive.panels_column \
|
|
685
|
+
# lg: { cols: 8, order: 0, padding: { bottom: 0 } },
|
|
686
|
+
# xs: { cols: 12, order: 1, padding: { bottom: 20 } },
|
|
687
|
+
# childViews: ->(col) do
|
|
688
|
+
# col.label text: 'Content'
|
|
689
|
+
# end
|
|
690
|
+
#
|
|
691
|
+
# @see https://vuetifyjs.com/en/components/grids/ Vuetify Grid System
|
|
470
692
|
class Column < View
|
|
693
|
+
# Configuration for xxl breakpoint (> 2560px).
|
|
694
|
+
# @example xxl: { cols: 3, order: 0, padding: { all: 16 } }
|
|
471
695
|
hash :xxl
|
|
696
|
+
|
|
697
|
+
# Configuration for xl breakpoint (1904px - 2560px).
|
|
698
|
+
# @example xl: { cols: 4, hide: false }
|
|
472
699
|
hash :xl
|
|
700
|
+
|
|
701
|
+
# Configuration for lg breakpoint (1264px - 1904px).
|
|
702
|
+
# @example lg: { cols: 6, order: 1 }
|
|
473
703
|
hash :lg
|
|
704
|
+
|
|
705
|
+
# Configuration for md breakpoint (960px - 1264px).
|
|
706
|
+
# @example md: { cols: 8 }
|
|
474
707
|
hash :md
|
|
708
|
+
|
|
709
|
+
# Configuration for sm breakpoint (600px - 960px).
|
|
710
|
+
# @example sm: { cols: 12 }
|
|
475
711
|
hash :sm
|
|
712
|
+
|
|
713
|
+
# Configuration for xs breakpoint (< 600px).
|
|
714
|
+
# @example xs: { cols: 12, hide: false }
|
|
476
715
|
hash :xs
|
|
477
716
|
|
|
717
|
+
# Configuration that applies only at xxl breakpoint.
|
|
478
718
|
hash :xxlOnly
|
|
719
|
+
|
|
720
|
+
# Configuration that applies only at xl breakpoint.
|
|
479
721
|
hash :xlOnly
|
|
722
|
+
|
|
723
|
+
# Configuration that applies only at lg breakpoint.
|
|
480
724
|
hash :lgOnly
|
|
725
|
+
|
|
726
|
+
# Configuration that applies only at md breakpoint.
|
|
481
727
|
hash :mdOnly
|
|
728
|
+
|
|
729
|
+
# Configuration that applies only at sm breakpoint.
|
|
482
730
|
hash :smOnly
|
|
731
|
+
|
|
732
|
+
# Configuration that applies only at xs breakpoint.
|
|
483
733
|
hash :xsOnly
|
|
484
734
|
|
|
735
|
+
# Configuration for xxl and smaller breakpoints.
|
|
485
736
|
hash :xxlAndDown
|
|
737
|
+
|
|
738
|
+
# Configuration for xl and smaller breakpoints.
|
|
486
739
|
hash :xlAndDown
|
|
740
|
+
|
|
741
|
+
# Configuration for lg and smaller breakpoints.
|
|
487
742
|
hash :lgAndDown
|
|
743
|
+
|
|
744
|
+
# Configuration for md and smaller breakpoints.
|
|
745
|
+
# @example mdAndDown: { hide: true } # Hide on medium screens and below
|
|
488
746
|
hash :mdAndDown
|
|
747
|
+
|
|
748
|
+
# Configuration for sm and smaller breakpoints.
|
|
489
749
|
hash :smAndDown
|
|
750
|
+
|
|
751
|
+
# Configuration for xs breakpoint and below.
|
|
490
752
|
hash :xsAndDown
|
|
491
753
|
|
|
754
|
+
# Child components to display inside the column.
|
|
492
755
|
views :childViews
|
|
756
|
+
|
|
757
|
+
# Action triggered when the column is clicked.
|
|
493
758
|
action :onClick
|
|
494
759
|
end
|
|
495
760
|
|
|
761
|
+
# Vertical layout panel that stacks children vertically (top to bottom).
|
|
762
|
+
#
|
|
763
|
+
# Vertical panels use CSS flexbox with flex-direction: column.
|
|
764
|
+
# Children are arranged vertically and can be aligned or distributed in various ways.
|
|
765
|
+
#
|
|
766
|
+
# @example Basic vertical stacking
|
|
767
|
+
# panel.panels_vertical backgroundColor: '#f0f0f0', childViews: ->(vert) do
|
|
768
|
+
# vert.button text: 'Button 1'
|
|
769
|
+
# vert.button text: 'Button 2'
|
|
770
|
+
# vert.button text: 'Button 3'
|
|
771
|
+
# end
|
|
772
|
+
#
|
|
773
|
+
# @example Centered content with equal spacing
|
|
774
|
+
# panel.panels_vertical \
|
|
775
|
+
# width: 'matchParent',
|
|
776
|
+
# height: 300,
|
|
777
|
+
# distribution: 'spaceEqually',
|
|
778
|
+
# align: 'center',
|
|
779
|
+
# childViews: ->(vert) do
|
|
780
|
+
# vert.button text: 'Top'
|
|
781
|
+
# vert.button text: 'Middle'
|
|
782
|
+
# vert.button text: 'Bottom'
|
|
783
|
+
# end
|
|
784
|
+
#
|
|
785
|
+
# @example Clickable vertical panel
|
|
786
|
+
# panel.panels_vertical \
|
|
787
|
+
# styleClasses: ['card'],
|
|
788
|
+
# onClick: ->(action) { action.windows_open url: item_path(@item) },
|
|
789
|
+
# childViews: ->(vert) do
|
|
790
|
+
# vert.h3 text: @item.title
|
|
791
|
+
# vert.p text: @item.description
|
|
792
|
+
# end
|
|
793
|
+
#
|
|
794
|
+
# @see app/views/json_ui/garage/panels/vertical.json.jbuilder Garage examples
|
|
496
795
|
class Vertical < View
|
|
796
|
+
# Child components to stack vertically.
|
|
497
797
|
views :childViews
|
|
498
|
-
|
|
499
|
-
|
|
798
|
+
|
|
799
|
+
# How children should be distributed vertically.
|
|
800
|
+
# - 'fillEqually': Each child gets equal height
|
|
801
|
+
# - 'spaceEqually': Equal spacing between children
|
|
802
|
+
# @example distribution: 'fillEqually'
|
|
803
|
+
enum :distribution, options: [:fillEqually, :spaceEqually]
|
|
804
|
+
|
|
805
|
+
# Horizontal alignment of children.
|
|
806
|
+
# - 'left': Align to left edge
|
|
807
|
+
# - 'center': Center horizontally
|
|
808
|
+
# - 'right': Align to right edge
|
|
809
|
+
# @example align: 'center'
|
|
810
|
+
enum :align, options: [:left, :center, :right]
|
|
811
|
+
|
|
812
|
+
# Action triggered when the panel is clicked.
|
|
500
813
|
action :onClick
|
|
501
814
|
end
|
|
502
815
|
|
|
816
|
+
# Horizontal layout panel that arranges children side-by-side (left to right).
|
|
817
|
+
#
|
|
818
|
+
# Horizontal panels use CSS flexbox with flex-direction: row.
|
|
819
|
+
# Supports drag-and-drop reordering and various distribution modes.
|
|
820
|
+
#
|
|
821
|
+
# @example Basic horizontal layout
|
|
822
|
+
# panel.panels_horizontal backgroundColor: '#f0f0f0', childViews: ->(horiz) do
|
|
823
|
+
# horiz.button text: '1'
|
|
824
|
+
# horiz.button text: '2'
|
|
825
|
+
# horiz.button text: '3'
|
|
826
|
+
# end
|
|
827
|
+
#
|
|
828
|
+
# @example With equal spacing and alignment
|
|
829
|
+
# panel.panels_horizontal \
|
|
830
|
+
# width: 300,
|
|
831
|
+
# distribution: 'spaceEqually',
|
|
832
|
+
# align: 'middle',
|
|
833
|
+
# childViews: ->(horiz) do
|
|
834
|
+
# horiz.button text: 'Left'
|
|
835
|
+
# horiz.button text: 'Center'
|
|
836
|
+
# horiz.button text: 'Right'
|
|
837
|
+
# end
|
|
838
|
+
#
|
|
839
|
+
# @example With drag-and-drop reordering
|
|
840
|
+
# panel.panels_horizontal \
|
|
841
|
+
# width: 300,
|
|
842
|
+
# dragSupport: {
|
|
843
|
+
# onDrop: { action: 'http/post', url: reorder_items_path },
|
|
844
|
+
# paramNameForFormData: 'order_data'
|
|
845
|
+
# },
|
|
846
|
+
# childViews: ->(horiz) do
|
|
847
|
+
# @items.each do |item|
|
|
848
|
+
# horiz.button id: "item_#{item.id}", text: item.name
|
|
849
|
+
# end
|
|
850
|
+
# end
|
|
851
|
+
#
|
|
852
|
+
# @example With overlapping items (negative margins)
|
|
853
|
+
# panel.panels_horizontal \
|
|
854
|
+
# distribution: 'overlap-3', # 12px negative margin
|
|
855
|
+
# childViews: ->(horiz) do
|
|
856
|
+
# horiz.avatar url: user1.avatar_url
|
|
857
|
+
# horiz.avatar url: user2.avatar_url
|
|
858
|
+
# horiz.avatar url: user3.avatar_url
|
|
859
|
+
# end
|
|
860
|
+
#
|
|
861
|
+
# @see app/views/json_ui/garage/panels/horizontal.json.jbuilder Garage examples
|
|
862
|
+
# @see https://vuetifyjs.com/en/styles/spacing/ Material Design Spacing
|
|
503
863
|
class Horizontal < View
|
|
864
|
+
# Child components to arrange horizontally.
|
|
504
865
|
views :childViews
|
|
866
|
+
|
|
867
|
+
# How children should be distributed horizontally.
|
|
868
|
+
# - 'fillEqually': Each child gets equal width
|
|
869
|
+
# - 'spaceEqually': Equal spacing between children
|
|
870
|
+
# - 'overlap-N': Negative spacing (N from 1-8, e.g., 'overlap-3' = -12px margin)
|
|
871
|
+
# - 'space-N': Positive spacing (N from 1-8, e.g., 'space-2' = 8px margin)
|
|
872
|
+
# @example distribution: 'spaceEqually'
|
|
873
|
+
# @note Uses Material Design spacing scale (4px increments)
|
|
505
874
|
string :distribution
|
|
506
|
-
|
|
875
|
+
|
|
876
|
+
# Vertical alignment of children.
|
|
877
|
+
# - 'top': Align to top edge
|
|
878
|
+
# - 'middle': Center vertically
|
|
879
|
+
# - 'bottom': Align to bottom edge
|
|
880
|
+
# @example align: 'middle'
|
|
881
|
+
enum :align, options: [:top, :middle, :bottom]
|
|
882
|
+
|
|
883
|
+
# Action triggered when the panel is clicked.
|
|
507
884
|
action :onClick
|
|
885
|
+
|
|
886
|
+
# Configuration for drag-and-drop reordering support.
|
|
887
|
+
# Enables users to reorder children by dragging them.
|
|
888
|
+
# @example dragSupport: { onDrop: { action: 'http/post', url: reorder_path }, paramNameForFormData: 'order' }
|
|
508
889
|
hash :dragSupport, optional: [:onDrop, :paramNameForFormData, :paramNameForNewIndex]
|
|
509
890
|
end
|
|
510
891
|
|
|
892
|
+
# Flow layout panel that wraps children like text (left to right, then top to bottom).
|
|
893
|
+
#
|
|
894
|
+
# Flow panels use CSS flexbox with flex-wrap, creating a responsive grid-like layout
|
|
895
|
+
# where children wrap to the next line when they exceed container width.
|
|
896
|
+
# Supports responsive gap and padding for different screen sizes.
|
|
897
|
+
#
|
|
898
|
+
# @example Basic flow layout
|
|
899
|
+
# panel.panels_flow width: 300, innerPadding: { all: 10 }, childViews: ->(flow) do
|
|
900
|
+
# (1..10).each do |n|
|
|
901
|
+
# flow.button text: "Item #{n}"
|
|
902
|
+
# end
|
|
903
|
+
# end
|
|
904
|
+
#
|
|
905
|
+
# @example Responsive gaps and padding
|
|
906
|
+
# panel.panels_flow \
|
|
907
|
+
# width: 'matchParent',
|
|
908
|
+
# xs: { gap: { x: 4, y: 4 }, padding: { all: 8 } },
|
|
909
|
+
# md: { gap: { x: 16, y: 16 }, padding: { all: 24 } },
|
|
910
|
+
# lg: { gap: { all: 32 } },
|
|
911
|
+
# childViews: ->(flow) do
|
|
912
|
+
# @products.each do |product|
|
|
913
|
+
# flow.panels_vertical styleClasses: ['card'], childViews: ->(card) do
|
|
914
|
+
# card.image url: product.image_url
|
|
915
|
+
# card.h4 text: product.name
|
|
916
|
+
# end
|
|
917
|
+
# end
|
|
918
|
+
# end
|
|
919
|
+
#
|
|
920
|
+
# @example Tag cloud with inner padding
|
|
921
|
+
# panel.panels_flow \
|
|
922
|
+
# innerPadding: { x: 5, y: 5 },
|
|
923
|
+
# childViews: ->(flow) do
|
|
924
|
+
# @tags.each do |tag|
|
|
925
|
+
# flow.chip text: tag.name
|
|
926
|
+
# end
|
|
927
|
+
# end
|
|
928
|
+
#
|
|
929
|
+
# @see app/views/json_ui/garage/panels/flow.json.jbuilder Garage examples
|
|
511
930
|
class Flow < View
|
|
931
|
+
# Padding applied to each child element wrapper.
|
|
932
|
+
# Different from the panel's own padding - this creates gaps between items.
|
|
933
|
+
# @example innerPadding: { x: 10, y: 10 }
|
|
934
|
+
# @example innerPadding: { top: 5, right: 10, bottom: 5, left: 10 }
|
|
512
935
|
hash :innerPadding, optional: [:top, :right, :bottom, :left, :x, :y]
|
|
513
936
|
|
|
937
|
+
# Configuration for xxl breakpoint (> 2560px).
|
|
938
|
+
# @example xxl: { gap: { all: 32 }, padding: { all: 48 } }
|
|
514
939
|
hash :xxl, optional: [:gap, :padding]
|
|
940
|
+
|
|
941
|
+
# Configuration for xl breakpoint (1904px - 2560px).
|
|
942
|
+
# @example xl: { gap: { x: 24, y: 24 } }
|
|
515
943
|
hash :xl, optional: [:gap, :padding]
|
|
944
|
+
|
|
945
|
+
# Configuration for lg breakpoint (1264px - 1904px).
|
|
946
|
+
# @example lg: { gap: { all: 16 }, padding: { x: 30, y: 30 } }
|
|
516
947
|
hash :lg, optional: [:gap, :padding]
|
|
948
|
+
|
|
949
|
+
# Configuration for md breakpoint (960px - 1264px).
|
|
950
|
+
# @example md: { gap: { y: 8, x: 8 } }
|
|
517
951
|
hash :md, optional: [:gap, :padding]
|
|
952
|
+
|
|
953
|
+
# Configuration for sm breakpoint (600px - 960px).
|
|
954
|
+
# @example sm: { gap: { y: 4, x: 6 }, padding: { all: 16 } }
|
|
518
955
|
hash :sm, optional: [:gap, :padding]
|
|
956
|
+
|
|
957
|
+
# Configuration for xs breakpoint (< 600px).
|
|
958
|
+
# @example xs: { gap: { y: 2, x: 2 }, padding: { left: 10, bottom: 8 } }
|
|
519
959
|
hash :xs, optional: [:gap, :padding]
|
|
520
960
|
|
|
961
|
+
# Child components to arrange in flow layout.
|
|
521
962
|
views :childViews
|
|
522
963
|
|
|
523
|
-
|
|
964
|
+
# Vertical alignment of children within each row.
|
|
965
|
+
# @example align: 'middle'
|
|
966
|
+
enum :align, options: [:top, :middle, :bottom]
|
|
524
967
|
|
|
525
968
|
# required :innerPadding
|
|
526
969
|
end
|
|
@@ -7,7 +7,7 @@ module Glib
|
|
|
7
7
|
included do
|
|
8
8
|
string :directUploadUrl
|
|
9
9
|
hash :accepts, optional: [:fileType, :maxFileSize, :maxFileLength, :maxFileSizeErrorText, :maxFileLengthErrorText]
|
|
10
|
-
|
|
10
|
+
enum :strategy, options: [:delegate, :dropUpload]
|
|
11
11
|
string :storagePrefix
|
|
12
12
|
hash :metadata
|
|
13
13
|
string :tagging
|