aeros 0.0.1 → 0.0.2

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/assets/stylesheets/aeros/application.css +1 -15
  4. data/app/assets/stylesheets/aeros/base.css +43 -0
  5. data/app/assets/stylesheets/aeros/reset.css +397 -0
  6. data/app/assets/stylesheets/aeros/source.css +15 -0
  7. data/app/assets/stylesheets/aeros/theme.css +6 -0
  8. data/app/assets/stylesheets/aeros/themes/slate.css +163 -0
  9. data/app/assets/stylesheets/aeros/themes/zinc.css +163 -0
  10. data/app/assets/stylesheets/aeros/utilities.css +23 -0
  11. data/app/components/aeros/application_view_component.rb +149 -5
  12. data/app/components/aeros/blocks/component_preview/component.html.erb +7 -0
  13. data/app/components/aeros/blocks/component_preview/component.rb +10 -0
  14. data/app/components/aeros/blocks/component_preview/styles.css +10 -0
  15. data/app/components/aeros/form_builder.rb +24 -8
  16. data/app/components/aeros/pages/showcase/index/component.html.erb +53 -0
  17. data/app/components/aeros/pages/showcase/index/component.rb +7 -0
  18. data/app/components/aeros/pages/showcase/index/styles.css +27 -0
  19. data/app/components/aeros/pages/showcase/placeholder/component.html.erb +7 -0
  20. data/app/components/aeros/pages/showcase/placeholder/component.rb +10 -0
  21. data/app/components/aeros/pages/showcase/show/component.html.erb +38 -0
  22. data/app/components/aeros/pages/showcase/show/component.rb +48 -0
  23. data/app/components/aeros/primitives/button/component.rb +66 -0
  24. data/app/components/aeros/primitives/button/styles.css +153 -0
  25. data/app/components/aeros/primitives/card/component.html.erb +3 -0
  26. data/app/components/aeros/primitives/card/component.rb +42 -0
  27. data/app/components/aeros/primitives/card/styles.css +28 -0
  28. data/app/components/aeros/primitives/conversation/component.html.erb +28 -0
  29. data/app/components/aeros/primitives/conversation/component.rb +15 -0
  30. data/app/components/aeros/primitives/conversation/controller.js +18 -0
  31. data/app/components/aeros/primitives/conversation/message/component.html.erb +24 -0
  32. data/app/components/aeros/primitives/conversation/message/component.rb +35 -0
  33. data/app/components/aeros/primitives/conversation/streaming_indicator/component.html.erb +21 -0
  34. data/app/components/aeros/primitives/conversation/streaming_indicator/component.rb +18 -0
  35. data/app/components/aeros/primitives/conversation/styles.css +221 -0
  36. data/app/components/aeros/primitives/conversation/user_message_box/component.html.erb +1 -0
  37. data/app/components/aeros/{empty → primitives/conversation/user_message_box}/component.rb +1 -2
  38. data/app/components/aeros/primitives/drawer/component.html.erb +43 -0
  39. data/app/components/aeros/primitives/drawer/component.rb +33 -0
  40. data/app/components/aeros/primitives/drawer/controller.js +104 -0
  41. data/app/components/aeros/primitives/drawer/styles.css +90 -0
  42. data/app/components/aeros/primitives/dropdown/checkbox.rb +22 -0
  43. data/app/components/aeros/primitives/dropdown/component.html.erb +38 -0
  44. data/app/components/aeros/primitives/dropdown/component.rb +53 -0
  45. data/app/components/aeros/primitives/dropdown/controller.js +153 -0
  46. data/app/components/aeros/primitives/dropdown/item.rb +29 -0
  47. data/app/components/aeros/primitives/dropdown/label.rb +7 -0
  48. data/app/components/aeros/primitives/dropdown/radio_group.rb +16 -0
  49. data/app/components/aeros/primitives/dropdown/radio_item.rb +24 -0
  50. data/app/components/aeros/primitives/dropdown/separator.rb +7 -0
  51. data/app/components/aeros/primitives/dropdown/styles.css +155 -0
  52. data/app/components/aeros/primitives/empty/component.html.erb +15 -0
  53. data/app/components/aeros/primitives/empty/component.rb +18 -0
  54. data/app/components/aeros/primitives/empty/styles.css +40 -0
  55. data/app/components/aeros/primitives/input_attachments/component.html.erb +60 -0
  56. data/app/components/aeros/primitives/input_attachments/component.rb +52 -0
  57. data/app/components/aeros/primitives/input_attachments/controller.js +357 -0
  58. data/app/components/aeros/primitives/input_attachments/styles.css +102 -0
  59. data/app/components/aeros/primitives/input_color/component.html.erb +24 -0
  60. data/app/components/aeros/primitives/input_color/component.rb +42 -0
  61. data/app/components/aeros/primitives/input_color/styles.css +64 -0
  62. data/app/components/aeros/primitives/input_password/component.html.erb +43 -0
  63. data/app/components/aeros/primitives/input_password/component.rb +20 -0
  64. data/app/components/aeros/primitives/input_password/styles.css +61 -0
  65. data/app/components/aeros/{input_select → primitives/input_select}/component.html.erb +19 -19
  66. data/app/components/aeros/primitives/input_select/component.rb +21 -0
  67. data/app/components/aeros/primitives/input_select/option.rb +14 -0
  68. data/app/components/aeros/primitives/input_select/styles.css +30 -0
  69. data/app/components/aeros/primitives/input_slider/component.html.erb +33 -0
  70. data/app/components/aeros/primitives/input_slider/component.rb +35 -0
  71. data/app/components/aeros/primitives/input_slider/styles.css +74 -0
  72. data/app/components/aeros/primitives/input_tagging/component.html.erb +73 -0
  73. data/app/components/aeros/primitives/input_tagging/component.rb +40 -0
  74. data/app/components/aeros/primitives/input_tagging/controller.js +326 -0
  75. data/app/components/aeros/primitives/input_tagging/styles.css +148 -0
  76. data/app/components/aeros/primitives/input_text/component.html.erb +25 -0
  77. data/app/components/aeros/primitives/input_text/component.rb +20 -0
  78. data/app/components/aeros/primitives/input_text/styles.css +38 -0
  79. data/app/components/aeros/primitives/input_text_area/component.html.erb +23 -0
  80. data/app/components/aeros/primitives/input_text_area/component.rb +19 -0
  81. data/app/components/aeros/primitives/input_text_area/styles.css +30 -0
  82. data/app/components/aeros/primitives/input_text_area_ai/component.html.erb +51 -0
  83. data/app/components/aeros/primitives/input_text_area_ai/component.rb +47 -0
  84. data/app/components/aeros/primitives/input_text_area_ai/controller.js +198 -0
  85. data/app/components/aeros/primitives/input_text_area_ai/styles.css +91 -0
  86. data/app/components/aeros/primitives/input_wrapper/component.html.erb +20 -0
  87. data/app/components/aeros/primitives/input_wrapper/component.rb +31 -0
  88. data/app/components/aeros/primitives/input_wrapper/styles.css +72 -0
  89. data/app/components/aeros/primitives/layouts/agentic/component.html.erb +4 -0
  90. data/app/components/aeros/primitives/layouts/agentic/component.rb +23 -0
  91. data/app/components/aeros/primitives/layouts/app/aside.rb +9 -0
  92. data/app/components/aeros/primitives/layouts/app/component.html.erb +14 -0
  93. data/app/components/aeros/primitives/layouts/app/component.rb +11 -0
  94. data/app/components/aeros/primitives/layouts/app/sidebar.rb +9 -0
  95. data/app/components/aeros/primitives/layouts/app/styles.css +46 -0
  96. data/app/components/aeros/primitives/page/component.html.erb +24 -0
  97. data/app/components/aeros/primitives/page/component.rb +23 -0
  98. data/app/components/aeros/primitives/page/styles.css +55 -0
  99. data/app/components/aeros/primitives/sidebar/component.html.erb +25 -0
  100. data/app/components/aeros/primitives/sidebar/component.rb +14 -0
  101. data/app/components/aeros/primitives/sidebar/footer.rb +7 -0
  102. data/app/components/aeros/primitives/sidebar/group.rb +18 -0
  103. data/app/components/aeros/primitives/sidebar/header.rb +7 -0
  104. data/app/components/aeros/primitives/sidebar/item.rb +19 -0
  105. data/app/components/aeros/primitives/sidebar/styles.css +95 -0
  106. data/app/components/aeros/primitives/spinner/component.rb +36 -0
  107. data/app/components/aeros/primitives/spinner/styles.css +81 -0
  108. data/app/components/aeros/primitives/table/cell.rb +7 -0
  109. data/app/components/aeros/primitives/table/column.rb +7 -0
  110. data/app/components/aeros/primitives/table/component.html.erb +8 -0
  111. data/app/components/aeros/primitives/table/component.rb +14 -0
  112. data/app/components/aeros/primitives/table/header.rb +13 -0
  113. data/app/components/aeros/primitives/table/row.rb +11 -0
  114. data/app/components/aeros/primitives/table/styles.css +39 -0
  115. data/app/controllers/aeros/application_controller.rb +11 -0
  116. data/app/controllers/aeros/showcase_controller.rb +37 -1
  117. data/app/controllers/aeros/theme_controller.rb +10 -0
  118. data/app/helpers/aeros/application_helper.rb +19 -7
  119. data/app/views/layouts/aeros/application.html.erb +49 -14
  120. data/config/importmap.rb +6 -1
  121. data/config/routes.rb +2 -0
  122. data/lib/aeros/configuration.rb +56 -0
  123. data/lib/aeros/engine.rb +7 -1
  124. data/lib/aeros/theme.rb +326 -0
  125. data/lib/aeros/version.rb +1 -1
  126. data/lib/aeros.rb +2 -0
  127. data/lib/tasks/aeros_tasks.rake +25 -7
  128. metadata +127 -38
  129. data/app/assets/stylesheets/aeros/application.tailwind.css +0 -7
  130. data/app/assets/stylesheets/aeros/tailwind.css +0 -1100
  131. data/app/components/aeros/button/component.rb +0 -128
  132. data/app/components/aeros/card/component.html.erb +0 -3
  133. data/app/components/aeros/card/component.rb +0 -7
  134. data/app/components/aeros/dropdown/component.html.erb +0 -26
  135. data/app/components/aeros/dropdown/component.rb +0 -66
  136. data/app/components/aeros/empty/component.html.erb +0 -12
  137. data/app/components/aeros/input_password/component.html.erb +0 -43
  138. data/app/components/aeros/input_password/component.rb +0 -6
  139. data/app/components/aeros/input_select/component.rb +0 -24
  140. data/app/components/aeros/input_text/component.html.erb +0 -25
  141. data/app/components/aeros/input_text/component.rb +0 -5
  142. data/app/components/aeros/input_wrapper/component.html.erb +0 -20
  143. data/app/components/aeros/input_wrapper/component.rb +0 -12
  144. data/app/components/aeros/page/component.html.erb +0 -24
  145. data/app/components/aeros/page/component.rb +0 -9
  146. data/app/components/aeros/spinner/component.rb +0 -55
  147. data/app/components/aeros/table/component.html.erb +0 -10
  148. data/app/components/aeros/table/component.rb +0 -64
  149. data/app/views/aeros/showcase/index.html.erb +0 -1
  150. /data/app/components/aeros/{button → primitives/button}/controller.js +0 -0
  151. /data/app/components/aeros/{input_password → primitives/input_password}/controller.js +0 -0
