keystone_ui 0.16.0 → 0.17.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/keystone_ui/file_upload_controller.js +2 -4
  3. data/app/components/keystone/ui/accordion_component.rb +9 -9
  4. data/app/components/keystone/ui/bottom_nav_component.rb +1 -1
  5. data/app/components/keystone/ui/bottom_nav_item_component.rb +2 -2
  6. data/app/components/keystone/ui/bucket_component.rb +9 -9
  7. data/app/components/keystone/ui/bucket_series_component.rb +1 -1
  8. data/app/components/keystone/ui/card_link_component.rb +4 -4
  9. data/app/components/keystone/ui/chart_card_component.rb +2 -2
  10. data/app/components/keystone/ui/checkbox_row_component.rb +4 -4
  11. data/app/components/keystone/ui/code_component.rb +3 -3
  12. data/app/components/keystone/ui/color_picker_component.html.erb +1 -1
  13. data/app/components/keystone/ui/color_picker_component.rb +4 -2
  14. data/app/components/keystone/ui/column_picker_component.rb +4 -4
  15. data/app/components/keystone/ui/copy_button_component.rb +1 -1
  16. data/app/components/keystone/ui/cta_banner_component.rb +7 -7
  17. data/app/components/keystone/ui/data_table_component.html.erb +4 -4
  18. data/app/components/keystone/ui/data_table_component.rb +14 -10
  19. data/app/components/keystone/ui/disclosure_component.rb +4 -4
  20. data/app/components/keystone/ui/feature_grid_component.rb +13 -13
  21. data/app/components/keystone/ui/file_upload_component.rb +10 -10
  22. data/app/components/keystone/ui/form_component.rb +1 -1
  23. data/app/components/keystone/ui/form_field_component.rb +2 -2
  24. data/app/components/keystone/ui/form_page_component.rb +2 -2
  25. data/app/components/keystone/ui/funnel_component.rb +12 -12
  26. data/app/components/keystone/ui/grid_component.rb +3 -3
  27. data/app/components/keystone/ui/hero_component.rb +11 -11
  28. data/app/components/keystone/ui/mobile_actions_component.rb +2 -2
  29. data/app/components/keystone/ui/mobile_header_component.rb +4 -4
  30. data/app/components/keystone/ui/modal_component.rb +5 -5
  31. data/app/components/keystone/ui/multi_select_component.rb +4 -4
  32. data/app/components/keystone/ui/nav_dropdown_component.rb +4 -4
  33. data/app/components/keystone/ui/nav_item_component.rb +1 -1
  34. data/app/components/keystone/ui/navbar_component.rb +1 -1
  35. data/app/components/keystone/ui/option_card_component.rb +2 -2
  36. data/app/components/keystone/ui/panel_component.rb +3 -3
  37. data/app/components/keystone/ui/pipeline_component.rb +14 -14
  38. data/app/components/keystone/ui/progress_component.rb +3 -3
  39. data/app/components/keystone/ui/radio_card_component.rb +4 -4
  40. data/app/components/keystone/ui/settings_link_component.html.erb +1 -1
  41. data/app/components/keystone/ui/settings_link_component.rb +3 -2
  42. data/app/components/keystone/ui/show_page_component.rb +2 -2
  43. data/app/components/keystone/ui/stat_card_component.html.erb +3 -3
  44. data/app/components/keystone/ui/stat_card_component.rb +17 -15
  45. data/app/components/keystone/ui/swipe_deck_component.html.erb +6 -6
  46. data/app/components/keystone/ui/swipe_deck_component.rb +7 -1
  47. data/app/components/keystone/ui/tab_switcher_component.rb +3 -3
  48. data/app/components/keystone/ui/theme_toggle_component.rb +2 -2
  49. data/lib/keystone_ui/source_css.rb +0 -1
  50. data/lib/keystone_ui/version.rb +1 -1
  51. data/the_local/agents/keystone_ui-info.md +12 -0
  52. data/the_local/agents/keystone_ui-install.md +27 -2
  53. metadata +3 -4
  54. data/app/assets/tailwind/keystone_ui_engine/nav.css +0 -175
@@ -16,10 +16,10 @@ module Keystone
16
16
  SVG
17
17
 
18
18
  WRAPPER_CLASSES = "lg:hidden"
