maquina-components 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +349 -138
- data/app/assets/images/maquina.svg +1 -0
- data/app/assets/stylesheets/alert.css +143 -0
- data/app/assets/stylesheets/badge.css +145 -0
- data/app/assets/stylesheets/breadcrumbs.css +163 -0
- data/app/assets/stylesheets/card.css +128 -0
- data/app/assets/stylesheets/dropdown_menu.css +248 -0
- data/app/assets/stylesheets/empty.css +133 -0
- data/app/assets/stylesheets/form.css +617 -0
- data/app/assets/stylesheets/header.css +61 -0
- data/app/assets/stylesheets/maquina_components.css +143 -64
- data/app/assets/stylesheets/pagination.css +154 -0
- data/app/assets/stylesheets/sidebar.css +477 -0
- data/app/assets/stylesheets/table.css +205 -0
- data/app/assets/stylesheets/toggle_group.css +151 -0
- data/app/assets/tailwind/maquina_components_engine/engine.css +16 -0
- data/app/helpers/maquina_components/breadcrumbs_helper.rb +118 -0
- data/app/helpers/maquina_components/dropdown_menu_helper.rb +249 -0
- data/app/helpers/maquina_components/empty_helper.rb +102 -0
- data/app/helpers/{components → maquina_components}/icons_helper.rb +40 -3
- data/app/helpers/maquina_components/pagination_helper.rb +153 -0
- data/app/helpers/maquina_components/sidebar_helper.rb +63 -0
- data/app/helpers/maquina_components/table_helper.rb +144 -0
- data/app/helpers/maquina_components/toggle_group_helper.rb +172 -0
- data/app/javascript/controllers/breadcrumb_controller.js +71 -0
- data/app/javascript/controllers/dropdown_menu_controller.js +203 -0
- data/app/javascript/controllers/menu_button_controller.js +59 -0
- data/app/javascript/controllers/sidebar_controller.js +316 -0
- data/app/javascript/controllers/sidebar_trigger_controller.js +32 -0
- data/app/javascript/controllers/toggle_group_controller.js +178 -0
- data/app/views/components/_alert.html.erb +11 -10
- data/app/views/components/_badge.html.erb +10 -0
- data/app/views/components/_breadcrumbs.html.erb +16 -0
- data/app/views/components/_card.html.erb +4 -8
- data/app/views/components/_dropdown.html.erb +25 -0
- data/app/views/components/_dropdown_menu.html.erb +9 -0
- data/app/views/components/_empty.html.erb +10 -0
- data/app/views/components/_header.html.erb +8 -0
- data/app/views/components/_menu_button.html.erb +44 -0
- data/app/views/components/_pagination.html.erb +12 -33
- data/app/views/components/_separator.html.erb +11 -0
- data/app/views/components/_sidebar.html.erb +30 -20
- data/app/views/components/_simple_table.html.erb +49 -0
- data/app/views/components/_table.html.erb +21 -0
- data/app/views/components/_toggle_group.html.erb +24 -0
- data/app/views/components/alert/_description.html.erb +6 -0
- data/app/views/components/alert/_title.html.erb +6 -0
- data/app/views/components/breadcrumbs/_ellipsis.html.erb +9 -0
- data/app/views/components/breadcrumbs/_item.html.erb +8 -0
- data/app/views/components/breadcrumbs/_link.html.erb +8 -0
- data/app/views/components/breadcrumbs/_list.html.erb +8 -0
- data/app/views/components/breadcrumbs/_page.html.erb +8 -0
- data/app/views/components/breadcrumbs/_separator.html.erb +17 -0
- data/app/views/components/card/_action.html.erb +6 -0
- data/app/views/components/card/_content.html.erb +9 -0
- data/app/views/components/card/_description.html.erb +6 -0
- data/app/views/components/card/_footer.html.erb +17 -0
- data/app/views/components/card/_header.html.erb +9 -0
- data/app/views/components/card/_title.html.erb +9 -0
- data/app/views/components/dropdown_menu/_content.html.erb +20 -0
- data/app/views/components/dropdown_menu/_group.html.erb +12 -0
- data/app/views/components/dropdown_menu/_item.html.erb +29 -0
- data/app/views/components/dropdown_menu/_label.html.erb +13 -0
- data/app/views/components/dropdown_menu/_separator.html.erb +11 -0
- data/app/views/components/dropdown_menu/_shortcut.html.erb +12 -0
- data/app/views/components/dropdown_menu/_trigger.html.erb +24 -0
- data/app/views/components/empty/_content.html.erb +8 -0
- data/app/views/components/empty/_description.html.erb +12 -0
- data/app/views/components/empty/_header.html.erb +8 -0
- data/app/views/components/empty/_media.html.erb +13 -0
- data/app/views/components/empty/_title.html.erb +12 -0
- data/app/views/components/pagination/_content.html.erb +8 -0
- data/app/views/components/pagination/_ellipsis.html.erb +28 -0
- data/app/views/components/pagination/_item.html.erb +8 -0
- data/app/views/components/pagination/_link.html.erb +23 -0
- data/app/views/components/pagination/_next.html.erb +57 -0
- data/app/views/components/pagination/_previous.html.erb +57 -0
- data/app/views/components/sidebar/_content.html.erb +8 -0
- data/app/views/components/sidebar/_footer.html.erb +8 -0
- data/app/views/components/sidebar/_group.html.erb +12 -0
- data/app/views/components/sidebar/_header.html.erb +8 -0
- data/app/views/components/sidebar/_inset.html.erb +8 -0
- data/app/views/components/sidebar/_menu.html.erb +8 -0
- data/app/views/components/sidebar/_menu_button.html.erb +14 -0
- data/app/views/components/sidebar/_menu_item.html.erb +7 -0
- data/app/views/components/sidebar/_menu_link.html.erb +32 -0
- data/app/views/components/sidebar/_provider.html.erb +16 -0
- data/app/views/components/sidebar/_trigger.html.erb +12 -0
- data/app/views/components/stats/_stats_card.html.erb +100 -0
- data/app/views/components/stats/_stats_grid.html.erb +38 -0
- data/app/views/components/table/_body.html.erb +5 -0
- data/app/views/components/table/_caption.html.erb +5 -0
- data/app/views/components/table/_cell.html.erb +5 -0
- data/app/views/components/table/_footer.html.erb +5 -0
- data/app/views/components/table/_head.html.erb +8 -0
- data/app/views/components/table/_header.html.erb +8 -0
- data/app/views/components/table/_row.html.erb +8 -0
- data/app/views/components/toggle_group/_item.html.erb +19 -0
- data/config/importmap.rb +1 -0
- data/lib/generators/maquina_components/install/USAGE +39 -0
- data/lib/generators/maquina_components/install/install_generator.rb +123 -0
- data/lib/generators/maquina_components/install/templates/maquina_components_helper.rb.tt +68 -0
- data/lib/generators/maquina_components/install/templates/theme.css.tt +179 -0
- data/lib/maquina_components/engine.rb +10 -0
- data/lib/maquina_components/version.rb +1 -1
- metadata +116 -12
- data/app/helpers/components/pagination_helper.rb +0 -15
- data/app/views/components/_card_content.html.erb +0 -5
- data/app/views/components/_card_header.html.erb +0 -8
- data/app/views/components/_sidebar_content.html.erb +0 -8
- data/app/views/components/_sidebar_group.html.erb +0 -42
- data/app/views/components/_sidebar_header.html.erb +0 -3
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<%# locals: (title:, value:, icon: nil, icon_class: "", subtitle: nil, value_class: "", container_class: "") -%>
|
|
2
|
+
|
|
3
|
+
<div
|
|
4
|
+
class="<%= class_names("bg-card p-4 rounded-lg shadow-sm border border-border", container_class) %>"
|
|
5
|
+
>
|
|
6
|
+
<div class="flex items-center justify-between">
|
|
7
|
+
<div>
|
|
8
|
+
<p class="text-sm text-muted-foreground"><%= title %></p>
|
|
9
|
+
<p
|
|
10
|
+
class="<%= class_names("text-2xl font-bold", value_class.presence || "text-foreground") %>"
|
|
11
|
+
>
|
|
12
|
+
<%= value %>
|
|
13
|
+
</p>
|
|
14
|
+
<% if subtitle.present? %>
|
|
15
|
+
<p class="text-xs text-muted-foreground mt-1"><%= subtitle %></p>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
<% if icon.present? %>
|
|
19
|
+
<div class="<%= icon_class.presence || "text-muted-foreground" %>">
|
|
20
|
+
<% case icon %>
|
|
21
|
+
<% when "message-square" %>
|
|
22
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
23
|
+
<path
|
|
24
|
+
stroke-linecap="round"
|
|
25
|
+
stroke-linejoin="round"
|
|
26
|
+
stroke-width="2"
|
|
27
|
+
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
|
|
28
|
+
/>
|
|
29
|
+
</svg>
|
|
30
|
+
<% when "arrow-up" %>
|
|
31
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
32
|
+
<path
|
|
33
|
+
stroke-linecap="round"
|
|
34
|
+
stroke-linejoin="round"
|
|
35
|
+
stroke-width="2"
|
|
36
|
+
d="M7 17L17 7M17 7H7M17 7V17"
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
<% when "arrow-down" %>
|
|
40
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
41
|
+
<path
|
|
42
|
+
stroke-linecap="round"
|
|
43
|
+
stroke-linejoin="round"
|
|
44
|
+
stroke-width="2"
|
|
45
|
+
d="M17 7L7 17M7 17H17M7 17V7"
|
|
46
|
+
/>
|
|
47
|
+
</svg>
|
|
48
|
+
<% when "check-circle" %>
|
|
49
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
50
|
+
<path
|
|
51
|
+
stroke-linecap="round"
|
|
52
|
+
stroke-linejoin="round"
|
|
53
|
+
stroke-width="2"
|
|
54
|
+
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
55
|
+
/>
|
|
56
|
+
</svg>
|
|
57
|
+
<% when "lightning-bolt" %>
|
|
58
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
59
|
+
<path
|
|
60
|
+
stroke-linecap="round"
|
|
61
|
+
stroke-linejoin="round"
|
|
62
|
+
stroke-width="2"
|
|
63
|
+
d="M13 10V3L4 14h7v7l9-11h-7z"
|
|
64
|
+
/>
|
|
65
|
+
</svg>
|
|
66
|
+
<% when "exclamation-circle" %>
|
|
67
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
68
|
+
<path
|
|
69
|
+
stroke-linecap="round"
|
|
70
|
+
stroke-linejoin="round"
|
|
71
|
+
stroke-width="2"
|
|
72
|
+
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
73
|
+
/>
|
|
74
|
+
</svg>
|
|
75
|
+
<% when "clipboard-list" %>
|
|
76
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
77
|
+
<path
|
|
78
|
+
stroke-linecap="round"
|
|
79
|
+
stroke-linejoin="round"
|
|
80
|
+
stroke-width="2"
|
|
81
|
+
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
|
82
|
+
/>
|
|
83
|
+
</svg>
|
|
84
|
+
<% when "chart-bar" %>
|
|
85
|
+
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
86
|
+
<path
|
|
87
|
+
stroke-linecap="round"
|
|
88
|
+
stroke-linejoin="round"
|
|
89
|
+
stroke-width="2"
|
|
90
|
+
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
|
91
|
+
/>
|
|
92
|
+
</svg>
|
|
93
|
+
<% else %>
|
|
94
|
+
<%# Allow custom SVG or icon HTML to be passed %>
|
|
95
|
+
<%= icon %>
|
|
96
|
+
<% end %>
|
|
97
|
+
</div>
|
|
98
|
+
<% end %>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<%# locals: (cards: [], columns: 3, container_class: "", action: nil, action_position: "end") -%>
|
|
2
|
+
|
|
3
|
+
<div
|
|
4
|
+
class="<%= class_names("flex flex-col lg:flex-row lg:items-center gap-4": action.present?) %>"
|
|
5
|
+
>
|
|
6
|
+
<% if action.present? && action_position == "start" %>
|
|
7
|
+
<div class="flex justify-center lg:justify-start">
|
|
8
|
+
<%= action %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
class="<%= class_names(
|
|
14
|
+
"grid gap-4",
|
|
15
|
+
"grid-cols-1",
|
|
16
|
+
"sm:grid-cols-#{columns}",
|
|
17
|
+
container_class,
|
|
18
|
+
"flex-1": action.present?
|
|
19
|
+
) %>"
|
|
20
|
+
>
|
|
21
|
+
<% cards.each do |card| %>
|
|
22
|
+
<%= render "components/stats_card",
|
|
23
|
+
title: card[:title],
|
|
24
|
+
value: card[:value],
|
|
25
|
+
icon: card[:icon],
|
|
26
|
+
icon_class: card[:icon_class] || "",
|
|
27
|
+
subtitle: card[:subtitle],
|
|
28
|
+
value_class: card[:value_class] || "",
|
|
29
|
+
container_class: card[:container_class] || "" %>
|
|
30
|
+
<% end %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<% if action.present? && action_position == "end" %>
|
|
34
|
+
<div class="flex justify-center lg:justify-end">
|
|
35
|
+
<%= action %>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", **html_options) %>
|
|
2
|
+
<% merged_data = (html_options.delete(:data) || {}).merge(table_part: :caption) %>
|
|
3
|
+
<%= content_tag :caption, class: css_classes.presence, data: merged_data, **html_options do %>
|
|
4
|
+
<%= yield if block_given? %>
|
|
5
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", scope: "col", **html_options) %>
|
|
2
|
+
<%
|
|
3
|
+
merged_data = (html_options.delete(:data) || {}).merge(table_part: :head)
|
|
4
|
+
html_options[:scope] = scope if scope
|
|
5
|
+
%>
|
|
6
|
+
<%= content_tag :th, class: css_classes.presence, data: merged_data, **html_options do %>
|
|
7
|
+
<%= yield if block_given? %>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", sticky: false, **html_options) %>
|
|
2
|
+
<%
|
|
3
|
+
merged_data = (html_options.delete(:data) || {}).merge(table_part: :header)
|
|
4
|
+
merged_data[:sticky] = "true" if sticky
|
|
5
|
+
%>
|
|
6
|
+
<%= content_tag :thead, class: css_classes.presence, data: merged_data, **html_options do %>
|
|
7
|
+
<%= yield %>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", selected: false, **html_options) %>
|
|
2
|
+
<%
|
|
3
|
+
merged_data = (html_options.delete(:data) || {}).merge(table_part: :row)
|
|
4
|
+
merged_data[:state] = :selected if selected
|
|
5
|
+
%>
|
|
6
|
+
<%= content_tag :tr, class: css_classes.presence, data: merged_data, **html_options do %>
|
|
7
|
+
<%= yield %>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<%# locals: (value:, pressed: false, disabled: false, aria_label: nil, css_classes: "", **html_options) %>
|
|
2
|
+
<% merged_data = (html_options.delete(:data) || {}).merge(
|
|
3
|
+
"toggle-group-part": "item",
|
|
4
|
+
"toggle-group-target": "item",
|
|
5
|
+
value: value,
|
|
6
|
+
state: pressed ? "on" : "off",
|
|
7
|
+
action: "click->toggle-group#toggle keydown->toggle-group#handleKeydown"
|
|
8
|
+
) %>
|
|
9
|
+
|
|
10
|
+
<%= content_tag :button,
|
|
11
|
+
type: "button",
|
|
12
|
+
class: css_classes.presence,
|
|
13
|
+
data: merged_data,
|
|
14
|
+
disabled: disabled,
|
|
15
|
+
"aria-pressed": pressed,
|
|
16
|
+
"aria-label": aria_label,
|
|
17
|
+
**html_options do %>
|
|
18
|
+
<%= yield %>
|
|
19
|
+
<% end %>
|
data/config/importmap.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pin_all_from MaquinaComponents::Engine.root.join("app/javascript/controllers"), under: "controllers"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Install maquina_components into your Rails application.
|
|
3
|
+
|
|
4
|
+
This generator will:
|
|
5
|
+
- Add the engine CSS import to your Tailwind application.css
|
|
6
|
+
- Add theme variables (shadcn/ui convention) for customization
|
|
7
|
+
- Create a helper file for icon overrides and customizations
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
bin/rails generate maquina_components:install
|
|
11
|
+
|
|
12
|
+
This will:
|
|
13
|
+
insert @import "../builds/tailwind/maquina_components_engine.css";
|
|
14
|
+
append Theme variables to app/assets/tailwind/application.css
|
|
15
|
+
create app/helpers/maquina_components_helper.rb
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--skip-theme Skip adding theme variables (if you already have them)
|
|
19
|
+
--skip-helper Skip creating the helper file
|
|
20
|
+
|
|
21
|
+
Prerequisites:
|
|
22
|
+
- tailwindcss-rails gem installed
|
|
23
|
+
- app/assets/tailwind/application.css exists
|
|
24
|
+
|
|
25
|
+
After Installation:
|
|
26
|
+
1. Customize theme variables in app/assets/tailwind/application.css
|
|
27
|
+
2. Override icon helper in app/helpers/maquina_components_helper.rb
|
|
28
|
+
3. Start using components:
|
|
29
|
+
|
|
30
|
+
<%%= render "components/card" do %>
|
|
31
|
+
<%%= render "components/card/header" do %>
|
|
32
|
+
<%%= render "components/card/title", text: "Hello World" %>
|
|
33
|
+
<%% end %>
|
|
34
|
+
<%% end %>
|
|
35
|
+
|
|
36
|
+
4. Use data attributes with form helpers:
|
|
37
|
+
|
|
38
|
+
<%%= f.text_field :email, data: { component: "input" } %>
|
|
39
|
+
<%%= f.submit "Save", data: { component: "button", variant: "primary" } %>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module MaquinaComponents
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
|
9
|
+
|
|
10
|
+
desc "Install maquina_components into your Rails application"
|
|
11
|
+
|
|
12
|
+
class_option :skip_theme, type: :boolean, default: false,
|
|
13
|
+
desc: "Skip adding theme variables to application.css"
|
|
14
|
+
class_option :skip_helper, type: :boolean, default: false,
|
|
15
|
+
desc: "Skip creating the maquina_components helper"
|
|
16
|
+
|
|
17
|
+
def check_tailwindcss_rails
|
|
18
|
+
css_path = "app/assets/tailwind/application.css"
|
|
19
|
+
|
|
20
|
+
unless File.exist?(File.join(destination_root, css_path))
|
|
21
|
+
say_status :warning, "tailwindcss-rails doesn't appear to be installed", :yellow
|
|
22
|
+
say "Please install tailwindcss-rails first:"
|
|
23
|
+
say " bundle add tailwindcss-rails"
|
|
24
|
+
say " rails tailwindcss:install"
|
|
25
|
+
say ""
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_engine_css_import
|
|
30
|
+
css_path = "app/assets/tailwind/application.css"
|
|
31
|
+
full_path = File.join(destination_root, css_path)
|
|
32
|
+
|
|
33
|
+
unless File.exist?(full_path)
|
|
34
|
+
say_status :skip, "#{css_path} not found", :yellow
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
import_line = '@import "../builds/tailwind/maquina_components_engine.css";'
|
|
39
|
+
|
|
40
|
+
if File.read(full_path).include?(import_line)
|
|
41
|
+
say_status :skip, "Engine CSS import already present", :blue
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Insert after @import "tailwindcss"; or @import 'tailwindcss'; line
|
|
46
|
+
inject_into_file css_path, after: /@import\s+["']tailwindcss["'];?\n/ do
|
|
47
|
+
"\n#{import_line}\n"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
say_status :insert, "Added maquina_components engine CSS import", :green
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def add_theme_variables
|
|
54
|
+
return if options[:skip_theme]
|
|
55
|
+
|
|
56
|
+
css_path = "app/assets/tailwind/application.css"
|
|
57
|
+
full_path = File.join(destination_root, css_path)
|
|
58
|
+
|
|
59
|
+
unless File.exist?(full_path)
|
|
60
|
+
say_status :skip, "#{css_path} not found", :yellow
|
|
61
|
+
return
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if File.read(full_path).include?("--color-primary:")
|
|
65
|
+
say_status :skip, "Theme variables already present", :blue
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
theme_content = File.read(File.expand_path("templates/theme.css.tt", __dir__))
|
|
70
|
+
|
|
71
|
+
append_to_file css_path, "\n#{theme_content}"
|
|
72
|
+
|
|
73
|
+
say_status :append, "Added theme variables to application.css", :green
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def create_helper
|
|
77
|
+
return if options[:skip_helper]
|
|
78
|
+
|
|
79
|
+
helper_path = "app/helpers/maquina_components_helper.rb"
|
|
80
|
+
full_path = File.join(destination_root, helper_path)
|
|
81
|
+
|
|
82
|
+
if File.exist?(full_path)
|
|
83
|
+
say_status :skip, "#{helper_path} already exists", :blue
|
|
84
|
+
return
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
template "maquina_components_helper.rb.tt", helper_path
|
|
88
|
+
say_status :create, helper_path, :green
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def show_post_install_message
|
|
92
|
+
say ""
|
|
93
|
+
say "=" * 60
|
|
94
|
+
say " maquina_components installed successfully!", :green
|
|
95
|
+
say "=" * 60
|
|
96
|
+
say ""
|
|
97
|
+
say "Next steps:"
|
|
98
|
+
say ""
|
|
99
|
+
say "1. Customize theme variables in app/assets/tailwind/application.css"
|
|
100
|
+
say " to match your design system."
|
|
101
|
+
say ""
|
|
102
|
+
say "2. Override the icon helper in app/helpers/maquina_components_helper.rb"
|
|
103
|
+
say " to use your own icon system (Heroicons, Lucide, etc.)."
|
|
104
|
+
say ""
|
|
105
|
+
say "3. Start using components in your views:"
|
|
106
|
+
say ""
|
|
107
|
+
say ' <%= render "components/card" do %>'
|
|
108
|
+
say ' <%= render "components/card/header" do %>'
|
|
109
|
+
say ' <%= render "components/card/title", text: "Hello" %>'
|
|
110
|
+
say " <% end %>"
|
|
111
|
+
say " <% end %>"
|
|
112
|
+
say ""
|
|
113
|
+
say "4. For form elements, use data attributes:"
|
|
114
|
+
say ""
|
|
115
|
+
say ' <%= f.text_field :email, data: { component: "input" } %>'
|
|
116
|
+
say ' <%= f.submit "Save", data: { component: "button", variant: "primary" } %>'
|
|
117
|
+
say ""
|
|
118
|
+
say "Documentation: https://github.com/maquina-app/maquina_components"
|
|
119
|
+
say ""
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# MaquinaComponents Helper
|
|
4
|
+
#
|
|
5
|
+
# This helper provides customization hooks for maquina_components.
|
|
6
|
+
# Override methods here to integrate with your application's icon system,
|
|
7
|
+
# sidebar state management, and other customizations.
|
|
8
|
+
#
|
|
9
|
+
# Documentation: https://github.com/maquina-app/maquina_components
|
|
10
|
+
#
|
|
11
|
+
module MaquinaComponentsHelper
|
|
12
|
+
# Icon Override
|
|
13
|
+
#
|
|
14
|
+
# Override this method to use your own icon system (Heroicons, Lucide, etc.)
|
|
15
|
+
# The engine's icon_for helper will call this method first.
|
|
16
|
+
#
|
|
17
|
+
# @param name [Symbol] Icon name (e.g., :check, :chevron_right, :home)
|
|
18
|
+
# @param options [Hash] Options hash with :class, :stroke_width, etc.
|
|
19
|
+
# @return [String, nil] SVG string or nil to fall back to engine's icons
|
|
20
|
+
#
|
|
21
|
+
# @example Using Heroicons
|
|
22
|
+
# def main_icon_svg_for(name)
|
|
23
|
+
# heroicon_tag(name, variant: :outline)
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# @example Using Lucide
|
|
27
|
+
# def main_icon_svg_for(name)
|
|
28
|
+
# lucide_icon(name)
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# @example Using inline SVG files
|
|
32
|
+
# def main_icon_svg_for(name)
|
|
33
|
+
# file_path = Rails.root.join("app/assets/images/icons/#{name}.svg")
|
|
34
|
+
# File.read(file_path) if File.exist?(file_path)
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
def main_icon_svg_for(name)
|
|
38
|
+
# Return nil to use the engine's built-in icons
|
|
39
|
+
# Override this method to use your own icon system
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Sidebar State Helpers
|
|
44
|
+
#
|
|
45
|
+
# These helpers are re-exported from the engine for convenience.
|
|
46
|
+
# You can override them if you need custom cookie names or behavior.
|
|
47
|
+
|
|
48
|
+
# Returns the current sidebar state from cookies
|
|
49
|
+
# @param cookie_name [String] Cookie name (default: "sidebar_state")
|
|
50
|
+
# @return [Symbol] :expanded or :collapsed
|
|
51
|
+
def app_sidebar_state(cookie_name = "sidebar_state")
|
|
52
|
+
sidebar_state(cookie_name)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Check if sidebar is expanded
|
|
56
|
+
# @param cookie_name [String] Cookie name (default: "sidebar_state")
|
|
57
|
+
# @return [Boolean]
|
|
58
|
+
def app_sidebar_open?(cookie_name = "sidebar_state")
|
|
59
|
+
sidebar_open?(cookie_name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Check if sidebar is collapsed
|
|
63
|
+
# @param cookie_name [String] Cookie name (default: "sidebar_state")
|
|
64
|
+
# @return [Boolean]
|
|
65
|
+
def app_sidebar_closed?(cookie_name = "sidebar_state")
|
|
66
|
+
sidebar_closed?(cookie_name)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
maquina_components Theme Variables
|
|
3
|
+
|
|
4
|
+
These CSS variables follow the shadcn/ui theming convention.
|
|
5
|
+
Customize these values to match your design system.
|
|
6
|
+
|
|
7
|
+
Documentation: https://github.com/maquina-app/maquina_components
|
|
8
|
+
========================================================================== */
|
|
9
|
+
|
|
10
|
+
@custom-variant dark (&:is(.dark *));
|
|
11
|
+
|
|
12
|
+
:root {
|
|
13
|
+
/* Layout */
|
|
14
|
+
--header-height: calc(var(--spacing) * 12 + 1px);
|
|
15
|
+
--sidebar-width: calc(var(--spacing) * 72);
|
|
16
|
+
--sidebar-width-icon: 3rem;
|
|
17
|
+
|
|
18
|
+
/* Core Colors */
|
|
19
|
+
--background: oklch(1 0 0);
|
|
20
|
+
--foreground: oklch(0.145 0 0);
|
|
21
|
+
|
|
22
|
+
/* Card */
|
|
23
|
+
--card: oklch(1 0 0);
|
|
24
|
+
--card-foreground: oklch(0.145 0 0);
|
|
25
|
+
|
|
26
|
+
/* Popover */
|
|
27
|
+
--popover: oklch(1 0 0);
|
|
28
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
29
|
+
|
|
30
|
+
/* Primary - Main brand color */
|
|
31
|
+
--primary: oklch(0.645 0.246 16);
|
|
32
|
+
--primary-foreground: oklch(0.969 0.015 12);
|
|
33
|
+
|
|
34
|
+
/* Secondary */
|
|
35
|
+
--secondary: oklch(0.97 0 0);
|
|
36
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
37
|
+
|
|
38
|
+
/* Muted - Subtle backgrounds */
|
|
39
|
+
--muted: oklch(0.97 0 0);
|
|
40
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
41
|
+
|
|
42
|
+
/* Accent - Hover states */
|
|
43
|
+
--accent: oklch(0.97 0 0);
|
|
44
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
45
|
+
|
|
46
|
+
/* Success - Success states */
|
|
47
|
+
--success: oklch(0.92 0.04 168);
|
|
48
|
+
--success-foreground: oklch(0.35 0.08 168);
|
|
49
|
+
|
|
50
|
+
/* Warning - Warning states */
|
|
51
|
+
--warning: oklch(0.93 0.04 55);
|
|
52
|
+
--warning-foreground: oklch(0.4 0.08 50);
|
|
53
|
+
|
|
54
|
+
/* Destructive - Error/danger states */
|
|
55
|
+
--destructive: oklch(0.92 0.05 8);
|
|
56
|
+
--destructive-foreground: oklch(0.4 0.12 8);
|
|
57
|
+
|
|
58
|
+
/* Borders & Inputs */
|
|
59
|
+
--border: oklch(0.922 0 0);
|
|
60
|
+
--input: oklch(0.922 0 0);
|
|
61
|
+
--ring: oklch(0.645 0.246 16);
|
|
62
|
+
|
|
63
|
+
/* Charts (optional) */
|
|
64
|
+
--chart-1: oklch(0.645 0.246 16);
|
|
65
|
+
--chart-2: oklch(0.65 0.09 168);
|
|
66
|
+
--chart-3: oklch(0.72 0.09 55);
|
|
67
|
+
--chart-4: oklch(0.58 0.18 17);
|
|
68
|
+
--chart-5: oklch(0.5 0.13 8);
|
|
69
|
+
|
|
70
|
+
/* Sidebar */
|
|
71
|
+
--sidebar: oklch(0.96 0 0);
|
|
72
|
+
--sidebar-foreground: oklch(0.2 0 0);
|
|
73
|
+
--sidebar-primary: oklch(0.645 0.246 16);
|
|
74
|
+
--sidebar-primary-foreground: oklch(0.969 0.015 12);
|
|
75
|
+
--sidebar-accent: oklch(0.9 0 0);
|
|
76
|
+
--sidebar-accent-foreground: oklch(0.145 0 0);
|
|
77
|
+
--sidebar-border: oklch(0.88 0 0);
|
|
78
|
+
--sidebar-ring: oklch(0.645 0.246 16);
|
|
79
|
+
|
|
80
|
+
/* Dark Mode */
|
|
81
|
+
.dark {
|
|
82
|
+
--background: oklch(0.145 0 0);
|
|
83
|
+
--foreground: oklch(0.985 0 0);
|
|
84
|
+
|
|
85
|
+
--card: oklch(0.205 0 0);
|
|
86
|
+
--card-foreground: oklch(0.985 0 0);
|
|
87
|
+
|
|
88
|
+
--popover: oklch(0.269 0 0);
|
|
89
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
90
|
+
|
|
91
|
+
--primary: oklch(0.712 0.194 13);
|
|
92
|
+
--primary-foreground: oklch(0.15 0.052 13);
|
|
93
|
+
|
|
94
|
+
--secondary: oklch(0.269 0 0);
|
|
95
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
96
|
+
|
|
97
|
+
--muted: oklch(0.269 0 0);
|
|
98
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
99
|
+
|
|
100
|
+
--accent: oklch(0.371 0 0);
|
|
101
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
102
|
+
|
|
103
|
+
--success: oklch(0.32 0.06 168);
|
|
104
|
+
--success-foreground: oklch(0.82 0.06 168);
|
|
105
|
+
|
|
106
|
+
--warning: oklch(0.36 0.06 55);
|
|
107
|
+
--warning-foreground: oklch(0.86 0.06 55);
|
|
108
|
+
|
|
109
|
+
--destructive: oklch(0.34 0.07 8);
|
|
110
|
+
--destructive-foreground: oklch(0.88 0.06 8);
|
|
111
|
+
|
|
112
|
+
--border: oklch(1 0 0 / 10%);
|
|
113
|
+
--input: oklch(1 0 0 / 15%);
|
|
114
|
+
--ring: oklch(0.455 0.188 13);
|
|
115
|
+
|
|
116
|
+
--chart-1: oklch(0.712 0.194 13);
|
|
117
|
+
--chart-2: oklch(0.72 0.09 168);
|
|
118
|
+
--chart-3: oklch(0.78 0.09 55);
|
|
119
|
+
--chart-4: oklch(0.645 0.246 16);
|
|
120
|
+
--chart-5: oklch(0.58 0.13 8);
|
|
121
|
+
|
|
122
|
+
--sidebar: oklch(0.14 0 0);
|
|
123
|
+
--sidebar-foreground: oklch(0.9 0 0);
|
|
124
|
+
--sidebar-primary: oklch(0.712 0.194 13);
|
|
125
|
+
--sidebar-primary-foreground: oklch(0.15 0.052 13);
|
|
126
|
+
--sidebar-accent: oklch(0.22 0 0);
|
|
127
|
+
--sidebar-accent-foreground: oklch(0.95 0 0);
|
|
128
|
+
--sidebar-border: oklch(1 0 0 / 12%);
|
|
129
|
+
--sidebar-ring: oklch(0.455 0.188 13);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Tailwind Theme Bindings
|
|
134
|
+
These make the CSS variables available as Tailwind utilities:
|
|
135
|
+
bg-primary, text-muted-foreground, border-sidebar, etc. */
|
|
136
|
+
@theme {
|
|
137
|
+
--color-background: var(--background);
|
|
138
|
+
--color-foreground: var(--foreground);
|
|
139
|
+
|
|
140
|
+
--color-primary: var(--primary);
|
|
141
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
142
|
+
|
|
143
|
+
--color-muted: var(--muted);
|
|
144
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
145
|
+
|
|
146
|
+
--color-secondary: var(--secondary);
|
|
147
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
148
|
+
|
|
149
|
+
--color-accent: var(--accent);
|
|
150
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
151
|
+
|
|
152
|
+
--color-destructive: var(--destructive);
|
|
153
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
154
|
+
|
|
155
|
+
--color-input: var(--input);
|
|
156
|
+
--color-border: var(--border);
|
|
157
|
+
--color-ring: var(--ring);
|
|
158
|
+
--color-ring-destructive: var(--destructive);
|
|
159
|
+
|
|
160
|
+
--color-card: var(--card);
|
|
161
|
+
--color-card-foreground: var(--card-foreground);
|
|
162
|
+
|
|
163
|
+
--color-popover: var(--popover);
|
|
164
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
165
|
+
|
|
166
|
+
--color-sidebar: var(--sidebar);
|
|
167
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
168
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
169
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
170
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
171
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
172
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
173
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* Global border color */
|
|
177
|
+
* {
|
|
178
|
+
border-color: var(--color-border);
|
|
179
|
+
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
module MaquinaComponents
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
|
+
initializer "maquina-components.importmap", before: "importmap" do |app|
|
|
4
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
|
5
|
+
app.config.importmap.cache_sweepers << root.join("app/javascript")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
initializer "maquin-components.assets" do |app|
|
|
9
|
+
if app.config.respond_to?(:assets)
|
|
10
|
+
app.config.assets.paths << Engine.root.join("app/javascript")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
3
13
|
end
|
|
4
14
|
end
|