solidus_admin 0.0.0 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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