19
- BACK_LINK_CLASSES = "text-gray-500 dark:text-gray-400"
20
- TITLE_CLASSES = "absolute left-1/2 -translate-x-1/2 font-semibold text-gray-900 dark:text-white lg:hidden truncate max-w-[60%]"
21
- SUBTITLE_CLASSES = "block text-xs font-normal text-gray-500 dark:text-gray-400 truncate text-center"
22
- DROPDOWN_CLASSES = "hidden absolute right-0 z-50 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5 dark:bg-zinc-800 dark:ring-white/10"
19
+ BACK_LINK_CLASSES = "ks-mobile-header-back"
20
+ TITLE_CLASSES = "ks-mobile-header-title absolute left-1/2 -translate-x-1/2 lg:hidden truncate max-w-[60%]"
21
+ SUBTITLE_CLASSES = "ks-mobile-header-subtitle block text-xs truncate text-center"
22
+ DROPDOWN_CLASSES = "ks-action-menu hidden absolute right-0 z-50 w-48 origin-top-right"
23
23
 
24
24
  # Renders the left-side and title of the mobile header.
25
25
  # Call from the left side of your navbar.
@@ -3,11 +3,11 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class ModalComponent < ViewComponent::Base
6
- BACKDROP_CLASSES = "hidden fixed inset-0 z-50 flex items-center justify-center bg-black/60"
7
- PANEL_CLASSES = "rounded-xl border border-gray-200 bg-white p-6 w-full mx-4 max-h-[80vh] flex flex-col dark:border-zinc-700 dark:bg-zinc-800"
8
- HEADER_CLASSES = "flex items-center justify-between mb-4"
9
- TITLE_CLASSES = "text-lg font-semibold text-gray-900 dark:text-gray-200"
10
- CLOSE_BUTTON_CLASSES = "text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
6
+ BACKDROP_CLASSES = "ks-modal-backdrop hidden fixed inset-0 z-50 flex items-center justify-center"
7
+ PANEL_CLASSES = "ks-modal-panel w-full max-h-[80vh] flex flex-col"
8
+ HEADER_CLASSES = "ks-modal-header flex items-center justify-between"
9
+ TITLE_CLASSES = "ks-modal-title text-lg"
10
+ CLOSE_BUTTON_CLASSES = "ks-modal-close"
11
11
  BODY_CLASSES = "overflow-auto flex-1"
12
12
 
