iron-cms 0.3.0 → 0.4.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/iron.css +1468 -1447
  3. data/app/assets/tailwind/iron/application.css +12 -1
  4. data/app/assets/tailwind/iron/components/button.css +110 -60
  5. data/app/assets/tailwind/iron/components/input.css +11 -9
  6. data/app/assets/tailwind/iron/components/sidebar.css +13 -17
  7. data/app/helpers/iron/application_helper.rb +1 -1
  8. data/app/helpers/iron/form_builder.rb +46 -0
  9. data/app/javascript/iron/application.js +2 -0
  10. data/app/models/iron/entry/web_publishable.rb +12 -12
  11. data/app/views/iron/block_definitions/_form.html.erb +1 -1
  12. data/app/views/iron/block_definitions/index.html.erb +1 -1
  13. data/app/views/iron/block_definitions/show.html.erb +3 -3
  14. data/app/views/iron/content_types/_form.html.erb +1 -1
  15. data/app/views/iron/content_types/index.html.erb +4 -7
  16. data/app/views/iron/content_types/show.html.erb +3 -9
  17. data/app/views/iron/contents/new.html.erb +2 -2
  18. data/app/views/iron/entries/_form.html.erb +45 -37
  19. data/app/views/iron/entries/edit.html.erb +2 -12
  20. data/app/views/iron/entries/fields/_block.html.erb +3 -4
  21. data/app/views/iron/entries/fields/_block_list.html.erb +26 -17
  22. data/app/views/iron/entries/fields/_reference_item.html.erb +2 -3
  23. data/app/views/iron/entries/fields/_text_field.html.erb +1 -1
  24. data/app/views/iron/entries/index.html.erb +1 -1
  25. data/app/views/iron/field_definitions/_field_definition.html.erb +1 -2
  26. data/app/views/iron/field_definitions/edit.html.erb +1 -7
  27. data/app/views/iron/field_definitions/layouts/_form.html.erb +1 -1
  28. data/app/views/iron/first_runs/show.html.erb +1 -1
  29. data/app/views/iron/locales/_form.html.erb +1 -1
  30. data/app/views/iron/locales/_locale.html.erb +1 -1
  31. data/app/views/iron/locales/index.html.erb +1 -1
  32. data/app/views/iron/passwords/edit.html.erb +31 -6
  33. data/app/views/iron/passwords/new.html.erb +19 -18
  34. data/app/views/iron/schemas/new.html.erb +2 -2
  35. data/app/views/iron/sessions/new.html.erb +27 -26
  36. data/app/views/iron/settings/show.html.erb +3 -4
  37. data/app/views/iron/shared/_collection_select.html.erb +31 -0
  38. data/app/views/iron/users/_form.html.erb +1 -1
  39. data/app/views/iron/users/new.html.erb +1 -1
  40. data/app/views/iron/users/show.html.erb +1 -4
  41. data/app/views/layouts/iron/_mobile_header.html.erb +10 -0
  42. data/app/views/layouts/iron/_sidebar.html.erb +26 -81
  43. data/app/views/layouts/iron/_sidebar_content.html.erb +36 -0
  44. data/app/views/layouts/iron/_sidebar_item.html.erb +1 -5
  45. data/app/views/layouts/iron/_user_menu.html.erb +26 -0
  46. data/app/views/layouts/iron/application.html.erb +11 -27
  47. data/app/views/layouts/iron/authentication.html.erb +4 -21
  48. data/config/importmap.rb +1 -0
  49. data/lib/iron/version.rb +1 -1
  50. metadata +6 -3
  51. data/app/helpers/iron/components/dropdown_helper.rb +0 -161
@@ -53,7 +53,7 @@
53
53
  ::before,
54
54
  ::backdrop,
55
55
  ::file-selector-button {
56
- border-color: var(--color-gray-200, currentColor);
56
+ border-color: var(--color-stone-200, currentColor);
57
57
  }
58
58
  }
59
59
 
