avo 4.0.0.beta.30 → 4.0.0.beta.32

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/builds/avo/application.css +222 -158
  4. data/app/assets/builds/avo/application.js +2 -2
  5. data/app/assets/builds/avo/application.js.map +3 -3
  6. data/app/assets/images/avo/favicon-dark.ico +0 -0
  7. data/app/assets/images/avo/logo-dark.png +0 -0
  8. data/app/assets/images/avo/logomark-dark.png +0 -0
  9. data/app/assets/stylesheets/css/components/breadcrumbs.css +44 -4
  10. data/app/assets/stylesheets/css/components/color_scheme_switcher.css +17 -22
  11. data/app/assets/stylesheets/css/components/ui/card.css +5 -0
  12. data/app/assets/stylesheets/css/components/ui/description_list.css +1 -1
  13. data/app/assets/stylesheets/css/fields/code.css +1 -1
  14. data/app/assets/stylesheets/css/layout.css +187 -38
  15. data/app/assets/stylesheets/css/scrollbar.css +12 -0
  16. data/app/assets/stylesheets/css/sidebar.css +2 -2
  17. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +3 -3
  18. data/app/javascript/js/controllers/actions_overflow_controller.js +22 -3
  19. data/app/javascript/js/controllers/sidebar_controller.js +11 -0
  20. data/app/views/avo/partials/_footer.html.erb +1 -1
  21. data/app/views/avo/partials/_navbar.html.erb +31 -49
  22. data/app/views/layouts/avo/application.html.erb +20 -24
  23. data/lib/avo/concerns/breadcrumbs.rb +1 -0
  24. data/lib/avo/configuration/appearance.rb +27 -37
  25. data/lib/avo/version.rb +1 -1
  26. data/lib/generators/avo/templates/locales/avo.ar.yml +1 -0
  27. data/lib/generators/avo/templates/locales/avo.de.yml +1 -0
  28. data/lib/generators/avo/templates/locales/avo.en.yml +1 -0
  29. data/lib/generators/avo/templates/locales/avo.es.yml +1 -0
  30. data/lib/generators/avo/templates/locales/avo.fr.yml +1 -0
  31. data/lib/generators/avo/templates/locales/avo.it.yml +1 -0
  32. data/lib/generators/avo/templates/locales/avo.ja.yml +1 -0
  33. data/lib/generators/avo/templates/locales/avo.nb.yml +1 -0
  34. data/lib/generators/avo/templates/locales/avo.nl.yml +1 -0
  35. data/lib/generators/avo/templates/locales/avo.nn.yml +1 -0
  36. data/lib/generators/avo/templates/locales/avo.pl.yml +1 -0
  37. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +1 -0
  38. data/lib/generators/avo/templates/locales/avo.pt.yml +1 -0
  39. data/lib/generators/avo/templates/locales/avo.ro.yml +1 -0
  40. data/lib/generators/avo/templates/locales/avo.ru.yml +1 -0
  41. data/lib/generators/avo/templates/locales/avo.tr.yml +1 -0
  42. data/lib/generators/avo/templates/locales/avo.ua.yml +1 -0
  43. data/lib/generators/avo/templates/locales/avo.zh-TW.yml +1 -0
  44. data/lib/generators/avo/templates/locales/avo.zh.yml +1 -0
  45. metadata +1 -1
@@ -35,41 +35,37 @@
35
35
  </head>
36
36
 
37
37
  <body class="<%= class_names("floating-controls bg-background", *body_classes, "all-fields-stacked": Avo.configuration.use_stacked_fields) %>">
38
+ <a href="#main-sidebar" class="skip-to-content"><%= t("avo.skip_to_sidebar") %></a>
38
39
  <a href="#main-content" class="skip-to-content"><%= t("avo.skip_to_content") %></a>
39
40
 
40
41
  <div
41
- class="relative flex min-h-dvh w-full flex-1"
42
+ class="main relative flex min-h-dvh w-full flex-1 flex-col <%= "sidebar-open" if @sidebar_open %>"
42
43
  data-controller="sidebar"
43
- data-sidebar-open-value="<%= @sidebar_open %>">
44
- <div class="flex max-w-full flex-1 flex-col">
45
- <%= render partial: "avo/partials/navbar", locals: {resource: @resource} %>
44
+ data-sidebar-open-value="<%= @sidebar_open %>"
45
+ data-sidebar-target="mainArea"
46
+ >
47
+ <%= render partial: "avo/partials/navbar", locals: {resource: @resource} %>
46
48
 
