solidus_admin 0.0.0 → 0.0.1

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 (122) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +7 -0
  3. data/README.md +31 -0
  4. data/Rakefile +21 -0
  5. data/app/assets/config/solidus_admin_manifest.js +4 -0
  6. data/app/assets/images/solidus_admin/.keep +0 -0
  7. data/app/assets/images/solidus_admin/arrow_down_s_fill_gray_700.svg +3 -0
  8. data/app/assets/images/solidus_admin/arrow_down_s_fill_red_400.svg +3 -0
  9. data/app/assets/images/solidus_admin/arrow_right_up_line.svg +5 -0
  10. data/app/assets/images/solidus_admin/favicon.ico +0 -0
  11. data/app/assets/images/solidus_admin/remixicon.symbol.svg +11 -0
  12. data/app/assets/stylesheets/solidus_admin/application.css +3 -0
  13. data/app/assets/stylesheets/solidus_admin/application.tailwind.css.erb +35 -0
  14. data/app/components/solidus_admin/base_component.rb +42 -0
  15. data/app/components/solidus_admin/feedback/component.html.erb +11 -0
  16. data/app/components/solidus_admin/feedback/component.rb +4 -0
  17. data/app/components/solidus_admin/feedback/component.yml +5 -0
  18. data/app/components/solidus_admin/orders/index/component.html.erb +31 -0
  19. data/app/components/solidus_admin/orders/index/component.rb +118 -0
  20. data/app/components/solidus_admin/orders/index/component.yml +13 -0
  21. data/app/components/solidus_admin/products/index/component.html.erb +30 -0
  22. data/app/components/solidus_admin/products/index/component.rb +126 -0
  23. data/app/components/solidus_admin/products/index/component.yml +13 -0
  24. data/app/components/solidus_admin/products/show/component.html.erb +149 -0
  25. data/app/components/solidus_admin/products/show/component.js +9 -0
  26. data/app/components/solidus_admin/products/show/component.rb +26 -0
  27. data/app/components/solidus_admin/products/show/component.yml +17 -0
  28. data/app/components/solidus_admin/products/status/component.rb +31 -0
  29. data/app/components/solidus_admin/products/status/component.yml +3 -0
  30. data/app/components/solidus_admin/sidebar/account_nav/component.html.erb +67 -0
  31. data/app/components/solidus_admin/sidebar/account_nav/component.rb +15 -0
  32. data/app/components/solidus_admin/sidebar/account_nav/component.yml +3 -0
  33. data/app/components/solidus_admin/sidebar/component.html.erb +39 -0
  34. data/app/components/solidus_admin/sidebar/component.js +14 -0
  35. data/app/components/solidus_admin/sidebar/component.rb +21 -0
  36. data/app/components/solidus_admin/sidebar/component.yml +2 -0
  37. data/app/components/solidus_admin/sidebar/item/component.html.erb +26 -0
  38. data/app/components/solidus_admin/sidebar/item/component.rb +27 -0
  39. data/app/components/solidus_admin/skip_link/component.rb +24 -0
  40. data/app/components/solidus_admin/skip_link/component.yml +2 -0
  41. data/app/components/solidus_admin/ui/badge/component.rb +34 -0
  42. data/app/components/solidus_admin/ui/button/component.rb +101 -0
  43. data/app/components/solidus_admin/ui/forms/checkbox/component.rb +42 -0
  44. data/app/components/solidus_admin/ui/forms/field/component.html.erb +28 -0
  45. data/app/components/solidus_admin/ui/forms/field/component.rb +72 -0
  46. data/app/components/solidus_admin/ui/forms/input/component.js +16 -0
  47. data/app/components/solidus_admin/ui/forms/input/component.rb +99 -0
  48. data/app/components/solidus_admin/ui/forms/switch/component.rb +47 -0
  49. data/app/components/solidus_admin/ui/icon/component.rb +25 -0
  50. data/app/components/solidus_admin/ui/icon/names.txt +2494 -0
  51. data/app/components/solidus_admin/ui/panel/component.html.erb +36 -0
  52. data/app/components/solidus_admin/ui/panel/component.js +14 -0
  53. data/app/components/solidus_admin/ui/panel/component.rb +19 -0
  54. data/app/components/solidus_admin/ui/panel/component.yml +4 -0
  55. data/app/components/solidus_admin/ui/tab/component.rb +43 -0
  56. data/app/components/solidus_admin/ui/table/component.html.erb +170 -0
  57. data/app/components/solidus_admin/ui/table/component.js +118 -0
  58. data/app/components/solidus_admin/ui/table/component.rb +150 -0
  59. data/app/components/solidus_admin/ui/table/component.yml +11 -0
  60. data/app/components/solidus_admin/ui/table/pagination/component.html.erb +28 -0
  61. data/app/components/solidus_admin/ui/table/pagination/component.rb +14 -0
  62. data/app/components/solidus_admin/ui/table/pagination/component.yml +3 -0
  63. data/app/components/solidus_admin/ui/toast/component.html.erb +26 -0
  64. data/app/components/solidus_admin/ui/toast/component.js +17 -0
  65. data/app/components/solidus_admin/ui/toast/component.rb +18 -0
  66. data/app/components/solidus_admin/ui/toast/component.yml +4 -0
  67. data/app/components/solidus_admin/ui/toggletip/component.html.erb +53 -0
  68. data/app/components/solidus_admin/ui/toggletip/component.js +26 -0
  69. data/app/components/solidus_admin/ui/toggletip/component.rb +98 -0
  70. data/app/components/solidus_admin/ui/toggletip/component.yml +2 -0
  71. data/app/controllers/solidus_admin/accounts_controller.rb +11 -0
  72. data/app/controllers/solidus_admin/authentication_adapters/backend.rb +26 -0
  73. data/app/controllers/solidus_admin/base_controller.rb +21 -0
  74. data/app/controllers/solidus_admin/controller_helpers/authentication.rb +31 -0
  75. data/app/controllers/solidus_admin/controller_helpers/authorization.rb +29 -0
  76. data/app/controllers/solidus_admin/controller_helpers/locale.rb +32 -0
  77. data/app/controllers/solidus_admin/orders_controller.rb +21 -0
  78. data/app/controllers/solidus_admin/products_controller.rb +93 -0
  79. data/app/helpers/solidus_admin/components_helper.rb +9 -0
  80. data/app/helpers/solidus_admin/layout_helper.rb +18 -0
  81. data/app/javascript/solidus_admin/application.js +2 -0
  82. data/app/javascript/solidus_admin/controllers/application.js +9 -0
  83. data/app/javascript/solidus_admin/controllers/components.js +35 -0
  84. data/app/javascript/solidus_admin/controllers/hello_controller.js +7 -0
  85. data/app/javascript/solidus_admin/controllers/index.js +14 -0
  86. data/app/javascript/solidus_admin/utils.js +8 -0
  87. data/app/views/layouts/solidus_admin/application.html.erb +30 -0
  88. data/app/views/layouts/solidus_admin/preview.html.erb +10 -0
  89. data/app/views/solidus_admin/.keep +0 -0
  90. data/bin/rails +13 -0
  91. data/config/importmap.rb +13 -0
  92. data/config/locales/main_nav.en.yml +13 -0
  93. data/config/locales/orders.en.yml +4 -0
  94. data/config/locales/products.en.yml +10 -0
  95. data/config/routes.rb +13 -0
  96. data/config/solidus_admin/tailwind.config.js.erb +95 -0
  97. data/docs/customizing_main_navigation.md +42 -0
  98. data/docs/customizing_tailwind.md +78 -0
  99. data/docs/customizing_view_components.md +153 -0
  100. data/lib/generators/solidus_admin/component/USAGE +13 -0
  101. data/lib/generators/solidus_admin/component/component_generator.rb +130 -0
  102. data/lib/generators/solidus_admin/component/templates/component.html.erb.tt +3 -0
  103. data/lib/generators/solidus_admin/component/templates/component.js.tt +14 -0
  104. data/lib/generators/solidus_admin/component/templates/component.rb.tt +14 -0
  105. data/lib/generators/solidus_admin/component/templates/component.yml.tt +4 -0
  106. data/lib/generators/solidus_admin/component/templates/component_preview.rb.tt +15 -0
  107. data/lib/generators/solidus_admin/component/templates/component_preview_overview.html.erb +7 -0
  108. data/lib/generators/solidus_admin/component/templates/component_spec.rb.tt +16 -0
  109. data/lib/generators/solidus_admin/install/install_generator.rb +44 -0
  110. data/lib/generators/solidus_admin/install/templates/config/initializers/solidus_admin.rb +44 -0
  111. data/lib/solidus_admin/configuration.rb +217 -0
  112. data/lib/solidus_admin/engine.rb +67 -0
  113. data/lib/solidus_admin/importmap.rb +26 -0
  114. data/lib/solidus_admin/main_nav_item.rb +97 -0
  115. data/lib/solidus_admin/preview.rb +81 -0
  116. data/lib/solidus_admin/tailwindcss.rb +58 -0
  117. data/lib/solidus_admin/version.rb +5 -0
  118. data/lib/solidus_admin.rb +15 -0
  119. data/lib/tasks/importmap.rake +10 -0
  120. data/lib/tasks/tailwindcss.rake +55 -0
  121. data/solidus_admin.gemspec +35 -0
  122. metadata +255 -18