@@ -64,3 +64,14 @@
64
64
  }
65
65
  }
66
66
  }
67
+
68
+ @utility scrollbar-* {
69
+ scrollbar-color: --alpha(--value(--color-*) / calc(--modifier(integer) * 1%)) transparent;
70
+ }
71
+
72
+ @layer base {
73
+ /* Global overlay scrollbars */
74
+ * {
75
+ @apply scrollbar-stone-500/30 dark:scrollbar-stone-400/30;
76
+ }
77
+ }
@@ -1,74 +1,124 @@
1
- @utility btn {
2
- /* ---------- base ------------------------------------------------------ */
3
- @apply relative isolate inline-flex items-center justify-center gap-x-2 rounded-lg border font-semibold text-base/6;
4
- /* sizing */
5
- @apply px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] sm:text-sm/6;
6
- /* focus ring */
7
- @apply focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-stone-400;
8
- /* disabled */
9
- @apply disabled:opacity-50;
10
-
11
- /* embedded icons ------------------------------------------------------- */
12
- & > *[data-slot="icon"] {
13
- @apply -mx-0.5 my-0.5 size-5 shrink-0 text-[--btn-icon] sm:my-1 sm:size-4;
1
+ /* Base button styles */
2
+ @utility button-base {
3
+ @layer components {
4
+ @apply font-semibold shadow-xs outline-none;
5
+ @apply transition-colors;
6
+ @apply focus-visible:outline-2 focus-visible:outline-offset-2;
7
+ @apply disabled:opacity-50 disabled:pointer-events-none;
8
+ @apply dark:shadow-none;
9
+
10
+ /* Default to button-md if no size variant specified */
11
+ &:not([class*='button-xs']):not([class*='button-sm']):not([class*='button-md']):not([class*='button-lg']):not([class*='button-xl']) {
12
+ @apply button-md;
13
+ }
14
14
  }
15
+ }
15
16
 
16
- /* “solid” -------------------------------------------------------------- */
17
- &[data-variant="solid"],
18
- &:not([data-variant]) {
19
- /* implicit default */
20
- @apply border-transparent bg-(--btn-bg)
21
- before:absolute before:inset-0 before:-z-10
22
- before:rounded-[calc(var(--radius-lg)-1px)]
23
- before:bg-(--btn-bg) before:shadow-sm dark:before:hidden
24
- dark:border-white/5
25
- after:absolute after:inset-0 after:-z-10
26
- after:rounded-[calc(var(--radius-lg)-1px)]
27
- after:shadow-[inset_0_1px_var(--theme--color-white/15%)]
28
- dark:after:-inset-px dark:after:rounded-lg
29
- hover:after:bg-(--btn-hover-overlay)
30
- active:after:bg-(--btn-hover-overlay)
31
- disabled:before:shadow-none disabled:after:shadow-none;
17
+ /* Variant styles */
18
+ @utility button-primary {
19
+ @layer components {
20
+ @apply button-base;
21
+ @apply bg-sky-600 text-white;
22
+ @apply hover:bg-sky-500;
23
+ @apply focus-visible:outline-sky-600;
24
+ @apply dark:bg-sky-600 dark:hover:bg-sky-400 dark:focus-visible:outline-sky-500;
32
25
  }
26
+ }
33
27
 
34
- /* “outline” ------------------------------------------------------------ */
35
- &[data-variant="outline"] {
36
- @apply border-stone-950/10 text-stone-950
37
- hover:bg-stone-950/[2.5%] active:bg-stone-950/[2.5%]
38
- dark:border-white/15 dark:text-white
39
- dark:hover:bg-white/5 dark:active:bg-white/5
40
- [--btn-icon:var(--color-stone-500)]
41
- hover:[--btn-icon:var(--color-stone-700)]
42
- active:[--btn-icon:var(--color-stone-700)]
43
- dark:hover:[--btn-icon:var(--color-stone-400)]
44
- dark:active:[--btn-icon:var(--color-stone-400)];
28
+ @utility button-secondary {
29
+ @layer components {
30
+ @apply button-base;
31
+ @apply bg-white text-stone-900 inset-ring inset-ring-stone-300;
32
+ @apply hover:bg-stone-50;
33
+ @apply focus-visible:outline-stone-600;
34
+ @apply dark:bg-white/10 dark:text-white dark:inset-ring-white/5 dark:hover:bg-white/20 dark:focus-visible:outline-stone-500;
45
35
  }
36
+ }
46
37
 
47
- /* “plain” -------------------------------------------------------------- */
48
- &[data-variant="plain"] {
49
- @apply border-transparent text-stone-950
50
- hover:bg-stone-950/5 active:bg-stone-950/5
51
- dark:text-white dark:hover:bg-white/10 dark:active:bg-white/10
52
- [--btn-icon:var(--color-stone-500)]
53
- hover:[--btn-icon:var(--color-stone-700)]
54
- active:[--btn-icon:var(--color-stone-700)]
55
- dark:hover:[--btn-icon:var(--color-stone-400)]
56
- dark:active:[--btn-icon:var(--color-stone-400)];
38
+ @utility button-soft {
39
+ @layer components {
40
+ @apply button-base;
41
+ @apply bg-indigo-50 text-indigo-600;
42
+ @apply hover:bg-indigo-100;
43
+ @apply focus-visible:outline-indigo-600;
44
+ @apply dark:bg-indigo-500/20 dark:text-indigo-400 dark:hover:bg-indigo-500/30 dark:focus-visible:outline-indigo-500;
57
45
  }
46
+ }
58
47
 
59
- /* ---------- semantic colors (primary, accent, destructive) ----------- */
60
- &[data-color="primary"],
61
- &:not([data-color]) {
62
- @apply text-white [--btn-bg:var(--color-stone-600)] [--btn-border:var(--color-stone-700)]/90 [--btn-hover-overlay:var(--color-white)]/10 [--btn-icon:var(--color-stone-400)] hover:[--btn-icon:var(--color-stone-300)] active:[--btn-icon:var(--color-stone-300)];
48
+ @utility button-ghost {
49
+ @layer components {
50
+ @apply button-base;
51
+ @apply text-stone-700;
52
+ @apply hover:bg-stone-100;
53
+ @apply focus-visible:outline-stone-600;
54
+ @apply dark:text-white dark:hover:bg-white/10 dark:focus-visible:outline-stone-500;
63
55
  }
64
- &[data-color="accent"] {
65
- @apply text-white [--btn-bg:var(--color-sky-500)] [--btn-border:var(--color-sky-600)]/80 [--btn-hover-overlay:var(--color-white)]/10 [--btn-icon:var(--color-white)]/60 hover:[--btn-icon:var(--color-white)]/80 active:[--btn-icon:var(--color-white)]/80;
56
+ }
57
+
58
+ @utility button-destructive {
59
+ @layer components {
60
+ @apply button-base;
61
+ @apply bg-red-600 text-white;
62
+ @apply hover:bg-red-500;
63
+ @apply focus-visible:outline-red-600;
64
+ @apply dark:bg-red-500 dark:hover:bg-red-400 dark:focus-visible:outline-red-500;
66
65
  }
67
- &[data-color="destructive"] {
68
- @apply text-white [--btn-bg:var(--color-red-600)] [--btn-border:var(--color-red-700)]/90 [--btn-hover-overlay:var(--color-white)]/10 [--btn-icon:var(--color-red-300)] hover:[--btn-icon:var(--color-red-200)] active:[--btn-icon:var(--color-red-200)];
66
+ }
67
+
68
+ /* Size variants */
69
+ @utility button-xs {
70
+ @layer components {
71
+ @apply inline-flex items-center gap-x-1 rounded-sm px-2 py-1 text-xs;
72
+
73
+ & > svg {
74
+ @apply size-5 first:-ml-0.5 last:-mr-0.5;
75
+ }
76
+ }
77
+ }
78
+
79
+ @utility button-sm {
80
+ @layer components {
81
+ @apply inline-flex items-center gap-x-1 rounded-sm px-2 py-1 text-sm;
82
+
83
+ & > svg {
84
+ @apply size-5 first:-ml-0.5 last:-mr-0.5;
85
+ }
69
86
  }
70
87
  }
71
88
 
72
- @utility btn-touch-target {
73
- @apply absolute left-1/2 top-1/2 size-[max(100%,2.75rem)] -translate-x-1/2 -translate-y-1/2 [@media(pointer:fine)]:hidden;
89
+ @utility button-md {
90
+ @layer components {
91
+ @apply inline-flex items-center gap-x-1.5 rounded-md px-2.5 py-1.5 text-sm;
92
+
93
+ & > svg {
94
+ @apply size-5 first:-ml-0.5 last:-mr-0.5;
95
+ }
96
+ }
97
+ }
98
+
99
+ @utility button-lg {
100
+ @layer components {
101
+ @apply inline-flex items-center gap-x-1.5 rounded-md px-3 py-2 text-sm;
102
+
103
+ & > svg {
104
+ @apply size-5 first:-ml-0.5 last:-mr-0.5;
105
+ }
106
+ }
107
+ }
108
+
109
+ @utility button-xl {
110
+ @layer components {
111
+ @apply inline-flex items-center gap-x-2 rounded-md px-3.5 py-2.5 text-sm;
112
+
113
+ & > svg {
114
+ @apply size-5 first:-ml-0.5 last:-mr-0.5;
115
+ }
116
+ }
117
+ }
118
+
119
+ /* Legacy support - map old btn class to button-primary button-md */
120
+ @utility btn {
121
+ @layer components {
122
+ @apply button-primary button-md;
123
+ }
74
124
  }
@@ -1,19 +1,21 @@
1
1
  @utility input {
2
- @apply relative block w-full appearance-none rounded-lg;
3
- @apply px-3 py-2 sm:px-2.5 sm:py-1.5;
4
- @apply text-base/6 sm:text-sm/6;
5
- @apply text-stone-100 placeholder:text-stone-500;
2
+ @apply relative block w-full appearance-none rounded-md;
3
+ @apply px-3 py-1.5;
4
+ @apply text-base sm:text-sm/6;
5
+ @apply text-stone-900 placeholder:text-stone-400;
6
6
 
7
7
  /* Border and background */
8
- @apply border border-stone-950/10;
9
- @apply dark:border-white/10;
10
- @apply bg-transparent dark:bg-white/5;
8
+ @apply outline-1 -outline-offset-1 outline-stone-300;
9
+ @apply bg-white;
11
10
 
12
11
  /* Focus state */
13
- @apply focus:outline focus:outline-2 focus:outline-stone-500;
12
+ @apply focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600;
13
+
14
+ /* Dark mode */
15
+ @apply dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-stone-500 dark:focus:outline-indigo-500;
14
16
 
15
17
  /* States */
16
- @apply disabled:opacity-50 disabled:bg-stone-700 disabled:border-stone-600;
18
+ @apply disabled:opacity-50;
17
19
 
18
20
  /* Error state */
19
21
  &.is-invalid {
@@ -1,21 +1,17 @@
1
1
  @utility sidebar-item {
2
2
  /* Base */
3
- @apply flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-base/6 font-medium text-stone-950 sm:py-2 sm:text-sm/5;
4
- /* Leading icon/icon-only */
5
- @apply *:data-[slot=icon]:size-6 *:data-[slot=icon]:shrink-0 sm:*:data-[slot=icon]:size-5;
6
- /* Trailing icon (down chevron or similar) */
7
- @apply *:last:data-[slot=icon]:ml-auto *:last:data-[slot=icon]:size-5 sm:*:last:data-[slot=icon]:size-4;
8
- /* Avatar */
9
- @apply *:data-[slot=avatar]:-m-0.5 *:data-[slot=avatar]:size-7 *:data-[slot=avatar]:[--ring-opacity:10%] sm:*:data-[slot=avatar]:size-6;
10
- /* Hover */
11
- @apply hover:bg-stone-950/5;
12
- /* Active */
13
- @apply active:bg-stone-950/5 active:*:data-[slot=icon]:fill-stone-950;
14
- /* Current */
15
- @apply data-current:*:data-[slot=icon]:bg-transparent;
16
- /* Dark mode */
17
- @apply dark:text-white dark:*:data-[slot=icon]:text-stone-400;
18
- @apply dark:hover:bg-white/5 dark:hover:*:data-[slot=icon]:text-white;
19
- @apply dark:active:bg-white/5 dark:active:*:data-[slot=icon]:text-white;
3
+ @apply flex gap-x-3 rounded-md p-2 text-sm/6 font-semibold;
4
+ /* Default state */
5
+ @apply text-stone-700 dark:text-stone-400;
6
+ /* Hover state */
7
+ @apply hover:bg-stone-50 hover:text-stone-600 dark:hover:bg-white/5 dark:hover:text-white;
8
+ /* Leading icon */
9
+ @apply *:data-[slot=icon]:size-6 *:data-[slot=icon]:shrink-0;
10
+ @apply *:data-[slot=icon]:text-stone-400;
11
+ @apply hover:*:data-[slot=icon]:text-stone-600 dark:hover:*:data-[slot=icon]:text-white;
12
+ /* Current state */
13
+ @apply data-current:bg-stone-50 data-current:text-stone-600;
14
+ @apply dark:data-current:bg-white/5 dark:data-current:text-white;
15
+ @apply data-current:*:data-[slot=icon]:text-stone-600;
20
16
  @apply dark:data-current:*:data-[slot=icon]:text-white;
21
17
  }
@@ -2,7 +2,7 @@ require "tailwind_merge"
2
2
  module Iron
3
3
  module ApplicationHelper
4
4
  include IconsHelper, AvatarHelper, ButtonsHelper, EntriesHelper, ContentTypesHelper
5
- include Components::DropdownHelper, Components::BadgeHelper
5
+ include Components::BadgeHelper
6
6
 
7
7
  def tw(*classes)
8
8
  TailwindMerge::Merger.new.merge(classes.reject(&:blank?).compact.join(" "))
@@ -39,5 +39,51 @@ module Iron
39
39
  options[:class] = @template.tw("text-sm/6 font-medium", options[:class])
40
40
  super(method, text, options, &block)
41
41
  end
42
+
43
+ def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
44
+ selected_value = object.send(method) rescue nil
45
+
46
+ @template.render partial: "iron/shared/collection_select", locals: {
47
+ field_name: "#{object_name}[#{method}]",
48
+ select_id: html_options[:id] || "#{object_name}_#{method}",
49
+ selected_value: selected_value,
50
+ collection: collection,
51
+ value_method: value_method,
52
+ text_method: text_method,
53
+ options: options,
54
+ html_options: html_options
55
+ }
56
+ end
57
+
58
+ def select(method, choices = nil, options = {}, html_options = {}, &block)
59
+ selected_value = object.send(method) rescue nil
60
+
61
+ # Convert choices to a uniform format
62
+ collection = case choices
63
+ when Hash
64
+ choices.map { |text, value| OpenStruct.new(text: text, value: value) }
65
+ when Array
66
+ choices.map do |item|
67
+ if item.is_a?(Array)
68
+ OpenStruct.new(text: item[0], value: item[1])
69
+ else
70
+ OpenStruct.new(text: item, value: item)
71
+ end
72
+ end
73
+ else
74
+ []
75
+ end
76
+
77
+ @template.render partial: "iron/shared/collection_select", locals: {
78
+ field_name: "#{object_name}[#{method}]",
79
+ select_id: html_options[:id] || "#{object_name}_#{method}",
80
+ selected_value: selected_value,
81
+ collection: collection,
82
+ value_method: :value,
83
+ text_method: :text,
84
+ options: options,
85
+ html_options: html_options
86
+ }
87
+ end
42
88
  end
43
89
  end
@@ -4,3 +4,5 @@ import "controllers";
4
4
 
5
5
  import "trix"
6
6
  import "@rails/actiontext"
7
+
8
+ import "@tailwindplus/elements"
@@ -3,8 +3,8 @@ module Iron
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- before_validation :generate_route, if: :should_generate_route?
7
6
  before_validation :normalize_route
7
+ before_validation :generate_route, if: :should_generate_route?
8
8
 
9
9
  validates :route, uniqueness: { scope: :content_type_id, allow_blank: true }, if: :route_required?
10
10
  validates :route, format: { with: /\A[a-z0-9\-\/]*\z/, message: "can only contain lowercase letters, numbers, hyphens and slashes" }, allow_blank: true
@@ -12,11 +12,7 @@ module Iron
12
12
  end
13
13
 
14
14
  def use_as_index=(value)
15
- if ActiveModel::Type::Boolean.new.cast(value)
16
- self.route = ""
17
- elsif route.blank?
18
- self.route = nil
19
- end
15
+ @use_as_index_intent = ActiveModel::Type::Boolean.new.cast(value)
20
16
  end
21
17
 
22
18
  def use_as_index
@@ -67,12 +63,16 @@ module Iron
67
63
  end
68
64
 
69
65
  def normalize_route
70
- return if route.blank?
71
-
72
- self.route = route.downcase
73
- .gsub(/[^a-z0-9\-\/]+/, "-") # Replace non-allowed chars with hyphens
74
- .gsub(/\-+/, "-") # Replace multiple hyphens with single hyphen
75
- .gsub(/\A[\-\/]+|[\-\/]+\z/, "") # Remove leading/trailing hyphens and slashes
66
+ if @use_as_index_intent
67
+ self.route = ""
68
+ elsif route.present?
69
+ self.route = route.downcase
70
+ .gsub(/[^a-z0-9\-\/]+/, "-") # Replace non-allowed chars with hyphens
71
+ .gsub(/\-+/, "-") # Replace multiple hyphens with single hyphen
72
+ .gsub(/\A[\-\/]+|[\-\/]+\z/, "") # Remove leading/trailing hyphens and slashes
73
+ elsif @use_as_index_intent == false
74
+ self.route = nil
75
+ end
76
76
  end
77
77
 
78
78
 
@@ -41,6 +41,6 @@
41
41
  </div>
42
42
 
43
43
  <div class="mt-4">
44
- <%= form.submit class: "btn" %>
44
+ <%= form.submit class: "button-primary" %>
45
45
  </div>
46
46
  <% end %>
@@ -3,7 +3,7 @@
3
3
  <div class="space-y-8">
4
4
  <div class="flex justify-between items-center">
5
5
  <h1 class="page-title">Block definitions</h1>
6
- <%= link_to "New block definition", new_block_definition_path, class: "btn" %>
6
+ <%= link_to "New block definition", new_block_definition_path, class: "button-primary" %>
7
7
  </div>
8
8
 
9
9
  <div
@@ -5,9 +5,9 @@
5
5
  <div class="flex justify-between">
6
6
  <h1 class="page-title"><%= @block_definition.name %></h1>
7
7
  <div>
8
- <%= link_to "Edit", edit_block_definition_path(@block_definition), class: "btn", data: { variant: "outline" } %>
8
+ <%= link_to "Edit", edit_block_definition_path(@block_definition), class: "button-secondary" %>
9
9
  <div class="mt-4 inline-block ml-2">
10
- <%= button_to "Destroy", @block_definition, method: :delete, class: "btn", data: { color: "destructive" } %>
10
+ <%= button_to "Destroy", @block_definition, method: :delete, class: "button-destructive" %>
11
11
  </div>
12
12
  </div>
13
13
  </div>
@@ -29,6 +29,6 @@
29
29
  <div class="mt-4">
30
30
  <%= link_to "+ Add new field",
31
31
  new_block_definition_field_definition_path(@block_definition),
32
- class: "btn" %>
32
+ class: "button-primary" %>
33
33
  </div>
34
34
  </div>
@@ -132,6 +132,6 @@
132
132
  <% end %>
133
133
 
134
134
  <div class="mt-4">
135
- <%= form.submit %>
135
+ <%= form.submit class: "button-primary" %>
136
136
  </div>
137
137
  <% end %>
@@ -6,13 +6,10 @@
6
6
  <div class="flex items-center gap-2">
7
7
  <%= link_to "Export",
8
8
  export_schema_path,
9
- class: "btn",
10
- data: {
11
- variant: "outline",
12
- turbo: false,
13
- } %>
14
- <%= link_to "Import", schema_path, class: "btn", data: { variant: "outline" } %>
15
- <%= link_to "New Content Type", new_content_type_path, class: "btn" %>
9
+ class: "button-secondary",
10
+ data: { turbo: false } %>
11
+ <%= link_to "Import", schema_path, class: "button-secondary" %>
12
+ <%= link_to "New Content Type", new_content_type_path, class: "button-primary" %>
16
13
  </div>
17
14
  </div>
18
15
 
@@ -7,18 +7,12 @@
7
7
  <div>
8
8
  <%= link_to "Edit",
9
9
  edit_content_type_path(@content_type),
10
- class: "btn",
11
- data: {
12
- variant: "outline",
13
- } %>
10
+ class: "button-secondary" %>
14
11
  <div class="mt-4 inline-block ml-2">
15
12
  <%= button_to "Destroy",
16
13
  @content_type,
17
14
  method: :delete,
18
- class: "btn",
19
- data: {
20
- color: "destructive",
21
- } %>
15
+ class: "button-destructive" %>
22
16
  </div>
23
17
  </div>
24
18
  </div>
@@ -44,6 +38,6 @@
44
38
  <div class="mt-4">
45
39
  <%= link_to "+ Add new field",
46
40
  new_content_type_field_definition_path(@content_type),
47
- class: "btn" %>
41
+ class: "button-primary" %>
48
42
  </div>
49
43
  </div>
@@ -27,8 +27,8 @@
27
27
  </div>
28
28
 
29
29
  <div class="mt-6 flex items-center gap-x-3">
30
- <%= form.submit "Import Content", class: "btn" %>
31
- <%= link_to "Cancel", settings_path, class: "btn", data: { variant: "plain" } %>
30
+ <%= form.submit "Import Content", class: "button-primary" %>
31
+ <%= link_to "Cancel", settings_path, class: "button-secondary" %>
32
32
  </div>
33
33
  <% end %>
34
34
  </div>
@@ -15,49 +15,57 @@
15
15
  </div>
16
16
 
17
17
  <% if entry.content_type.web_publishing_enabled? %>
18
- <fieldset class="mt-6">
19
- <legend>Web Publishing</legend>
20
-
21
- <div class="field">
22
- <%= form.label :route, "Route" %>
23
- <div>
24
- <%= form.text_field :route,
25
- placeholder: "e.g., 'about' or 'company/team'",
26
- pattern: "[a-z0-9\\-\\/]*",
27
- title:
28
- "Only lowercase letters, numbers, hyphens and slashes allowed" %>
29
- <% if entry.content_type.base_path.present? %>
30
- <p class="text-sm text-stone-500 mt-1">
31
- URL:
32
- <%= entry.content_type.path_for(entry) || "/#{entry.content_type.base_path}/[route]" %>
33
- </p>
34
- <% else %>
35
- <p class="text-sm text-stone-500 mt-1">
36
- URL:
37
- <%= entry.route.blank? ? "/" : "/#{entry.route}" %>
38
- </p>
39
- <% end %>
40
- <%= form.error_for :route %>
18
+ <fieldset class="my-6 group">
19
+ <legend class="mb-4">Web Publishing</legend>
20
+
21
+ <div>
22
+
23
+ <div class="flex items-center justify-between">
24
+ <span class="flex grow flex-col">
25
+ <%= form.label :use_as_index, "Use as index page", class: "text-sm/6 font-medium text-stone-900 dark:text-white" %>
26
+ <span class="text-sm text-stone-500 dark:text-stone-400">
27
+ <% if entry.content_type.base_path.present? %>
28
+ Make this entry available at /<%= entry.content_type.base_path %>/
29
+ <% else %>
30
+ Make this entry the site home page at /
31
+ <% end %>
32
+ </span>
33
+ </span>
34
+ <div class="group relative inline-flex w-11 shrink-0 rounded-full bg-stone-200 p-0.5 inset-ring inset-ring-stone-900/5 outline-offset-2 outline-sky-600 transition-colors duration-200 ease-in-out has-checked:bg-sky-600 has-focus-visible:outline-2 dark:bg-white/5 dark:inset-ring-white/10 dark:outline-sky-500 dark:has-checked:bg-sky-500">
35
+ <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-stone-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-5"></span>
36
+ <%= form.check_box :use_as_index, class: "absolute inset-0 appearance-none focus:outline-hidden" %>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="field group-has-checked:hidden">
41
+ <%= form.label :route, "Route" %>
42
+ <div>
43
+ <%= form.text_field :route,
44
+ placeholder: "e.g., 'about' or 'company/team'",
45
+ pattern: "[a-z0-9\\-\\/]*",
46
+ title:
47
+ "Only lowercase letters, numbers, hyphens and slashes allowed" %>
48
+ <% if entry.content_type.base_path.present? %>
49
+ <p class="text-sm text-stone-500 mt-1">
50
+ URL:
51
+ <%= entry.content_type.path_for(entry) || "/#{entry.content_type.base_path}/[route]" %>
52
+ </p>
53
+ <% else %>
54
+ <p class="text-sm text-stone-500 mt-1">
55
+ URL:
56
+ <%= entry.route.blank? ? "/" : "/#{entry.route}" %>
57
+ </p>
58
+ <% end %>
59
+ <%= form.error_for :route %>
60
+ </div>
41
61
  </div>
42
- </div>
43
62
 
44
- <div class="field">
45
- <%= form.label :use_as_index do %>
46
- <%= form.check_box :use_as_index %>
47
- Use as index page
48
- <% end %>
49
- <p class="text-sm text-stone-500 mt-1">
50
- <% if entry.content_type.base_path.present? %>
51
- Check this to make this entry available at /<%= entry.content_type.base_path %>/
52
- <% else %>
53
- Check this to make this entry the site home page at /
54
- <% end %>
55
- </p>
56
63
  </div>
64
+
57
65
  </fieldset>
58
66
  <% end %>
59
67
 
60
68
  <div class="mt-4">
61
- <%= form.submit %>
69
+ <%= form.submit class: "button-primary" %>
62
70
  </div>
63
71
  <% end %>
@@ -29,22 +29,12 @@
29
29
  <% end %>
30
30
  <% end %>
31
31
  <% if @entry.content_type.web_publishing_enabled? && !@entry.route.nil? %>
32
- <%= link_to "View",
33
- @entry.path,
34
- target: "_blank",
35
- rel: "noopener",
36
- class: "btn",
37
- data: {
38
- color: "secondary",
39
- } %>
32
+ <%= link_to "View", @entry.path, target: "_blank", rel: "noopener", class: "button-secondary" %>
40
33
  <% end %>
41
34
  <%= button_to "Destroy",
42
35
  entry_path(@entry),
43
36
  method: :delete,
44
- class: "btn",
45
- data: {
46
- color: "destructive",
47
- } %>
37
+ class: "button-destructive" %>
48
38
  </div>
49
39
  </div>
50
40