13
13
  SIZE_CLASSES = {
@@ -4,10 +4,10 @@ module Keystone
4
4
  module Ui
5
5
  class MultiSelectComponent < ViewComponent::Base
6
6
  WRAPPER_CLASSES = "relative inline-block"
7
- TRIGGER_CLASSES = "inline-flex items-center gap-1 rounded-md border px-3 py-2 text-sm border-gray-300 bg-white text-gray-900 dark:border-zinc-700 dark:bg-zinc-900 dark:text-white"
8
- MENU_CLASSES = "absolute z-10 mt-1 w-56 rounded-md border border-gray-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-900 hidden"
9
- OPTION_CLASSES = "flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-zinc-800 cursor-pointer"
10
- CHECKBOX_CLASSES = "rounded border-gray-300 text-accent-600 focus:ring-accent-500 dark:border-zinc-600"
7
+ TRIGGER_CLASSES = "ks-menu-trigger inline-flex items-center text-sm"
8
+ MENU_CLASSES = "ks-menu absolute z-10 w-56 hidden"
9
+ OPTION_CLASSES = "ks-menu-option flex items-center text-sm cursor-pointer"
10
+ CHECKBOX_CLASSES = "ks-menu-checkbox"
11
11
  CARET_ICON = <<~SVG.freeze
12
12
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4">
13
13
  <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
@@ -3,12 +3,12 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class NavDropdownComponent < ViewComponent::Base
6
- WRAPPER_CLASSES = "nav-dropdown"
7
- MENU_CLASSES = "nav-dropdown-menu hidden"
8
- TRIGGER_BASE = "nav-dropdown-trigger"
6
+ WRAPPER_CLASSES = "ks-nav-dropdown"
7
+ MENU_CLASSES = "ks-nav-dropdown-menu hidden"
8
+ TRIGGER_BASE = "ks-nav-dropdown-trigger"
9
9
  ACTIVE_CLASS = "active"
10
10
  CARET_ICON = <<~SVG.freeze
11
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="nav-dropdown-caret">
11
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="ks-nav-dropdown-caret">
12
12
  <path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
13
13
  </svg>
14
14
  SVG
@@ -14,7 +14,7 @@ module Keystone
14
14
  ACTIVE_CLASS = "active"
15
15
 
16
16
  def link_classes
17
- @active ? ACTIVE_CLASS : ""
17
+ [ "ks-nav-item", (ACTIVE_CLASS if @active) ].compact.join(" ")
18
18
  end
19
19
  end
20
20
  end
@@ -7,7 +7,7 @@ module Keystone
7
7
  NAV_STICKY = "sticky top-0 z-40"
8
8
  MOBILE_LEFT_CLASSES = "lg:hidden flex items-center"
9
9
  LOGO_CLASSES = "logo"
10
- MOBILE_CENTER_CLASSES = "absolute left-1/2 -translate-x-1/2 font-semibold text-gray-900 dark:text-white lg:hidden truncate max-w-[60%]"
10
+ MOBILE_CENTER_CLASSES = "ks-navbar-title absolute left-1/2 -translate-x-1/2 lg:hidden truncate max-w-[60%]"
11
11
  DESKTOP_LINKS_CLASSES = "nav-container hidden lg:flex"
12
12
  MOBILE_RIGHT_CLASSES = "nav-user-controls ml-auto"
13
13
 
@@ -3,7 +3,7 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class OptionCardComponent < ViewComponent::Base
6
- BASE_CLASSES = "inline-flex items-center gap-2 px-3 py-2 rounded-lg border-2 transition cursor-pointer"
6
+ BASE_CLASSES = "ks-option-card inline-flex items-center transition cursor-pointer"
7
7
 
8
8
  attr_reader :name, :value, :input_data, :label_data
9
9
 
@@ -20,7 +20,7 @@ module Keystone
20
20
  end
21
21
 
22
22
  def classes
23
- border = selected? ? "border-accent-500" : "border-transparent"
23
+ border = selected? ? "ks-option-card-selected" : "border-transparent"
24
24
  "#{BASE_CLASSES} #{border}"
25
25
  end
26
26
  end
@@ -3,8 +3,8 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class PanelComponent < ViewComponent::Base
6
- PADDING_CLASSES = { sm: "p-4", md: "p-5", lg: "p-6" }.freeze
7
- RADIUS_CLASSES = { md: "rounded-lg", lg: "rounded-xl", xl: "rounded-2xl" }.freeze
6
+ PADDING_CLASSES = { sm: "ks-panel-padding-sm", md: "ks-panel-padding-md", lg: "ks-panel-padding-lg" }.freeze
7
+ RADIUS_CLASSES = { md: "ks-panel-radius-md", lg: "ks-panel-radius-lg", xl: "ks-panel-radius-xl" }.freeze
8
8
 
9
9
  def initialize(padding: :md, radius: :lg, shadow: true)
10
10
  @padding = padding
@@ -13,7 +13,7 @@ module Keystone
13
13
  end
14
14
 
15
15
  BASE_CLASSES = "ks-panel"
16
- SHADOW_CLASS = "shadow-sm"
16
+ SHADOW_CLASS = "ks-panel-shadow"
17
17
 
18
18
  def classes
19
19
  tokens = [ RADIUS_CLASSES.fetch(@radius), BASE_CLASSES, PADDING_CLASSES.fetch(@padding) ]
@@ -3,24 +3,24 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class PipelineComponent < ViewComponent::Base
6
- CONTAINER_CLASSES = "rounded-xl border border-surface-700 bg-surface-800 p-6"
7
- HEADER_CLASSES = "mb-4"
8
- TITLE_CLASSES = "text-lg font-semibold text-white"
9
- SUBTITLE_CLASSES = "mt-1 text-sm text-surface-400"
10
- TRACK_CLASSES = "flex flex-col gap-3 sm:flex-row sm:items-stretch"
11
- BOX_CLASSES = "flex flex-1 flex-col items-center gap-2 rounded-lg border border-surface-700 bg-surface-900 p-4 text-center"
12
- BOX_LABEL_CLASSES = "text-xs uppercase tracking-wide text-surface-500"
6
+ CONTAINER_CLASSES = "ks-pipeline"
7
+ HEADER_CLASSES = "ks-pipeline-header"
8
+ TITLE_CLASSES = "ks-pipeline-title text-lg"
9
+ SUBTITLE_CLASSES = "ks-pipeline-subtitle text-sm"
10
+ TRACK_CLASSES = "ks-pipeline-track flex flex-col sm:flex-row sm:items-stretch"
11
+ BOX_CLASSES = "ks-pipeline-box flex flex-1 flex-col items-center text-center"
12
+ BOX_LABEL_CLASSES = "ks-pipeline-box-label text-xs uppercase tracking-wide"
13
13
  CONNECTOR_CLASSES = "flex items-center justify-center"
14
- COUNT_BASE_CLASSES = "text-3xl font-bold"
14
+ COUNT_BASE_CLASSES = "ks-pipeline-count text-3xl"
15
15
  LINK_BASE_CLASSES = "link-toggle text-2xl leading-none"
16
- LINK_HEALTHY_CLASSES = "text-accent-500"
17
- LINK_BROKEN_CLASSES = "text-red-500"
16
+ LINK_HEALTHY_CLASSES = "ks-pipeline-link-healthy"
17
+ LINK_BROKEN_CLASSES = "ks-pipeline-link-broken"
18
18
 
19
19
  COUNT_CLASSES = {
20
- amber: "text-amber-400",
21
- emerald: "text-accent-400",
22
- danger: "text-red-400",
23
- muted: "text-surface-500"
20
+ amber: "ks-pipeline-count-amber",
21
+ emerald: "ks-pipeline-count-emerald",
22
+ danger: "ks-pipeline-count-danger",
23
+ muted: "ks-pipeline-count-muted"
24
24
  }.freeze
25
25
 
26
26
  attr_reader :title, :boxes, :links, :subtitle
@@ -3,9 +3,9 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class ProgressComponent < ViewComponent::Base
6
- TRACK_CLASSES = "w-full h-2 bg-surface-200 rounded-full overflow-hidden dark:bg-surface-700"
7
- BAR_CLASSES = "h-full bg-accent-500 rounded-full transition-all"
8
- LABEL_CLASSES = "mb-1 text-sm font-medium text-surface-700 dark:text-surface-300"
6
+ TRACK_CLASSES = "ks-progress-track w-full h-2 overflow-hidden"
7
+ BAR_CLASSES = "ks-progress-bar h-full transition-all"
8
+ LABEL_CLASSES = "ks-meter-label text-sm"
9
9
 
10
10
  attr_reader :value, :max, :label
11
11
 
@@ -3,10 +3,10 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class RadioCardComponent < ViewComponent::Base
6
- BASE_CLASSES = "inline-flex flex-col px-4 py-3 rounded-lg border-2 cursor-pointer transition"
7
- HIGHLIGHT_CLASSES = "border-gray-200 dark:border-zinc-700 peer-checked:border-accent-500 peer-checked:bg-accent-50 dark:peer-checked:bg-zinc-800"
8
- LABEL_CLASSES = "block font-medium text-gray-900 dark:text-gray-100"
9
- HINT_CLASSES = "block mt-1 text-sm text-surface-500 dark:text-gray-400"
6
+ BASE_CLASSES = "ks-radio-card inline-flex flex-col cursor-pointer transition"
7
+ HIGHLIGHT_CLASSES = "ks-radio-card-highlight"
8
+ LABEL_CLASSES = "ks-radio-card-label block"
9
+ HINT_CLASSES = "ks-radio-card-hint block text-sm"
10
10
 
11
11
  attr_reader :name, :value, :label, :hint
12
12
 
@@ -1,4 +1,4 @@
1
1
  <%= link_to @href, class: link_classes do %>
2
- <span class="font-medium"><%= @label %></span>
2
+ <span class="<%= LABEL_CLASSES %>"><%= @label %></span>
3
3
  <%= CHEVRON_ICON.html_safe %>
4
4
  <% end %>
@@ -3,12 +3,13 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class SettingsLinkComponent < ViewComponent::Base
6
+ LABEL_CLASSES = "ks-settings-link-label"
6
7
  attr_reader :label, :href
7
8
 
8
- LINK_CLASSES = "flex items-center justify-between px-4 py-3 text-gray-900 dark:text-gray-100 no-underline hover:bg-gray-50 dark:hover:bg-gray-800"
9
+ LINK_CLASSES = "ks-settings-link flex items-center justify-between no-underline"
9
10
 
10
11
  CHEVRON_ICON = <<~SVG.freeze
11
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5 text-gray-400">
12
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5 ks-settings-link-chevron">
12
13
  <path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
13
14
  </svg>
14
15
  SVG
@@ -4,8 +4,8 @@ module Keystone
4
4
  module Ui
5
5
  class ShowPageComponent < ViewComponent::Base
6
6
  DESKTOP_WRAPPER_CLASSES = "hidden md:block"
7
- TITLE_CLASSES = "text-2xl font-semibold text-gray-900 dark:text-white"
8
- SUBTITLE_CLASSES = "mt-1 text-sm text-gray-500 dark:text-gray-400"
7
+ TITLE_CLASSES = "ks-page-title text-2xl"
8
+ SUBTITLE_CLASSES = "ks-page-header-subtitle text-sm"
9
9
 
10
10
  def initialize(title:, back_url:, subtitle: nil)
11
11
  @title = title
@@ -1,13 +1,13 @@
1
1
  <div class="<%= classes %>"<%= info? ? ' data-controller="stat-card-info"'.html_safe : "" %>>
2
- <div class="flex items-start justify-between gap-2">
2
+ <div class="<%= HEADER_CLASSES %>">
3
3
  <p class="<%= label_classes %>"><%= label %></p>
4
4
  <% if info? %>
5
5
  <button type="button" class="<%= info_button_classes %>" data-action="click->stat-card-info#toggle" aria-label="Show metric details">
6
6
  <%= info_icon.html_safe %>
7
7
  </button>
8
8
  <div class="<%= disclosure_classes %>" data-stat-card-info-target="panel">
9
- <% if definition %><p><span class="font-medium text-gray-700 dark:text-gray-300">Captures:</span> <%= definition %></p><% end %>
10
- <% if calculation %><p><span class="font-medium text-gray-700 dark:text-gray-300">Calc:</span> <%= calculation %></p><% end %>
9
+ <% if definition %><p><span class="<%= EMPHASIS_CLASSES %>">Captures:</span> <%= definition %></p><% end %>
10
+ <% if calculation %><p><span class="<%= EMPHASIS_CLASSES %>">Calc:</span> <%= calculation %></p><% end %>
11
11
  </div>
12
12
  <% end %>
13
13
  </div>
@@ -3,25 +3,27 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class StatCardComponent < ViewComponent::Base
6
- CARD_CLASSES = "relative rounded-xl border border-gray-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-800"
7
- LABEL_CLASSES = "text-sm font-medium text-gray-500 dark:text-gray-400"
8
- VALUE_BASE_CLASSES = "mt-1 text-3xl font-bold"
9
- SUFFIX_CLASSES = "text-lg text-gray-500 dark:text-gray-400"
10
- DISCLOSURE_CLASSES = "hidden peer-hover:block peer-focus-visible:block absolute inset-x-0 top-full z-10 mt-2 space-y-1 rounded-lg border border-gray-200 bg-white p-3 text-sm text-gray-600 shadow-lg dark:border-zinc-700 dark:bg-zinc-800 dark:text-gray-400"
11
- CHANGE_ROW_CLASSES = "mt-1 h-5 text-sm font-medium"
6
+ EMPHASIS_CLASSES = "ks-stat-card-emphasis"
7
+ HEADER_CLASSES = "ks-stat-card-header flex items-start justify-between"
8
+ CARD_CLASSES = "ks-metric-card relative"
9
+ LABEL_CLASSES = "ks-stat-card-label text-sm"
10
+ VALUE_BASE_CLASSES = "ks-stat-card-value text-3xl"
11
+ SUFFIX_CLASSES = "ks-stat-card-suffix text-lg"
12
+ DISCLOSURE_CLASSES = "ks-stat-card-disclosure hidden peer-hover:block peer-focus-visible:block absolute inset-x-0 top-full z-10 text-sm"
13
+ CHANGE_ROW_CLASSES = "ks-stat-card-change h-5 text-sm"
12
14
  VALUE_LINK_CLASSES = "hover:underline focus:outline-none focus-visible:underline"
13
- INFO_BUTTON_CLASSES = "peer shrink-0 text-gray-400 transition hover:text-accent-600 dark:hover:text-accent-400"
15
+ INFO_BUTTON_CLASSES = "ks-stat-card-info peer shrink-0 transition"
14
16
 
15
17
  INFO_ICON = <<~SVG.freeze
16
18
  <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
17
19
  SVG
18
20
 
19
21
  VARIANT_CLASSES = {
20
- neutral: "text-gray-900 dark:text-white",
21
- success: "text-green-600 dark:text-green-400",
22
- danger: "text-red-600 dark:text-red-400",
23
- warning: "text-yellow-600 dark:text-yellow-400",
24
- info: "text-accent-600 dark:text-accent-400"
22
+ neutral: "ks-tone-neutral",
23
+ success: "ks-tone-success",
24
+ danger: "ks-tone-danger",
25
+ warning: "ks-tone-warning",
26
+ info: "ks-tone-info"
25
27
  }.freeze
26
28
 
27
29
  attr_reader :label, :value, :suffix, :definition, :calculation, :change, :href
@@ -87,10 +89,10 @@ module Keystone
87
89
  end
88
90
 
89
91
  def change_classes
90
- return "text-gray-500 dark:text-gray-400" if !change? || @change.zero?
91
- return "text-red-600 dark:text-red-400" if @change.negative?
92
+ return "ks-tone-muted" if !change? || @change.zero?
93
+ return "ks-tone-danger" if @change.negative?
92
94
 
93
- "text-green-600 dark:text-green-400"
95
+ "ks-tone-success"
94
96
  end
95
97
 
96
98
  def disclosure_classes
@@ -2,10 +2,10 @@
2
2
  data-swipe-deck-empty-title-value="<%= @empty_title %>"
3
3
  data-swipe-deck-empty-subtitle-value="<%= @empty_subtitle %>">
4
4
  <% if empty? %>
5
- <div class="text-center py-16" data-testid="swipe-empty">
6
- <p class="text-2xl font-semibold text-gray-900 dark:text-white"><%= @empty_title %></p>
5
+ <div class="<%= EMPTY_CLASSES %>" data-testid="swipe-empty">
6
+ <p class="<%= EMPTY_TITLE_CLASSES %>"><%= @empty_title %></p>
7
7
  <% if @empty_subtitle %>
8
- <p class="mt-2 text-gray-500 dark:text-gray-400"><%= @empty_subtitle %></p>
8
+ <p class="<%= EMPTY_MESSAGE_CLASSES %>"><%= @empty_subtitle %></p>
9
9
  <% end %>
10
10
  </div>
11
11
  <% else %>
@@ -21,15 +21,15 @@
21
21
  <% end %>
22
22
  </div>
23
23
 
24
- <div class="flex justify-center gap-8 mt-8">
24
+ <div class="<%= ACTIONS_CLASSES %>">
25
25
  <button data-action="swipe-deck#skip" data-testid="skip-button"
26
- class="flex items-center justify-center size-14 rounded-full border-2 border-gray-300 dark:border-zinc-600 text-gray-400 hover:border-red-400 hover:text-red-400 transition-colors">
26
+ class="<%= REJECT_BUTTON_CLASSES %>">
27
27
  <svg class="size-6" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
28
28
  <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
29
29
  </svg>
30
30
  </button>
31
31
  <button data-action="swipe-deck#complete" data-testid="complete-button"
32
- class="flex items-center justify-center size-14 rounded-full border-2 border-gray-300 dark:border-zinc-600 text-gray-400 hover:border-green-400 hover:text-green-400 transition-colors">
32
+ class="<%= ACCEPT_BUTTON_CLASSES %>">
33
33
  <svg class="size-6" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
34
34
  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
35
35
  </svg>
@@ -3,7 +3,13 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class SwipeDeckComponent < ViewComponent::Base
6
- CARD_CLASSES = "absolute inset-0 rounded-2xl border border-gray-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 shadow-lg p-6 flex flex-col items-center justify-center transition-transform duration-300"
6
+ ACCEPT_BUTTON_CLASSES = "ks-swipe-button ks-swipe-button-accept flex items-center justify-center size-14 transition-colors"
7
+ REJECT_BUTTON_CLASSES = "ks-swipe-button ks-swipe-button-reject flex items-center justify-center size-14 transition-colors"
8
+ ACTIONS_CLASSES = "ks-swipe-actions flex justify-center"
9
+ EMPTY_MESSAGE_CLASSES = "ks-swipe-empty-message"
10
+ EMPTY_TITLE_CLASSES = "ks-swipe-empty-title text-2xl"
11
+ EMPTY_CLASSES = "ks-swipe-empty text-center"
12
+ CARD_CLASSES = "ks-swipe-card absolute inset-0 flex flex-col items-center justify-center transition-transform duration-300"
7
13
 
8
14
  STACK_SCALE_STEP = 0.05
9
15
  STACK_TRANSLATE_STEP = 8
@@ -3,8 +3,8 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class TabSwitcherComponent < ViewComponent::Base
6
- TAB_BAR_CLASSES = "mb-8 flex flex-wrap justify-center gap-2"
7
- TAB_BASE_CLASSES = "rounded-lg px-4 py-2 text-sm font-semibold transition text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
6
+ TAB_BAR_CLASSES = "ks-tab-bar flex flex-wrap justify-center"
7
+ TAB_BASE_CLASSES = "ks-tab text-sm transition"
8
8
  PANEL_CLASSES = "hidden"
9
9
 
10
10
  attr_reader :tabs
@@ -18,7 +18,7 @@ module Keystone
18
18
  end
19
19
 
20
20
  def tab_classes
21
- "#{TAB_BASE_CLASSES} data-[active]:bg-accent-500/10 data-[active]:text-accent-600 dark:data-[active]:bg-accent-500/10 dark:data-[active]:text-accent-400"
21
+ "#{TAB_BASE_CLASSES} ks-tab-active"
22
22
  end
23
23
 
24
24
  def panel_classes
@@ -4,8 +4,8 @@ module Keystone
4
4
  module Ui
5
5
  class ThemeToggleComponent < ViewComponent::Base
6
6
  OPTIONS = [ [ "Light", "light" ], [ "Dark", "dark" ], [ "System", "system" ] ].freeze
7
- GROUP_CLASSES = "inline-flex gap-1"
8
- OPTION_CLASSES = "ks-button ks-button-sm ks-button-secondary aria-pressed:bg-accent-600 aria-pressed:hover:bg-accent-500"
7
+ GROUP_CLASSES = "ks-theme-toggle inline-flex"
8
+ OPTION_CLASSES = "ks-theme-toggle-option ks-button ks-button-sm ks-button-secondary"
9
9
 
10
10
  def initialize(current: nil)
11
11
  @current = current
@@ -21,7 +21,6 @@ module KeystoneUi
21
21
  [
22
22
  %(@import "#{KeystoneUi::Styles.tailwind_file}";),
23
23
  %(@source "#{@root}/app/components/**/*.{erb,rb}";),
24
- %(@import "#{@root}/app/assets/tailwind/keystone_ui_engine/nav.css";),
25
24
  %(@import "#{@root}/app/assets/tailwind/keystone_ui_engine/color_picker.css";),
26
25
  %(@import "#{@root}/app/assets/tailwind/keystone_ui_engine/grid_safelist.css";),
27
26
  *@imports.map { |import| %(@import "#{import}";) },
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.16.0"
4
+ VERSION = "0.17.0"
5
5
  end
@@ -74,6 +74,18 @@ holds the catalog.
74
74
  Tailwind's stock `gray-*` and `zinc-*` neutrals, or fixed status colors such
75
75
  as green and amber, directly. Changing the defaults belongs to the install
76
76
  local.
77
+ - **Looks.** A look is one CSS file that sets the `--ks-` variables from
78
+ keystone_ui-styles 0.6.0 or later: corner radius, font, label weight, border
79
+ width, padding and colours. Each colour variable has a `-dark` partner read
80
+ on a dark page. Buttons, panels, cards, alerts, badges, form fields, the
81
+ modal, the mobile action menu, the column picker, multi select, copy button,
82
+ theme toggle, checkbox row, radio card, option card, file upload and colour
83
+ picker read these variables. So do the data display components: stat card,
84
+ chart card, card link, CTA banner, feature grid, hero, data table, code,
85
+ accordion, disclosure, tab switcher, progress, funnel, bucket, pipeline and
86
+ swipe deck. So do the navigation components: navbar, nav item, nav dropdown,
87
+ bottom nav, mobile header and settings link. A host imports its look after `keystone_source.css`, and a gem ships one through
88
+ `tailwind_imports`, both set up through the install local.
77
89
  - **Light, dark, system and custom themes.** Every component has dark-mode
78
90
  styling. The theme is chosen in this order: the user's choice stored in a
79
91
  cookie, then a mode another gem supplies, then light. System leaves the page
@@ -33,7 +33,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
33
33
  ## How to use it
34
34
 
35
35
  1. Confirm the prerequisites: Ruby >= 3.2 and **tailwindcss-rails v4+** in the
36
- host app. The gem brings ViewComponent and keystone_ui-styles with it.
36
+ host app. The gem brings ViewComponent and keystone_ui-styles 0.6.0 or later with it.
37
37
  Tailwind does not have to be initialized first, because the generator creates
38
38
  the stylesheet if it is missing.
39
39
 
@@ -128,6 +128,29 @@ built on ViewComponent; hook it in before building any screen with those helpers
128
128
  or per-user colors generated at runtime by a companion theming gem. Ask which
129
129
  the app wants before wiring either.
130
130
 
131
+ To change how components look beyond the palette, write a look file: one CSS
132
+ file holding a `:root` rule, outside any `@layer` block, that sets the
133
+ `--ks-` variables from keystone_ui-styles for corner radius, font, label
134
+ weight, border width, padding and colours. Set each colour's `-dark`
135
+ partner too, or dark pages keep the default colour. Import it after
136
+ Keystone:
137
+
138
+ ```css
139
+ @import "tailwindcss";
140
+ @import "./keystone_source.css";
141
+ @import "./look.css";
142
+ ```
143
+
144
+ Buttons, panels, cards, alerts, badges, form fields, the modal, the mobile
145
+ action menu, the column picker, multi select, copy button, theme toggle,
146
+ checkbox row, radio card, option card, file upload and colour picker read
147
+ these variables. So do the data display components: stat card, chart card,
148
+ card link, CTA banner, feature grid, hero, data table, code, accordion,
149
+ disclosure, tab switcher, progress, funnel, bucket, pipeline and swipe deck.
150
+ So do the navigation components: navbar, nav item, nav dropdown, bottom nav,
151
+ mobile header and settings link. The keystone_ui-styles README lists every
152
+ variable and its default.
153
+
131
154
  7. Write `config/initializers/keystone_ui.rb` only if one of the settings below
132
155
  is wanted. Ask the developer about each rather than adding any by default.
133
156
  The engine reads the configuration after initializers have run, so this file
@@ -161,7 +184,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
161
184
  assign. Each import becomes an `@import` line and each source becomes an
162
185
  `@source` line in `keystone_source.css` on the next boot. They are for
163
186
  another gem or engine whose CSS or templates must be in the same Tailwind
164
- build, and that gem normally appends its own entries.
187
+ build, and that gem normally appends its own entries. A gem that ships a
188
+ look appends its look file to `tailwind_imports` from its own initializer,
189
+ and `keystone_source.css` imports it after keystone_ui-styles.
165
190
 
166
191
  ## Conventions
167
192
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keystone_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.3.0
18
+ version: 0.6.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 0.3.0
25
+ version: 0.6.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: view_component
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -71,7 +71,6 @@ files:
71
71
  - app/assets/javascripts/keystone_ui/theme_toggle_controller.js
72
72
  - app/assets/tailwind/keystone_ui_engine/color_picker.css
73
73
  - app/assets/tailwind/keystone_ui_engine/grid_safelist.css
74
- - app/assets/tailwind/keystone_ui_engine/nav.css
75
74
  - app/components/keystone/ui/accordion_component.html.erb
76
75
  - app/components/keystone/ui/accordion_component.rb
77
76
  - app/components/keystone/ui/alert_component.html.erb