@@ -0,0 +1,10 @@
1
+ en:
2
+ solidus_admin:
3
+ products:
4
+ title: "Products"
5
+ destroy:
6
+ success: "Products were successfully removed."
7
+ discontinue:
8
+ success: "Products were successfully discontinued."
9
+ activate:
10
+ success: "Products were successfully activated."
data/config/routes.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ SolidusAdmin::Engine.routes.draw do
4
+ resource :account, only: :show
5
+ resources :products, only: [:index, :show, :edit, :update] do
6
+ collection do
7
+ delete :destroy
8
+ put :discontinue
9
+ put :activate
10
+ end
11
+ end
12
+ resources :orders, only: :index
13
+ end
@@ -0,0 +1,95 @@
1
+ const defaultTheme = require('tailwindcss/defaultTheme')
2
+ const plugin = require('tailwindcss/plugin')
3
+
4
+ module.exports = {
5
+ content: [
6
+ <%= SolidusAdmin::Config.tailwind_content.map { "'#{_1}'" }.join(",\n ") %>
7
+ ],
8
+ theme: {
9
+ extend: {
10
+ aria: {
11
+ 'current': 'current="true"',
12
+ },
13
+ fontFamily: {
14
+ sans: ['Inter var', ...defaultTheme.fontFamily.sans],
15
+ },
16
+ colors: {
17
+ transparent: "transparent",
18
+ current: "currentColor",
19
+
20
+ // Primary palette
21
+ solidusRed: "#ef3023",
22
+ black: "#222222",
23
+ graphite: "#c7ccc7",
24
+ graphiteLight: "#d8dad8",
25
+ sand: "#f5f3f0",
26
+ white: "#ffffff",
27
+
28
+ // Secondary palette
29
+ yellow: "#fdc071",
30
+ orange: "#f68050",
31
+ blue: "#2554b1",
32
+ moss: "#2d3925",
33
+ forest: "#096756",
34
+ midnight: "#163449",
35
+ pink: "#f6d7e2",
36
+ plum: "#3a0e31",
37
+ sky: "#cbdff1",
38
+ seafoam: "#c1e0de",
39
+ dune: "#e6bf9b",
40
+
41
+ // Extra colors (not part of the original palette)
42
+ papayaWhip: "#f9e3d9",
43
+
44
+ // UI Red
45
+ red: {
46
+ 100: "#f8d6d3",
47
+ 200: "#f1ada7",
48
+ 300: "#ea8980",
49
+ 400: "#e36054",
50
+ 500: "#dc3728",
51
+ 600: "#b12c20",
52
+ 700: "#862219",
53
+ 800: "#561610",
54
+ 900: "#2b0b08",
55
+ },
56
+
57
+ // Grayscale
58
+ gray: {
59
+ 15: "#fafafa",
60
+ 25: "#f5f5f5",
61
+ 50: "#f0f0f0",
62
+ 100: "#dedede",
63
+ 200: "#cfcfcf",
64
+ 300: "#bababa",
65
+ 400: "#a3a3a3",
66
+ 500: "#737373",
67
+ 600: "#616161",
68
+ 700: "#4a4a4a",
69
+ 800: "#333333",
70
+ },
71
+ },
72
+ borderRadius: {
73
+ sm: '4px',
74
+ },
75
+ backgroundImage: {
76
+ 'arrow-right-up-line': "url('solidus_admin/arrow_right_up_line.svg')",
77
+ 'arrow-down-s-fill-gray-700': "url('solidus_admin/arrow_down_s_fill_gray_700.svg')",
78
+ 'arrow-down-s-fill-red-400': "url('solidus_admin/arrow_down_s_fill_red_400.svg')",
79
+ },
80
+ boxShadow: {
81
+ sm: '0px 1px 2px 0px rgba(0, 0, 0, 0.04)',
82
+ base: '0px 4px 8px 0px rgba(0, 0, 0, 0.08), 0px 2px 4px -1px rgba(0, 0, 0, 0.04)'
83
+ },
84
+ },
85
+ },
86
+ plugins: [
87
+ require('@tailwindcss/forms')({ strategy: 'class' }),
88
+ require('@tailwindcss/aspect-ratio'),
89
+ require('@tailwindcss/typography'),
90
+ require('@tailwindcss/container-queries'),
91
+ plugin(({ addVariant }) => addVariant('hidden', '&([hidden])')),
92
+ plugin(({ addVariant }) => addVariant('visible', '&:not([hidden])')),
93
+ plugin(({ addVariant }) => addVariant('search-cancel', '&::-webkit-search-cancel-button')),
94
+ ]
95
+ }
@@ -0,0 +1,42 @@
1
+ # Customizing the main navigation
2
+
3
+ You are allowed to add your custom links to the main navigation. To do so, you can access `SolidusAdmin::Config.main_nav` in an initializer:
4
+
5
+ ```ruby
6
+ # config/initializers/solidus_admin.rb
7
+ SolidusAdmin::Config.menu_items << {
8
+ key: :my_custom_link,
9
+ route: :my_custom_link_path,
10
+ icon: "24-hours-fill",
11
+ position: 80
12
+ }
13
+ ```
14
+
15
+ - The key you provide will be used to translate the link's label under the
16
+ `solidus_admin.main_nav.#{key}` key.
17
+ - Icon needs to be an icon name from [Remixicon](https://remixicon.com/).
18
+ - Position tells Solidus where to place the link in the main navigation. The
19
+ default items are placed with 10 points of difference between them.
20
+
21
+ For nested links, you can provide a `children:` option with an array of hashes:
22
+
23
+ ```ruby
24
+ # config/initializers/solidus_admin.rb
25
+ SolidusAdmin::Config.configure do |config|
26
+ config.menu_items << {
27
+ key: :my_custom_link,
28
+ route: :my_custom_link_path,
29
+ icon: "24-hours-fill",
30
+ position: 80,
31
+ children: [
32
+ {
33
+ key: :my_custom_nested_link,
34
+ route: :my_custom_nested_link_path,
35
+ position: 80
36
+ }
37
+ ]
38
+ }
39
+ end
40
+ ```
41
+
42
+ Your custom link will be rendered in the active state when its base path (i.e, the path without the query string) matches the one for the current url.
@@ -0,0 +1,78 @@
1
+ # Customizing tailwind
2
+
3
+ Solidus Admin uses [Tailwind CSS](https://tailwindcss.com/) for styling. The
4
+ benefit of using Tailwind is that it allows you to customize the look and feel
5
+ of the admin without having to write any CSS. By leveraging utility classes,
6
+ you can easily change the colors, fonts, and spacing in use.
7
+
8
+ Solidus Admin sets up Tailwind in a way that allows customization. When you
9
+ install `solidus_admin`, its compiled CSS file is generated at
10
+ `app/assets/builds/solidus_admin/tailwind.css`. As we'll see below, there are
11
+ different ways in which you can add your styles to it. There are a couple of
12
+ tasks you can run to recompile the CSS file:
13
+
14
+ - `bin/rails solidus_admin:tailwindcss:build` - compiles the CSS file once.
15
+ - `bin/rails solidus_admin:tailwindcss:watch` - compiles the CSS file and
16
+ watches for changes.
17
+
18
+ When deploying to production, the build task is automatically added as part of
19
+ the assets precompilation process.
20
+
21
+ ### Adding new paths to Tailwind
22
+
23
+ Tailwind generates its CSS by scanning a configured set of paths for CSS
24
+ classes. By default, Solidus Admin will add to this list the following globs
25
+ from your host application:
26
+
27
+ - `app/components/solidus_admin/**/*.rb`
28
+ - `app/views/solidus_admin/**/*.{erb,haml,html,slim}`
29
+ - `app/helpers/solidus_admin/**/*.rb`
30
+ - `app/assets/javascripts/solidus_admin/**/*.js`
31
+ - `public/solidus_admin/*.html`
32
+
33
+ If that flexibility is not enough, you can add your own paths by appending the
34
+ `SolidusAdmin::Config.tailwind_content` setting:
35
+
36
+ ```ruby
37
+ # config/initializers/solidus_admin.rb
38
+ SolidusAdmin::Config.tailwind_content << Rails.root.join("app/my/custom/path/**/*.rb")
39
+ ```
40
+
41
+ > ⚠ Remember to re-run the `build` or `watch` tasks after changing this setting.
42
+
43
+ ### Adding custom CSS
44
+
45
+ If you need advanced Tailwind customization, you can also create your own CSS
46
+ file and append it to the Solidus Admin's default one. Be aware that's
47
+ [considered a last-resort option](https://tailwindcss.com/docs/reusing-styles)
48
+ according to Tailwind's philosophy, and most of the time you should be ok by
49
+ making use of the available Tailwind classes.
50
+
51
+ In case you need to do it, you can append your CSS file by pushing it to the
52
+ `SolidusAdmin.tailwind_stylesheets` array:
53
+
54
+ ```ruby
55
+ # config/initializers/solidus_admin.rb
56
+ SolidusAdmin.tailwind_stylesheets << Rails.root.join("app/my/custom/path/my_styles.css")
57
+ ```
58
+
59
+ > ⚠ Remember to re-run the `build` or `watch` tasks after changing this setting.
60
+
61
+ ## Acquiring full control over Tailwind configuration
62
+
63
+ For very advanced use cases, it's possible to bail out of the Solidus Admin's
64
+ managed Tailwind configuration and get a grip on it yourself. This is not
65
+ recommended, as it will make your app more brittle to future changes in Solidus
66
+ Admin, so do it at your own risk!
67
+
68
+ There are a couple of tasks you can run for that:
69
+
70
+ - `bin/rails solidus_admin:tailwindcss:override_config` - copies the default
71
+ Tailwind configuration file to `config/solidus_admin/tailwind.config.js.erb`.
72
+ - `bin/rails solidus_admin:tailwindcss:override_stylesheet` - copies the
73
+ default Tailwind stylesheet file to
74
+ `app/assets/stylesheets/solidus_admin/application.tailwind.css.erb`.
75
+
76
+ Notice that, unlike in a regular Tailwind setup, the config and stylesheet
77
+ files are ERB templates. This is because they need to be able to access the
78
+ Solidus Admin and application paths.
@@ -0,0 +1,153 @@
1
+ # Customizing view components
2
+
3
+ Solidus Admin uses [view components](https://viewcomponent.org/) to render the views. Components are
4
+ a pattern for breaking up the view layer into small, reusable pieces, easy to
5
+ reason about and test.
6
+
7
+ All the components Solidus Admin uses are located in the [`app/components`](../app/components) folder of the
8
+ `solidus_admin` gem. As you can see, they are organized in a particular folder structure:
9
+
10
+ - All of them are under the `SolidusAdmin` namespace.
11
+ - They are grouped in sidecar directories, where the main component file and
12
+ all its related files (assets, i18n files, etc.) live together.
13
+
14
+ For instance, the component for the main navigation is located in
15
+ [`app/components/solidus_admin/main_nav/component.rb`](../app/components/solidus_admin/main_nav/component.rb).
16
+
17
+ Solidus Admin components are designed to be easily customizable by the host
18
+ application. Because of that, if you look at how they are designed, you'll find
19
+ a series of patterns are followed consistently:
20
+
21
+ - Components are always resolved from a global registry in
22
+ `SolidusAdmin::Config.components` instead of being referenced by their constant. For
23
+ example, we call `component('main_nav')` instead of referencing
24
+ `SolidusAdmin::MainNav::Component` directly. As you'll see later, this makes
25
+ it easy to replace or tweak a component.
26
+ - It's possible to override the registry locally inside a component by redefining
27
+ the `#component` method. This is useful when you need to use a component that
28
+ is not registered in the global registry or need to address some edge case.
29
+ - In any case, Solidus Admin components initializers only take keyword
30
+ arguments.
31
+
32
+ A picture is worth a thousand words, so let's depict how this works with an
33
+ example:
34
+
35
+ ```ruby
36
+ # app/components/solidus_admin/foo/component.rb
37
+ class SolidusAdmin::Foo::Component < SolidusAdmin::BaseComponent
38
+ def component(key)
39
+ return MyApplication::Bar::Component if key == 'bar'
40
+
41
+ super
42
+ end
43
+
44
+ erb_template <<~ERB
45
+ <div>
46
+ <%= render component('bar').new %>
47
+ </div>
48
+ ERB
49
+ end
50
+ # render component('foo').new
51
+ ```
52
+
53
+ ## Customizing components
54
+
55
+ Some of the customizations detailed below require you to match Solidus Admin's
56
+ component paths in your application. For instance, if we talk about the
57
+ component in `solidus_admin` gem's
58
+ `app/components/solidus_admin/main_nav/component.rb`, the matching path in your
59
+ application would be
60
+ `app/components/my_application/solidus_admin/main_nav/component.rb`, where
61
+ `my_application` is the underscored name of your application (you can get it by
62
+ running `Rails.application.class.module_parent_name`).
63
+
64
+ ### Replacing a component's template
65
+
66
+ In the most typical case, you'll only need to replace the template used by a
67
+ component. You can do that by creating a new component with a maching path in
68
+ your application, inheriting from the default one. Then, you can create a new
69
+ template for it. For example, to replace the main nav template:
70
+
71
+ ```erb
72
+ # app/components/my_application/solidus_admin/main_nav/component.rb %>
73
+ class MyApplication::SolidusAdmin::MainNav::Component < ::SolidusAdmin::MainNav::Component
74
+ end
75
+
76
+ <%# app/components/my_application/solidus_admin/main_nav/component.html.erb %>
77
+ <nav class="my_own_classes">
78
+ <%=
79
+ render main_nav_item_component.with_collection(
80
+ sorted_items
81
+ )
82
+ %>
83
+ </nav>
84
+ ```
85
+
86
+ ### Prepending or appending to a component's template
87
+
88
+ In some situations, you might only need to add some markup before or after a
89
+ component. You can easily do that by rendering the Solidus Admin component and
90
+ adding your markup before or after it.
91
+
92
+ ```erb
93
+ <%# app/components/my_application/solidus_admin/main_nav/component.html.erb %>
94
+ <h1>MY STORE ADMINISTRATION</h1>
95
+ <%= render SolidusAdmin::MainNav::Component.new %>
96
+ ```
97
+
98
+ ### Replacing a component
99
+
100
+ You can replace a component by creating a new one with a matching path in your
101
+ application.
102
+
103
+ There are two considerations to keep in mind:
104
+
105
+ - Be aware that other components might be using the component you're replacing.
106
+ They should only be using its `#initialize` method, so make sure to keep
107
+ compatibility with it when they're called.
108
+ - Solidus Admin's components always inherit from
109
+ [SolidusAdmin::BaseComponent](../app/components/solidus_admin/base_component.rb).
110
+ You can consider doing the same if you need to use one of its helpers.
111
+
112
+ For example, the following replaces the main nav component:
113
+
114
+ ```ruby
115
+ # app/components/my_application/solidus_admin/main_nav/component.rb
116
+ class MyApplication::SolidusAdmin::MainNav::Component < SolidusAdmin::BaseComponent
117
+ # do your thing
118
+ end
119
+ ```
120
+
121
+ If you need more control, you can explicitly register your component in the
122
+ Solidus Admin container instead of using an implicit path:
123
+
124
+ > ⓘ Right now, that will raise an error when the application is reloaded. We
125
+ > need to fix it.
126
+
127
+ ```ruby
128
+ # config/initalizers/solidus_admin.rb
129
+ Rails.application.config.to_prepare do
130
+ SolidusAdmin::Config.components['ui/button'] = MyApplication::Button::Component
131
+ end
132
+ ```
133
+
134
+ ### Tweaking a component
135
+
136
+ If you only need to tweak a component, you can always inherit from it in a
137
+ matching path from within your application (or manually add it to the
138
+ registry) and override the methods you need to change:
139
+
140
+ ```ruby
141
+ # app/components/my_application/solidus_admin/main_nav/component.rb
142
+ class MyApplication::SolidusAdmin::MainNav::Component < ::SolidusAdmin::MainNav::Component
143
+ def sorted_items
144
+ super.reverse
145
+ end
146
+ end
147
+ ```
148
+
149
+ Be aware that this approach comes with an important trade-off: You'll need to
150
+ keep your component in sync with the original one as it changes on future updates.
151
+ For instance, in the example above, the component is overriding a private
152
+ method, so there's no guarantee that it will continue to exist in the future
153
+ without being deprecated, as we only guarantee public API stability.
@@ -0,0 +1,13 @@
1
+ Description:
2
+
3
+ Creates a SolidusAdmin component.
4
+
5
+ Example:
6
+
7
+ $ bin/rails generate solidus_admin:component my_namespace/my_module_name my_attribute
8
+
9
+ create app/components/my_namespace/my_module_name/component.rb
10
+ create app/components/my_namespace/my_module_name/component.html.erb
11
+ create app/components/my_namespace/my_module_name/component.yml
12
+ create app/components/my_namespace/my_module_name/component.js
13
+ create spec/components/my_namespace/my_module_name/component_spec.rb
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusAdmin
4
+ class ComponentGenerator < Rails::Generators::NamedBase
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ argument :attributes, type: :array, default: [], banner: "attribute"
8
+
9
+ class_option :html, type: :boolean, default: true
10
+ class_option :i18n, type: :boolean, default: true
11
+ class_option :js, type: :boolean, default: true
12
+ class_option :spec, type: :boolean, default: true
13
+ class_option :preview, type: :boolean, default: true
14
+
15
+ def setup_inflections
16
+ # This is needed because the generator won't run the initialization process,
17
+ # in order to ensure that UI is not rendered as Ui we need to setup inflections
18
+ # manually.
19
+ SolidusAdmin::Engine.initializers.find { _1.name =~ /inflections/ }.run
20
+ end
21
+
22
+ def create_component_files
23
+ template "component.html.erb", destination(".html.erb")
24
+ unless options["html"]
25
+ say_status :inline, destination(".html.erb"), :blue
26
+ @inline_html = File.read(destination(".html.erb"))
27
+ shell.mute { remove_file(destination(".html.erb")) }
28
+ end
29
+ template "component.rb", destination(".rb")
30
+ template "component.yml", destination(".yml") if options["i18n"]
31
+ template "component.js", destination(".js") if options["js"]
32
+ template "component_spec.rb", destination("_spec.rb", root: "spec/components") if options["spec"]
33
+
34
+ if options["preview"]
35
+ preview_destination_path = destination("_preview.rb", root: "spec/components/previews")
36
+ template "component_preview.rb", preview_destination_path
37
+ template "component_preview_overview.html.erb", preview_destination_path.sub(/\.rb/, '/overview.html.erb')
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def component_registry_id
44
+ [class_path.presence, file_name].compact.join("/")
45
+ end
46
+
47
+ def destination(suffix, root: "app/components")
48
+ File.join(root, class_path, file_name, "component#{suffix}")
49
+ end
50
+
51
+ def file_name
52
+ @_file_name ||= super.sub(/_component\z/i, "")
53
+ end
54
+
55
+ def dom_class
56
+ [class_path.presence, file_name].compact.join("/").tr("_", "-").gsub("/", "--")
57
+ end
58
+
59
+ def stimulus_controller_name
60
+ dom_class
61
+ end
62
+
63
+ def stimulus_attributes
64
+ ' data-controller="<%= stimulus_id %>"'
65
+ end
66
+
67
+ def initialize_signature
68
+ return if attributes.blank?
69
+
70
+ attributes.map { |attr| "#{attr.name}:" }.join(", ")
71
+ end
72
+
73
+ def initialize_body
74
+ attributes.map { |attr| "@#{attr.name} = #{attr.name}" }.join("\n ")
75
+ end
76
+
77
+ def preview_signature
78
+ return if attributes.blank?
79
+
80
+ signature = attributes.map { |attr| "#{attr.name}: #{attr.name.to_s.inspect}" }.join(", ")
81
+ "(#{signature})"
82
+ end
83
+
84
+ def preview_playground_yard_tags
85
+ return if attributes.blank?
86
+
87
+ # See https://lookbook.build/guide/previews/params#input-types
88
+ attributes.map { |attr| "# @param #{attr.name} text" }.join("\n ")
89
+ end
90
+
91
+ def preview_playground_body
92
+ render_signature = attributes.map { |attr| "#{attr.name}: #{attr.name}" }.join(", ")
93
+ render_signature = "(#{render_signature})" if render_signature.present?
94
+
95
+ "render component(#{component_registry_id.inspect}).new#{render_signature}"
96
+ end
97
+
98
+ def preview_overview_body
99
+ component_registry_id = [class_path.presence, file_name].compact.join("/")
100
+
101
+ "render component(#{component_registry_id.inspect}).new#{preview_signature}"
102
+ end
103
+
104
+ def attributes_html
105
+ attributes.map { |attr| "<p> <%= @#{attr.name} %> </p>" }.join("\n ")
106
+ end
107
+
108
+ def stimulus_html
109
+ %{\n <label>Your name: <input data-action="input->#{stimulus_controller_name}#typed"/></label>} +
110
+ %{\n <p>Hello <span data-#{stimulus_controller_name}-target="output"></span></p>}
111
+ end
112
+
113
+ def i18n_html
114
+ "<%= t '.hello' %>"
115
+ end
116
+
117
+ def initialize_html
118
+ [
119
+ "<p>Add #{class_name} HTML here</p>",
120
+ (attributes_html if attributes.present?),
121
+ (stimulus_html if options["js"]),
122
+ (i18n_html if options["i18n"]),
123
+ ].compact.join("\n ")
124
+ end
125
+
126
+ def inline_html(indent: '')
127
+ @inline_html.gsub!(/^/, indent).strip
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,3 @@
1
+ <div class="<%%= stimulus_id %>"<%= stimulus_attributes if options[:js] %>>
2
+ <%= initialize_html %>
3
+ </div>
@@ -0,0 +1,14 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ static targets = ['output']
5
+
6
+ typed(event) {
7
+ this.text = event.currentTarget.value
8
+ this.render()
9
+ }
10
+
11
+ render() {
12
+ this.outputTarget.innerText = this.text
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= File.join(*[namespaced_path, file_path].compact).classify %>::Component < SolidusAdmin::BaseComponent
4
+ <%- if initialize_signature -%>
5
+ def initialize(<%= initialize_signature %>)
6
+ <%= initialize_body %>
7
+ end
8
+ <%- end -%>
9
+ <% unless options['html'] %>
10
+ erb_template <<~ERB
11
+ <%= inline_html indent: ' ' %>
12
+ ERB
13
+ <%- end -%>
14
+ end
@@ -0,0 +1,4 @@
1
+ # Add your component translations here.
2
+ # Use the translation in the example in your template with `t(".hello")`.
3
+ en:
4
+ hello: "Hello world!"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @component <%= component_registry_id.inspect %>
4
+ class <%= File.join(*[namespaced_path, file_path].compact).classify %>::ComponentPreview < ViewComponent::Preview
5
+ include SolidusAdmin::Preview
6
+
7
+ def overview
8
+ render_with_template
9
+ end
10
+
11
+ <%= preview_playground_yard_tags %>
12
+ def playground<%= preview_signature %>
13
+ <%= preview_playground_body %>
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ <div class="mb-8">
2
+ <h6 class="text-gray-500 mb-3 mt-0">
3
+ Scenario 1
4
+ </h6>
5
+
6
+ <%%= render current_component.new<%= preview_signature %> %>
7
+ </div>
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe <%= File.join(*[namespaced_path, file_path].compact).classify %>::Component, type: :component do
6
+ it "renders the overview preview" do
7
+ render_preview(:overview)
8
+ end
9
+
10
+ # it "renders something useful" do
11
+ # render_inline(described_class.new(<%= attributes.map { |attr| "#{attr.name}: #{attr.name.to_s.inspect}" }.join(", ") %>))
12
+ #
13
+ # expect(page).to have_text "Hello, components!"
14
+ # expect(page).to have_css '.value'
15
+ # end
16
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusAdmin
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ class_option :lookbook, type: :boolean, default: !!ENV['SOLIDUS_ADMIN_LOOKBOOK'], desc: 'Install Lookbook for component previews'
7
+
8
+ source_root "#{__dir__}/templates"
9
+
10
+ def install_solidus_core_support
11
+ route <<~RUBY
12
+ mount SolidusAdmin::Engine, at: '/admin', constraints: ->(req) {
13
+ req.cookies['solidus_admin'] != 'false' &&
14
+ req.params['solidus_admin'] != 'false'
15
+ }
16
+ RUBY
17
+ end
18
+
19
+ def copy_initializer
20
+ copy_file "config/initializers/solidus_admin.rb"
21
+ end
22
+
23
+ def ignore_tailwind_build_files
24
+ append_file(".gitignore", "app/assets/builds/solidus_admin/") if File.exist?(Rails.root.join(".gitignore"))
25
+ end
26
+
27
+ def build_tailwind
28
+ rake "solidus_admin:tailwindcss:build"
29
+ end
30
+
31
+ def install_lookbook
32
+ return unless options[:lookbook]
33
+
34
+ gem_group :development, :test do
35
+ gem "lookbook"
36
+ gem "listen"
37
+ gem "actioncable"
38
+ end
39
+
40
+ route "mount Lookbook::Engine, at: '/lookbook' if Rails.env.development?"
41
+ end
42
+ end
43
+ end
44
+ end