@@ -0,0 +1,25 @@
1
+ <div class="cp-sidebar">
2
+ <% if header? %>
3
+ <div class="cp-sidebar__header"><%= header %></div>
4
+ <% end %>
5
+
6
+ <% if items.any? || groups.any? %>
7
+ <nav class="cp-sidebar__nav">
8
+ <% if items.any? %>
9
+ <ul class="cp-sidebar__menu">
10
+ <% items.each do |item| %>
11
+ <li><%= item %></li>
12
+ <% end %>
13
+ </ul>
14
+ <% end %>
15
+
16
+ <% groups.each do |group| %>
17
+ <%= group %>
18
+ <% end %>
19
+ </nav>
20
+ <% end %>
21
+
22
+ <% if footer? %>
23
+ <div class="cp-sidebar__footer"><%= footer %></div>
24
+ <% end %>
25
+ </div>
@@ -0,0 +1,14 @@
1
+ module Aeros::Primitives::Sidebar
2
+ class Component < Aeros::ApplicationViewComponent
3
+ renders_many(:items, Aeros::Primitives::Sidebar::Item)
4
+ renders_many(:groups, Aeros::Primitives::Sidebar::Group)
5
+ renders_one(:header, Aeros::Primitives::Sidebar::Header)
6
+ renders_one(:footer, Aeros::Primitives::Sidebar::Footer)
7
+
8
+ examples("Sidebar", description: "Navigation sidebar with groups and items") do |b|
9
+ b.example(:default, title: "Default") do |e|
10
+ e.preview
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Aeros::Primitives::Sidebar
2
+ class Footer < Aeros::ApplicationViewComponent
3
+ erb_template <<~ERB
4
+ <div><%= content %></div>
5
+ ERB
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ module Aeros::Primitives::Sidebar
2
+ class Group < Aeros::ApplicationViewComponent
3
+ option :label
4
+
5
+ renders_many :items, Item
6
+
7
+ erb_template <<~ERB
8
+ <div class="cp-sidebar__group">
9
+ <div class="cp-sidebar__group-label"><%= label %></div>
10
+ <ul class="cp-sidebar__group-menu">
11
+ <% items.each do |item| %>
12
+ <li><%= item %></li>
13
+ <% end %>
14
+ </ul>
15
+ </div>
16
+ ERB
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Aeros::Primitives::Sidebar
2
+ class Header < Aeros::ApplicationViewComponent
3
+ erb_template <<~ERB
4
+ <div><%= content %></div>
5
+ ERB
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Aeros::Primitives::Sidebar
2
+ class Item < Aeros::ApplicationViewComponent
3
+ option :label
4
+ option :href
5
+ option :icon, optional: true
6
+ option :active, default: proc { false }
7
+
8
+ def item_classes
9
+ ["cp-sidebar__item", active ? "cp-sidebar__item--active" : nil, css].compact.join(" ")
10
+ end
11
+
12
+ erb_template <<~ERB
13
+ <%= link_to(href, class: item_classes) do %>
14
+ <%= lucide_icon(icon) if icon %>
15
+ <span><%= label %></span>
16
+ <% end %>
17
+ ERB
18
+ end
19
+ end
@@ -0,0 +1,95 @@
1
+ /* Sidebar component styles */
2
+ .cp-sidebar {
3
+ width: 100%;
4
+ height: 100vh;
5
+ display: flex;
6
+ flex-direction: column;
7
+ overflow: hidden;
8
+ background-color: var(--ui-sidebar-bg, #fafafa);
9
+ color: var(--ui-sidebar-fg, #1a1a1a);
10
+ border-right: 1px solid var(--ui-sidebar-border, #e5e5e5);
11
+
12
+ &__header {
13
+ flex-shrink: 0;
14
+ }
15
+
16
+ &__nav {
17
+ flex: 1;
18
+ overflow-y: auto;
19
+ padding: 0 0.5rem;
20
+ }
21
+
22
+ &__footer {
23
+ flex-shrink: 0;
24
+ padding: 1rem;
25
+ border-top: 1px solid var(--ui-sidebar-border, #e5e5e5);
26
+ font-size: 0.75rem;
27
+ color: var(--ui-muted-color, #737373);
28
+ }
29
+
30
+ &__menu {
31
+ display: flex;
32
+ width: 100%;
33
+ min-width: 0;
34
+ flex-direction: column;
35
+ gap: 0.25rem;
36
+ }
37
+
38
+ &__group {
39
+ display: flex;
40
+ width: 100%;
41
+ min-width: 0;
42
+ flex-direction: column;
43
+ padding: 0.25rem 0;
44
+ }
45
+
46
+ &__group-label {
47
+ color: var(--ui-muted-color, #737373);
48
+ height: 2rem;
49
+ display: flex;
50
+ align-items: center;
51
+ padding: 0 0.5rem;
52
+ font-size: 0.75rem;
53
+ font-weight: 500;
54
+ text-transform: uppercase;
55
+ letter-spacing: 0.05em;
56
+ }
57
+
58
+ &__group-menu {
59
+ display: flex;
60
+ width: 100%;
61
+ min-width: 0;
62
+ flex-direction: column;
63
+ gap: 0.25rem;
64
+ }
65
+
66
+ &__item {
67
+ display: flex;
68
+ width: 100%;
69
+ align-items: center;
70
+ gap: 0.5rem;
71
+ border-radius: var(--ui-input-radius, 0.375rem);
72
+ padding: 0.5rem;
73
+ text-align: left;
74
+ font-size: 0.875rem;
75
+ color: var(--ui-sidebar-fg, #1a1a1a);
76
+ transition:
77
+ background-color 0.15s ease,
78
+ color 0.15s ease;
79
+
80
+ &:hover {
81
+ background-color: var(--ui-sidebar-hover, #f0f0f0);
82
+ }
83
+
84
+ & svg {
85
+ width: 1rem;
86
+ height: 1rem;
87
+ flex-shrink: 0;
88
+ }
89
+
90
+ &--active {
91
+ background-color: var(--ui-sidebar-active, #e5e5e5);
92
+ font-weight: 500;
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,36 @@
1
+ module Aeros::Primitives::Spinner
2
+ class Component < ::Aeros::ApplicationViewComponent
3
+ prop :size, description: "Spinner size", values: [:sm, :default, :lg], default: -> { :default }
4
+ prop :variant, description: "Spinner color variant", values: [:default, :white], default: -> { :default }
5
+
6
+ examples("Spinner", description: "Loading indicator") do |b|
7
+ b.example(:default, title: "Default") do |e|
8
+ e.preview
9
+ end
10
+
11
+ b.example(:sizes, title: "Sizes") do |e|
12
+ e.preview size: :sm
13
+ e.preview size: :default
14
+ e.preview size: :lg
15
+ end
16
+
17
+ b.example(:variants, title: "Variants") do |e|
18
+ e.preview variant: :default
19
+ e.preview variant: :white
20
+ end
21
+ end
22
+
23
+ def classes
24
+ [
25
+ class_for("base"),
26
+ class_for(size.to_s),
27
+ class_for(variant.to_s),
28
+ css
29
+ ].compact.join(" ")
30
+ end
31
+
32
+ erb_template <<~ERB
33
+ <span class="<%= classes %>"></span>
34
+ ERB
35
+ end
36
+ end
@@ -0,0 +1,81 @@
1
+ /* Spinner component styles */
2
+ .cp-spinner {
3
+ position: relative;
4
+ inset: 0;
5
+ padding-left: 0.5rem;
6
+ margin-right: 0;
7
+ width: 1.25rem;
8
+ height: 1.25rem;
9
+
10
+ &::before {
11
+ content: "";
12
+ box-sizing: border-box;
13
+ position: absolute;
14
+ top: 50%;
15
+ left: 50%;
16
+ width: 1.25rem;
17
+ height: 1.25rem;
18
+ margin-top: -0.625rem;
19
+ margin-left: -0.625rem;
20
+ border-radius: 9999px;
21
+ border-width: 2px;
22
+ border-style: solid;
23
+ animation: spin 1s linear infinite;
24
+ }
25
+
26
+ /* Sizes */
27
+ &--xs::before {
28
+ width: 0.75rem;
29
+ height: 0.75rem;
30
+ margin-top: -0.375rem;
31
+ margin-left: -0.375rem;
32
+ }
33
+
34
+ &--sm::before {
35
+ width: 1rem;
36
+ height: 1rem;
37
+ margin-top: -0.5rem;
38
+ margin-left: -0.5rem;
39
+ }
40
+
41
+ &--lg::before {
42
+ width: 1.5rem;
43
+ height: 1.5rem;
44
+ margin-top: -0.75rem;
45
+ margin-left: -0.75rem;
46
+ }
47
+
48
+ &--xl::before {
49
+ width: 2rem;
50
+ height: 2rem;
51
+ margin-top: -1rem;
52
+ margin-left: -1rem;
53
+ }
54
+
55
+ /* Variants */
56
+ &--white::before {
57
+ border-color: rgb(255 255 255 / 0.5);
58
+ border-top-color: white;
59
+ }
60
+
61
+ &--default::before {
62
+ border-color: rgb(107 114 128 / 0.5);
63
+ border-top-color: rgb(107 114 128);
64
+ }
65
+
66
+ &--primary::before {
67
+ border-color: rgb(from var(--ui-button-bg, #475569) r g b / 0.5);
68
+ border-top-color: var(--ui-button-bg, #475569);
69
+ }
70
+
71
+ &--black::before {
72
+ border-color: rgb(0 0 0 / 0.5);
73
+ border-top-color: black;
74
+ }
75
+ }
76
+
77
+ @keyframes spin {
78
+ to {
79
+ transform: rotate(360deg);
80
+ }
81
+ }
@@ -0,0 +1,7 @@
1
+ module Aeros::Primitives::Table
2
+ class Cell < Aeros::ApplicationViewComponent
3
+ erb_template <<~ERB
4
+ <td class="cp-table__td <%= css %>"><%= content %></td>
5
+ ERB
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Aeros::Primitives::Table
2
+ class Column < Aeros::ApplicationViewComponent
3
+ erb_template <<~ERB
4
+ <th scope="col" class="cp-table__th <%= css %>"><%= content %></th>
5
+ ERB
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ <div class="cp-table">
2
+ <table<%= " id=\"#{id}\"" if id %>>
3
+ <%= header if header? %>
4
+ <tbody>
5
+ <% rows.each do |row| %><%= row %><% end %>
6
+ </tbody>
7
+ </table>
8
+ </div>
@@ -0,0 +1,14 @@
1
+ module Aeros::Primitives::Table
2
+ class Component < ::Aeros::ApplicationViewComponent
3
+ prop :id, description: "HTML id attribute", optional: true
4
+
5
+ renders_one :header, Aeros::Primitives::Table::Header
6
+ renders_many :rows, Aeros::Primitives::Table::Row
7
+
8
+ examples("Table", description: "Data table with header and rows") do |b|
9
+ b.example(:default, title: "Default") do |e|
10
+ e.preview
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Aeros::Primitives::Table
2
+ class Header < Aeros::ApplicationViewComponent
3
+ renders_many :columns, Aeros::Primitives::Table::Column
4
+
5
+ erb_template <<~ERB
6
+ <thead class="cp-table__head">
7
+ <tr>
8
+ <% columns.each do |column| %><%= column %><% end %>
9
+ </tr>
10
+ </thead>
11
+ ERB
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Aeros::Primitives::Table
2
+ class Row < Aeros::ApplicationViewComponent
3
+ renders_many :cells, Aeros::Primitives::Table::Cell
4
+
5
+ erb_template <<~ERB
6
+ <tr class="cp-table__tr <%= css %>">
7
+ <% cells.each do |cell| %><%= cell %><% end %>
8
+ </tr>
9
+ ERB
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ .cp-table {
2
+ overflow-x: auto;
3
+
4
+ & table {
5
+ width: 100%;
6
+ border-collapse: collapse;
7
+ }
8
+
9
+ &__head {
10
+ background-color: var(--ui-area-bg);
11
+ }
12
+
13
+ &__th {
14
+ padding: 0.75rem 1rem;
15
+ text-align: left;
16
+ font-size: 0.75rem;
17
+ font-weight: 500;
18
+ color: var(--ui-muted-color);
19
+ text-transform: uppercase;
20
+ letter-spacing: 0.05em;
21
+ }
22
+
23
+ &__tr {
24
+ border-bottom: 1px solid var(--ui-card-border);
25
+ }
26
+
27
+ &__td {
28
+ padding: 0.75rem 1rem;
29
+ font-size: 0.875rem;
30
+ color: var(--ui-foreground);
31
+
32
+ & code {
33
+ background: var(--ui-area-bg);
34
+ padding: 0.125rem 0.375rem;
35
+ border-radius: 0.25rem;
36
+ font-size: 0.8125rem;
37
+ }
38
+ }
39
+ }
@@ -1,4 +1,15 @@
1
1
  module Aeros
2
2
  class ApplicationController < ActionController::Base
3
+ include Aeros::ApplicationHelper
4
+
5
+ helper_method :current_theme, :current_mode
6
+
7
+ def current_theme
8
+ session[:theme] || "slate"
9
+ end
10
+
11
+ def current_mode
12
+ session[:mode] || "light"
13
+ end
3
14
  end
4
15
  end
@@ -1,4 +1,40 @@
1
1
  module Aeros
2
2
  class ShowcaseController < ApplicationController
3
+ helper_method :primitives, :blocks
4
+
5
+ def index
6
+ page("showcase/index")
7
+ end
8
+
9
+ def show
10
+ component_class = resolve_component(params[:namespace], params[:id])
11
+ if component_class
12
+ page("showcase/show", component_class: component_class)
13
+ else
14
+ page("showcase/placeholder", namespace: params[:namespace], id: params[:id])
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def resolve_component(namespace, id)
21
+ ns = namespace.to_s.camelize
22
+ name = id.to_s.camelize
23
+ "Aeros::#{ns}::#{name}::Component".constantize
24
+ rescue NameError, NoMethodError
25
+ nil
26
+ end
27
+
28
+ def components_path
29
+ Aeros::Engine.root.join("app/components/aeros")
30
+ end
31
+
32
+ def primitives
33
+ @primitives ||= Dir.glob(components_path.join("primitives/*/")).map { |p| File.basename(p) }.sort
34
+ end
35
+
36
+ def blocks
37
+ @blocks ||= Dir.glob(components_path.join("blocks/*/")).map { |p| File.basename(p) }.sort
38
+ end
3
39
  end
4
- end
40
+ end
@@ -0,0 +1,10 @@
1
+ module Aeros
2
+ class ThemeController < ApplicationController
3
+ def update
4
+ session[:theme] = params[:theme] if %w[slate zinc].include?(params[:theme])
5
+ session[:mode] = params[:mode] if %w[light dark].include?(params[:mode])
6
+
7
+ redirect_back(fallback_location: root_path, status: :see_other)
8
+ end
9
+ end
10
+ end
@@ -1,16 +1,28 @@
1
1
  module Aeros
2
2
  module ApplicationHelper
3
- def sqema_importmap_tags(entry_point = "application", shim: true)
4
- safe_join [
5
- javascript_inline_importmap_tag(Aeros.importmap.to_json(resolver: self)),
6
- javascript_importmap_module_preload_tags(Aeros.importmap),
7
- javascript_import_module_tag(entry_point)
8
- ].compact, "\n"
3
+ def page(name, *args, **kwargs, &block)
4
+ component = "Aeros::Pages::#{name.split("/").map(&:camelize).join("::")}::Component".constantize
5
+ render(component.new(*args, **kwargs), &block)
9
6
  end
10
7
 
11
8
  def ui(name, *args, **kwargs, &block)
12
- component = "Aeros::#{name.to_s.camelize}::Component".constantize
9
+ class_name = name.to_s.tr("-", "_").camelize
10
+ component = "Aeros::Primitives::#{class_name}::Component".constantize
13
11
  render(component.new(*args, **kwargs), &block)
14
12
  end
13
+
14
+ def block(name, *args, **kwargs, &blk)
15
+ class_name = name.to_s.tr("-", "_").camelize
16
+ component = "Aeros::Blocks::#{class_name}::Component".constantize
17
+ render(component.new(*args, **kwargs), &blk)
18
+ end
19
+
20
+ # Output theme configuration as inline CSS in the aeros-config layer
21
+ def aeros_theme_tag
22
+ css = Aeros.configuration.theme_css
23
+ return "".html_safe if css.empty?
24
+
25
+ "<style>#{css}</style>".html_safe
26
+ end
15
27
  end
16
28
  end
@@ -1,20 +1,55 @@
1
1
  <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Aeros</title>
5
- <%= csrf_meta_tags %>
6
- <%= csp_meta_tag %>
2
+ <html data-theme="<%= current_theme %>" data-mode="<%= current_mode %>">
3
+ <head>
4
+ <title>Aeros</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <%= yield :head %>
8
+ <%= stylesheet_link_tag "aeros/application", media: "all" %>
9
+ <%= javascript_importmap_tags "aeros/application", importmap: Aeros.importmap %>
10
+ </head>
11
+ <body>
12
+ <%= ui("layouts/app") do |layout| %>
13
+ <% layout.with_sidebar(style: { width: "240px" }) do %>
14
+ <%= ui("sidebar") do |s| %>
15
+ <% s.with_header do %>
16
+ <a href="#" class="cp-layout-app__logo">Aeros</a>
17
+ <% end %>
7
18
 
8
- <%= yield :head %>
19
+ <% s.with_group(label: "Primitives") do |g| %>
20
+ <% primitives.each do |name| %>
21
+ <% g.with_item(label: name.titleize, href: showcase_component_path("primitives", name)) %>
22
+ <% end %>
23
+ <% end %>
9
24
 
10
- <script src="https://cdn.jsdelivr.net/npm/@tailwindplus/elements@1" type="module"></script>
11
- <%= stylesheet_link_tag "aeros/application", media: "all" %>
12
- <%= stylesheet_link_tag "aeros/tailwind", media: "all" %>
13
- <%= javascript_importmap_tags "aeros/application", importmap: Aeros.importmap %>
14
- </head>
15
- <body>
25
+ <% s.with_group(label: "Blocks") do |g| %>
26
+ <% blocks.each do |name| %>
27
+ <% g.with_item(label: name.titleize, href: showcase_component_path("blocks", name)) %>
28
+ <% end %>
29
+ <% end %>
16
30
 
17
- <%= yield %>
31
+ <% s.with_footer do %>
32
+ <span>v0.1.0</span>
33
+ <% end %>
34
+ <% end %>
35
+ <% end %>
18
36
 
19
- </body>
37
+ <%= yield %>
38
+ <% end %>
39
+
40
+ <div class="cg-theme-toggle">
41
+ <%= ui("dropdown", placement: :top, strategy: :fixed) do |d| %>
42
+ <% d.with_trigger do %>
43
+ <%= ui("button", icon: "palette", label: "#{current_theme.titleize} (#{current_mode.titleize})", variant: :outline, css: "text-xs") %>
44
+ <% end %>
45
+ <% d.with_label do %>Palette<% end %>
46
+ <% d.with_item(href: theme_path(theme: "slate", mode: current_mode), method: :patch, form_data: { turbo: false }) do %>Slate<% end %>
47
+ <% d.with_item(href: theme_path(theme: "zinc", mode: current_mode), method: :patch, form_data: { turbo: false }) do %>Zinc<% end %>
48
+ <% d.with_separator %>
49
+ <% d.with_label do %>Mode<% end %>
50
+ <% d.with_item(href: theme_path(theme: current_theme, mode: "light"), method: :patch, form_data: { turbo: false }) do %>Light<% end %>
51
+ <% d.with_item(href: theme_path(theme: current_theme, mode: "dark"), method: :patch, form_data: { turbo: false }) do %>Dark<% end %>
52
+ <% end %>
53
+ </div>
54
+ </body>
20
55
  </html>
data/config/importmap.rb CHANGED
@@ -3,6 +3,11 @@ pin "aeros/application"
3
3
  pin "@hotwired/stimulus", to: "stimulus.min.js"
4
4
  pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
5
5
 
6
+ # Floating UI
7
+ pin "@floating-ui/core", to: "https://cdn.jsdelivr.net/npm/@floating-ui/core@1.6.9/+esm"
8
+ pin "@floating-ui/utils", to: "https://cdn.jsdelivr.net/npm/@floating-ui/utils@0.2.9/+esm"
9
+ pin "@floating-ui/dom", to: "https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.6.13/+esm"
10
+
6
11
  pin_all_from(
7
12
  Aeros::Engine.root.join("app/javascript/aeros/controllers"),
8
13
  under: "aeros/controllers",
@@ -12,4 +17,4 @@ pin_all_from(
12
17
  Aeros::Engine.root.join("app/components/aeros"),
13
18
  under: "aeros/components",
14
19
  to: "aeros"
15
- )
20
+ )
data/config/routes.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  Aeros::Engine.routes.draw do
2
+ get("/showcase/:namespace/:id", to: "showcase#show", as: :showcase_component)
3
+ patch("/theme", to: "theme#update", as: :theme)
2
4
  root(to: "showcase#index")
3
5
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aeros
4
+ class Configuration
5
+ attr_reader :theme_overrides
6
+
7
+ def initialize
8
+ @theme_overrides = {}
9
+ end
10
+
11
+ def theme
12
+ yield ThemeBuilder.new(@theme_overrides) if block_given?
13
+ end
14
+
15
+ # Generate CSS for the aeros-config layer
16
+ def theme_css
17
+ return "" if @theme_overrides.empty?
18
+
19
+ vars = @theme_overrides.map { |k, v| "#{k}:#{v}" }.join(";")
20
+ "@layer aeros-config{:root{#{vars}}}"
21
+ end
22
+
23
+ class ThemeBuilder
24
+ def initialize(overrides)
25
+ @overrides = overrides
26
+ end
27
+
28
+ # Allow setting any --ui-* variable
29
+ def method_missing(name, value = nil)
30
+ if value
31
+ # Remove trailing = from setter method name
32
+ var_name = "--ui-#{name.to_s.chomp('=').tr('_', '-')}"
33
+ @overrides[var_name] = value
34
+ end
35
+ end
36
+
37
+ def respond_to_missing?(name, include_private = false)
38
+ true
39
+ end
40
+ end
41
+ end
42
+
43
+ class << self
44
+ def configuration
45
+ @configuration ||= Configuration.new
46
+ end
47
+
48
+ def configure
49
+ yield(configuration)
50
+ end
51
+
52
+ def reset_configuration!
53
+ @configuration = Configuration.new
54
+ end
55
+ end
56
+ end