47
- <div data-sidebar-target="mainArea" class="main relative flex flex-1 <%= "sidebar-open" if @sidebar_open %>">
48
- <div class="hidden lg:flex"><%= render Avo::SidebarComponent.new sidebar_open: @sidebar_open %></div>
49
+ <div id="main-sidebar" tabindex="-1" class="hidden lg:flex"><%= render Avo::SidebarComponent.new sidebar_open: @sidebar_open %></div>
49
50
 
50
- <div class="flex lg:hidden">
51
- <%= render Avo::SidebarComponent.new sidebar_open: @sidebar_open, for_mobile: true %>
52
- </div>
51
+ <div class="flex lg:hidden">
52
+ <%= render Avo::SidebarComponent.new sidebar_open: @sidebar_open, for_mobile: true %>
53
+ </div>
54
+
55
+ <main id="main-content" class="main-content" tabindex="-1">
56
+ <%= render Avo::BreadcrumbsComponent.new(items: avo_breadcrumbs) %>
53
57
 
54
- <main id="main-content" class="main-content-area" tabindex="-1">
55
- <div class="mb-4">
56
- <%= render Avo::BreadcrumbsComponent.new(items: avo_breadcrumbs) %>
57
- </div>
58
+ <div class="main-content__container <%= container_classes %>">
58
59
 
59
- <%= render partial: "avo/partials/custom_tools_alert" %>
60
+ <%= render partial: "avo/partials/custom_tools_alert" %>
60
61
 
61
- <div class="scrollable-wrapper">
62
- <div class="avo-container <%= container_classes %>">
63
- <%= yield.force_encoding("UTF-8") %>
62
+ <%= yield.force_encoding("UTF-8") %>
64
63
 
65
- <div class="mt-8">
66
- <%= render partial: "avo/partials/footer" %>
67
- </div>
68
- </div>
69
- </div>
70
- </main>
64
+ <div class="mt-auto pt-8 justify-self-end">
65
+ <%= render partial: "avo/partials/footer" %>
66
+ </div>
71
67
  </div>
72
- </div>
68
+ </main>
73
69
  </div>
74
70
 
75
71
  <%= turbo_frame_tag Avo::MODAL_FRAME_ID %>
@@ -19,6 +19,7 @@ module Avo
19
19
 
20
20
  class Builder
21
21
  extend PropInitializer::Properties
22
+
22
23
  prop :context, reader: :public
23
24
  prop :options, reader: :public
24
25
 
@@ -2,8 +2,8 @@ class Avo::Configuration::Appearance
2
2
  attr_reader :scheme, # :auto | :light | :dark
3
3
  :neutral, # Symbol — default theme selection (e.g. :slate, :brand)
4
4
  :accent, # Symbol — default accent selection (e.g. :blue, :brand)
5
- :neutral_colors, # Hash{ light:, dark: } — full 12-shade brand override
6
- :accent_colors, # Hash{ light:, dark: } — three-token brand override
5
+ :neutral_colors, # Hash{ 25 => ..., 50 => ..., ..., 950 => ... } — full 12-shade brand override (single palette, applied in both light and dark mode)
6
+ :accent_colors, # Hash{ color:, content:, foreground: } — three-token brand override (single palette, applied in both light and dark mode)
7
7
  :neutrals, # Array[String] — available neutral theme names
8
8
  :accents, # Array[String] — available accent color names
9
9
  :lock, # Array[Symbol] — subset of [:scheme, :neutral, :accent]
@@ -37,7 +37,6 @@ class Avo::Configuration::Appearance
37
37
  content: "--color-accent-content",
38
38
  foreground: "--color-accent-foreground"
39
39
  }.freeze
40
- SCHEMES = [:light, :dark].freeze
41
40
 
42
41
  DEFAULTS = {
43
42
  scheme: :auto,
@@ -100,17 +99,25 @@ class Avo::Configuration::Appearance
100
99
  # Returns the accent name for the data attribute (nil when accent is unset)
101
100
  def accent_css_class = accent&.to_s
102
101
 
103
- # Returns the full inline CSS string that overrides brand vars at :root and .dark
104
- # when neutral_colors / accent_colors are configured. Returns nil when neither is set
105
- # so the layout can skip emitting the <style> tag entirely.
102
+ # Returns the inline CSS string that overrides brand vars at :root when
103
+ # neutral_colors / accent_colors are configured. Returns nil when neither is
104
+ # set so the layout can skip emitting the <style> tag entirely.
105
+ #
106
+ # Brand palettes are single-toned — one set of values applied in both light
107
+ # and dark mode (matching how the built-in `.neutral-theme-*` /
108
+ # `.accent-theme-*` classes work). The override is emitted only in `:root`;
109
+ # layer ordering does the rest.
106
110
  #
107
111
  # The output is wrapped in `@layer base` so it sits between Avo's defaults
108
- # (`@layer theme`, where the built-in `:root` colors live) and the theme classes
109
- # (`@layer components`, where `.neutral-theme-*` / `.accent-theme-*` are defined).
112
+ # (`@layer theme`, where the built-in `:root` colors and the `.dark`
113
+ # overrides live) and the theme classes (`@layer components`, where
114
+ # `.neutral-theme-*` / `.accent-theme-*` are defined).
110
115
  # Layer ordering — `theme < base < components` — guarantees:
111
- # * Our override beats Avo's default `:root` palette (we're in a later layer)
112
- # * A user-selected `.accent-theme-orange` still wins over our `:root` (it's
113
- # in a later layer), so the picker keeps working.
116
+ # * Our :root override beats Avo's default `:root` palette and `.dark`
117
+ # overrides (we're in a later layer), so the brand color applies in
118
+ # both light and dark mode.
119
+ # * A user-selected `.accent-theme-orange` still wins over our `:root`
120
+ # (it's in a later layer), so the picker keeps working.
114
121
  # Without an `@layer` wrapper, the unlayered inline style would beat every
115
122
  # layered rule regardless of specificity, silently breaking theme selection.
116
123
  def brand_css_overrides
@@ -119,10 +126,7 @@ class Avo::Configuration::Appearance
119
126
  [
120
127
  "@layer base {",
121
128
  " :root {",
122
- *brand_declarations_for(:light).map { |line| " #{line}" },
123
- " }",
124
- " .dark {",
125
- *brand_declarations_for(:dark).map { |line| " #{line}" },
129
+ *brand_declarations.map { |line| " #{line}" },
126
130
  " }",
127
131
  "}"
128
132
  ].join("\n")
@@ -130,27 +134,27 @@ class Avo::Configuration::Appearance
130
134
 
131
135
  private
132
136
 
133
- def brand_declarations_for(scheme)
137
+ def brand_declarations
134
138
  declarations = []
135
139
 
136
140
  if neutral_colors
137
141
  NEUTRAL_SHADES.each do |shade|
138
- declarations << " --color-avo-neutral-#{shade}: #{neutral_colors[scheme][shade]};"
142
+ declarations << " --color-avo-neutral-#{shade}: #{neutral_colors[shade]};"
139
143
  end
140
144
  # Brand-scoped alias for the picker swatch. Theme classes (`.neutral-theme-*`)
141
145
  # never set this var, so the swatch keeps showing the configured brand
142
146
  # neutral even while another theme is hovered or selected.
143
- declarations << " --color-brand-neutral-400: #{neutral_colors[scheme][400]};"
147
+ declarations << " --color-brand-neutral-400: #{neutral_colors[400]};"
144
148
  end
145
149
 
146
150
  if accent_colors
147
151
  ACCENT_TOKENS.each do |token|
148
- declarations << " #{ACCENT_TOKEN_VAR_NAMES[token]}: #{accent_colors[scheme][token]};"
152
+ declarations << " #{ACCENT_TOKEN_VAR_NAMES[token]}: #{accent_colors[token]};"
149
153
  end
150
154
  # Brand-scoped alias for the picker swatch. Theme classes (`.accent-theme-*`)
151
155
  # never set this var, so the swatch keeps showing the configured brand
152
156
  # accent even while another accent is hovered or selected.
153
- declarations << " --color-brand-accent: #{accent_colors[scheme][:color]};"
157
+ declarations << " --color-brand-accent: #{accent_colors[:color]};"
154
158
  end
155
159
 
156
160
  declarations
@@ -175,24 +179,10 @@ class Avo::Configuration::Appearance
175
179
 
176
180
  def validate_color_palette!(name, palette, required_keys, missing_label)
177
181
  unless palette.is_a?(Hash)
178
- raise ArgumentError, "#{name} must be a Hash with :light and :dark keys, got #{palette.class}"
179
- end
180
-
181
- errors = []
182
- SCHEMES.each do |scheme|
183
- scheme_hash = palette[scheme]
184
- if scheme_hash.nil?
185
- errors << "missing scheme :#{scheme}"
186
- next
187
- end
188
- unless scheme_hash.is_a?(Hash)
189
- errors << ":#{scheme} must be a Hash, got #{scheme_hash.class}"
190
- next
191
- end
192
- missing = required_keys.select { |key| scheme_hash[key].nil? }
193
- errors << ":#{scheme} missing #{missing_label} #{missing.inspect}" if missing.any?
182
+ raise ArgumentError, "#{name} must be a Hash, got #{palette.class}"
194
183
  end
195
184
 
196
- raise ArgumentError, "#{name} is invalid: #{errors.join("; ")}" if errors.any?
185
+ missing = required_keys.select { |key| palette[key].nil? }
186
+ raise ArgumentError, "#{name} is missing #{missing_label} #{missing.inspect}" if missing.any?
197
187
  end
198
188
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "4.0.0.beta.30" unless const_defined?(:VERSION)
2
+ VERSION = "4.0.0.beta.32" unless const_defined?(:VERSION)
3
3
  end
@@ -157,6 +157,7 @@ ar:
157
157
  show_content: عرض المحتوى
158
158
  sign_out: تسجيل الخروج
159
159
  skip_to_content: انتقل إلى المحتوى
160
+ skip_to_sidebar: تخطي إلى الشريط الجانبي
160
161
  sort_asc: ترتيب تصاعدي
161
162
  sort_desc: ترتيب تنازلي
162
163
  sort_reset: إعادة تهيئة الترتيب
@@ -147,6 +147,7 @@ de:
147
147
  show_content: Inhalt anzeigen
148
148
  sign_out: Abmelden
149
149
  skip_to_content: Zum Inhalt springen
150
+ skip_to_sidebar: Zum Seitenbereich überspringen
150
151
  sort_asc: Aufsteigend sortieren
151
152
  sort_desc: Absteigend sortieren
152
153
  sort_reset: Sortierung zurücksetzen
@@ -147,6 +147,7 @@ en:
147
147
  show_content: Show content
148
148
  sign_out: Sign out
149
149
  skip_to_content: Skip to content
150
+ skip_to_sidebar: Skip to sidebar
150
151
  sort_asc: Sort ascending
151
152
  sort_desc: Sort descending
152
153
  sort_reset: Reset sorting
@@ -149,6 +149,7 @@ es:
149
149
  show_content: Mostrar contenido
150
150
  sign_out: Salir
151
151
  skip_to_content: Ir al contenido
152
+ skip_to_sidebar: Saltar a la barra lateral
152
153
  sort_asc: Ordenar de forma ascendente
153
154
  sort_desc: Ordenar de forma descendente
154
155
  sort_reset: Restablecer ordenación
@@ -149,6 +149,7 @@ fr:
149
149
  show_content: Afficher le contenu
150
150
  sign_out: Se déconnecter
151
151
  skip_to_content: Passer au contenu
152
+ skip_to_sidebar: Passer au menu latéral
152
153
  sort_asc: Trier par ordre croissant
153
154
  sort_desc: Trier par ordre décroissant
154
155
  sort_reset: Réinitialiser le tri
@@ -147,6 +147,7 @@ it:
147
147
  show_content: Mostra contenuto
148
148
  sign_out: Esci
149
149
  skip_to_content: Vai al contenuto
150
+ skip_to_sidebar: Salta al sidebar
150
151
  sort_asc: Ordina in ordine crescente
151
152
  sort_desc: Ordina in ordine decrescente
152
153
  sort_reset: Reimposta ordinamento
@@ -149,6 +149,7 @@ ja:
149
149
  show_content: 内容を表示
150
150
  sign_out: サインアウト
151
151
  skip_to_content: コンテンツへスキップ
152
+ skip_to_sidebar: サイドバーにスキップ
152
153
  sort_asc: 昇順で並べ替え
153
154
  sort_desc: 降順で並べ替え
154
155
  sort_reset: ソートをリセット
@@ -149,6 +149,7 @@ nb:
149
149
  show_content: Vis innhold
150
150
  sign_out: Logg ut
151
151
  skip_to_content: Hopp til innhold
152
+ skip_to_sidebar: Hopp til sidefelt
152
153
  sort_asc: Sorter stigende
153
154
  sort_desc: Sorter synkende
154
155
  sort_reset: Tilbakestill sortering
@@ -147,6 +147,7 @@ nl:
147
147
  show_content: Inhoud tonen
148
148
  sign_out: Afmelden
149
149
  skip_to_content: Ga naar de inhoud
150
+ skip_to_sidebar: Overslaan naar zijbalk
150
151
  sort_asc: Oplopend sorteren
151
152
  sort_desc: Aflopend sorteren
152
153
  sort_reset: Sortering resetten
@@ -149,6 +149,7 @@ nn:
149
149
  show_content: Vis innhald
150
150
  sign_out: Logg ut
151
151
  skip_to_content: Hopp til innhald
152
+ skip_to_sidebar: Hopp til sidefelt
152
153
  sort_asc: Sorter stigande
153
154
  sort_desc: Sorter synkende
154
155
  sort_reset: Nullstill sortering
@@ -149,6 +149,7 @@ pl:
149
149
  show_content: Pokaż zawartość
150
150
  sign_out: Wyloguj się
151
151
  skip_to_content: Przejdź do treści
152
+ skip_to_sidebar: Przejdź do paska bocznego
152
153
  sort_asc: Sortuj rosnąco
153
154
  sort_desc: Sortuj malejąco
154
155
  sort_reset: Resetuj sortowanie
@@ -149,6 +149,7 @@ pt-BR:
149
149
  show_content: Mostrar conteúdo
150
150
  sign_out: sair
151
151
  skip_to_content: Pular para o conteúdo
152
+ skip_to_sidebar: Pular para a barra lateral
152
153
  sort_asc: Ordenar em ordem crescente
153
154
  sort_desc: Ordenar em ordem decrescente
154
155
  sort_reset: Redefinir ordenação
@@ -149,6 +149,7 @@ pt:
149
149
  show_content: Mostrar conteúdo
150
150
  sign_out: Terminar sessão
151
151
  skip_to_content: Ir para o conteúdo
152
+ skip_to_sidebar: Pular para a barra lateral
152
153
  sort_asc: Ordenar em ordem crescente
153
154
  sort_desc: Ordenar em ordem decrescente
154
155
  sort_reset: Redefinir ordenação
@@ -151,6 +151,7 @@ ro:
151
151
  show_content: Arată conținutul
152
152
  sign_out: Delogare
153
153
  skip_to_content: Sari la conținut
154
+ skip_to_sidebar: Sari la bara laterală
154
155
  sort_asc: Sortare crescătoare
155
156
  sort_desc: Sortare descrescătoare
156
157
  sort_reset: Resetare sortare
@@ -149,6 +149,7 @@ ru:
149
149
  show_content: Показать содержимое
150
150
  sign_out: Выйти
151
151
  skip_to_content: Перейти к содержимому
152
+ skip_to_sidebar: Пропустить в боковую панель
152
153
  sort_asc: Сортировать по возрастанию
153
154
  sort_desc: Сортировать по убыванию
154
155
  sort_reset: Сбросить сортировку
@@ -149,6 +149,7 @@ tr:
149
149
  show_content: İçeriği göster
150
150
  sign_out: Çıkış yap
151
151
  skip_to_content: İçeriğe atla
152
+ skip_to_sidebar: Kenara atla
152
153
  sort_asc: Artan sırala
153
154
  sort_desc: Azalan sırala
154
155
  sort_reset: Sıralamayı sıfırla
@@ -149,6 +149,7 @@ ua:
149
149
  show_content: Показати вміст
150
150
  sign_out: Вийти
151
151
  skip_to_content: Перейти до вмісту
152
+ skip_to_sidebar: Пропустити до бокової панелі
152
153
  sort_asc: Rūšiuoti didėjančia tvarka
153
154
  sort_desc: Rūšiuoti mažėjančia tvarka
154
155
  sort_reset: Atstatyti rūšiavimą
@@ -147,6 +147,7 @@ zh-TW:
147
147
  show_content: 顯示內容
148
148
  sign_out: 登出
149
149
  skip_to_content: 跳至內容
150
+ skip_to_sidebar: 跳到側邊欄
150
151
  sort_asc: 升冪排序
151
152
  sort_desc: 降冪排序
152
153
  sort_reset: 重置排序
@@ -147,6 +147,7 @@ zh:
147
147
  show_content: 显示内容
148
148
  sign_out: 登出
149
149
  skip_to_content: 跳转至内容
150
+ skip_to_sidebar: 跳到侧边栏
150
151
  sort_asc: 升序排序
151
152
  sort_desc: 降序排序
152
153
  sort_reset: 重置排序
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avo
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta.30
4
+ version: 4.0.0.beta.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Marin