rails_devtools 0.1.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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +92 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/devtools_manifest.js +1 -0
  5. data/app/assets/stylesheets/devtools/application.css +15 -0
  6. data/app/controllers/rails_devtools/application_controller.rb +4 -0
  7. data/app/controllers/rails_devtools/base_controller.rb +7 -0
  8. data/app/controllers/rails_devtools/database_tables_controller.rb +16 -0
  9. data/app/controllers/rails_devtools/frontend/modules_controller.rb +18 -0
  10. data/app/controllers/rails_devtools/gems_controller.rb +16 -0
  11. data/app/controllers/rails_devtools/host_app_images_controller.rb +35 -0
  12. data/app/controllers/rails_devtools/image_assets_controller.rb +43 -0
  13. data/app/controllers/rails_devtools/routes/route_path_inputs_controller.rb +23 -0
  14. data/app/controllers/rails_devtools/routes_controller.rb +21 -0
  15. data/app/forms/rails_devtools/database_table_search_form.rb +51 -0
  16. data/app/forms/rails_devtools/gem_search_form.rb +86 -0
  17. data/app/forms/rails_devtools/image_search_form.rb +30 -0
  18. data/app/forms/rails_devtools/route_search_form.rb +17 -0
  19. data/app/helpers/rails_devtools/application_helper.rb +4 -0
  20. data/app/javascript/application.js +4 -0
  21. data/app/javascript/controllers/application.js +10 -0
  22. data/app/javascript/controllers/checkbox_controller.js +9 -0
  23. data/app/javascript/controllers/index.js +11 -0
  24. data/app/javascript/controllers/search_reset_controller.js +7 -0
  25. data/app/javascript/controllers/turbo_form_controller.js +9 -0
  26. data/app/jobs/rails_devtools/application_job.rb +4 -0
  27. data/app/mailers/rails_devtools/application_mailer.rb +6 -0
  28. data/app/models/rails_devtools/application_record.rb +5 -0
  29. data/app/models/rails_devtools/image_assets/image_info.rb +85 -0
  30. data/app/models/rails_devtools/routes/collection.rb +83 -0
  31. data/app/models/rails_devtools/routes/controller_info.rb +30 -0
  32. data/app/models/rails_devtools/routes/engine_info.rb +33 -0
  33. data/app/models/rails_devtools/routes/route_info.rb +120 -0
  34. data/app/views/rails_devtools/application_layout.rb +90 -0
  35. data/app/views/rails_devtools/application_view.rb +6 -0
  36. data/app/views/rails_devtools/components/application_component.rb +24 -0
  37. data/app/views/rails_devtools/components/flash_message.rb +29 -0
  38. data/app/views/rails_devtools/components/lucide/base.rb +18 -0
  39. data/app/views/rails_devtools/components/lucide/close.rb +25 -0
  40. data/app/views/rails_devtools/components/lucide/database.rb +26 -0
  41. data/app/views/rails_devtools/components/lucide/external_link.rb +26 -0
  42. data/app/views/rails_devtools/components/lucide/images.rb +27 -0
  43. data/app/views/rails_devtools/components/lucide/menu.rb +26 -0
  44. data/app/views/rails_devtools/components/lucide/package.rb +30 -0
  45. data/app/views/rails_devtools/components/lucide/pocket_knife.rb +28 -0
  46. data/app/views/rails_devtools/components/lucide/sign_post.rb +29 -0
  47. data/app/views/rails_devtools/components/lucide/trash.rb +26 -0
  48. data/app/views/rails_devtools/components/lucide/triangle_alert.rb +29 -0
  49. data/app/views/rails_devtools/components/page_content.rb +27 -0
  50. data/app/views/rails_devtools/components/ui/drawer.rb +49 -0
  51. data/app/views/rails_devtools/components/ui/menu.rb +81 -0
  52. data/app/views/rails_devtools/components/ui/search_form.rb +65 -0
  53. data/app/views/rails_devtools/components.rb +5 -0
  54. data/app/views/rails_devtools/database_tables/index.rb +32 -0
  55. data/app/views/rails_devtools/database_tables/table_card.rb +61 -0
  56. data/app/views/rails_devtools/gems/gem_card.rb +74 -0
  57. data/app/views/rails_devtools/gems/index.rb +32 -0
  58. data/app/views/rails_devtools/image_assets/image_card.rb +37 -0
  59. data/app/views/rails_devtools/image_assets/image_details.rb +82 -0
  60. data/app/views/rails_devtools/image_assets/index.rb +39 -0
  61. data/app/views/rails_devtools/routes/index.rb +37 -0
  62. data/app/views/rails_devtools/routes/route_card.rb +70 -0
  63. data/app/views/rails_devtools/routes/route_details/controller_card.rb +87 -0
  64. data/app/views/rails_devtools/routes/route_details/route_path_input.rb +46 -0
  65. data/app/views/rails_devtools/routes/route_details.rb +171 -0
  66. data/config/routes.rb +24 -0
  67. data/lib/rails_devtools/asset_config.rb +52 -0
  68. data/lib/rails_devtools/asset_providers/jsbundling_rails_config.rb +21 -0
  69. data/lib/rails_devtools/asset_providers/propshaft_config.rb +19 -0
  70. data/lib/rails_devtools/asset_providers/shakapacker_config.rb +26 -0
  71. data/lib/rails_devtools/asset_providers/sprocket_config.rb +19 -0
  72. data/lib/rails_devtools/asset_providers/vite_rails_config.rb +19 -0
  73. data/lib/rails_devtools/engine.rb +22 -0
  74. data/lib/rails_devtools/importmap.rb +16 -0
  75. data/lib/rails_devtools/importmaps/base.rb +82 -0
  76. data/lib/rails_devtools/version.rb +3 -0
  77. data/lib/rails_devtools.rb +20 -0
  78. data/lib/tasks/rails_devtools_tasks.rake +4 -0
  79. data/vendor/javascript/@stimulus-components--clipboard.js +4 -0
  80. data/vendor/javascript/@stimulus-components--notification.js +4 -0
  81. data/vendor/javascript/@stimulus-components--reveal.js +4 -0
  82. data/vendor/javascript/stimulus-autoloader.js +54 -0
  83. data/vendor/javascript/stimulus-importmap-autoloader.js +27 -0
  84. data/vendor/javascript/stimulus-loading.js +93 -0
  85. data/vendor/javascript/stimulus-use.js +4 -0
  86. data/vendor/javascript/stimulus.min.js +5 -0
  87. data/vendor/javascript/turbo.min.js +36 -0
  88. metadata +241 -0
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module ImageAssets
5
+ class ImageInfo
6
+ IMAGE_EXTENSIONS = Set[
7
+ ".jpg", ".jpeg", # JPEG
8
+ ".png", # PNG
9
+ ".gif", # GIF
10
+ ".webp", # WebP
11
+ ".svg", # SVG
12
+ ".avif", # AVIF
13
+ ".ico" # Favicon
14
+ ].freeze
15
+
16
+ def initialize(image_path)
17
+ @image_path = image_path
18
+ end
19
+
20
+ def full_path
21
+ @image_path
22
+ end
23
+
24
+ def valid?
25
+ File.file?(@image_path) && image?
26
+ end
27
+
28
+ def image?
29
+ FastImage.type(@image_path).present?
30
+ end
31
+
32
+ def basename
33
+ @basename ||= File.basename(@image_path)
34
+ end
35
+
36
+ def name
37
+ basename.split(".").first
38
+ end
39
+
40
+ def extension
41
+ File.extname(@image_path).downcase
42
+ end
43
+
44
+ def file_size
45
+ @file_size ||= FastImage.new(@image_path).content_length
46
+ end
47
+
48
+ def image_helper_snippet
49
+ "#{asset_config.helper_snippet}(\"#{devtools_image_path}\")"
50
+ end
51
+
52
+ def devtools_image_path
53
+ return @devtools_image_path if defined?(@devtools_image_path)
54
+
55
+ matching_path = asset_config.paths.find { |asset_path| @image_path.start_with?(asset_path) }
56
+ matching_base = Pathname.new(matching_path).join(asset_config.implicit_path)
57
+ asset_path = Pathname.new(@image_path)
58
+
59
+ @devtools_image_path = asset_path
60
+ .relative_path_from(matching_base)
61
+ .to_s.sub("../", "")
62
+ end
63
+
64
+ def width
65
+ size[0]
66
+ end
67
+
68
+ def height
69
+ size[1]
70
+ end
71
+
72
+ delegate :provider, to: :asset_config
73
+
74
+ private
75
+
76
+ def size
77
+ @size ||= FastImage.size(@image_path)
78
+ end
79
+
80
+ def asset_config
81
+ @asset_config ||= RailsDevtools.asset_config
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class Collection
6
+ def self.all
7
+ new.all
8
+ end
9
+
10
+ def self.find(id)
11
+ new.find(id)
12
+ end
13
+
14
+ def all
15
+ return @all if defined?(@all)
16
+
17
+ @all = []
18
+ @current_id = 0
19
+
20
+ add_routes(app_routes, engine_name: "Application")
21
+ process_engine_routes(rails_routes)
22
+
23
+ @all
24
+ end
25
+
26
+ def find(id)
27
+ all.find { |route| route.id == id.to_i }
28
+ end
29
+
30
+ private
31
+
32
+ def add_routes(routes, engine_name:)
33
+ routes.each do |route|
34
+ @current_id += 1
35
+ @all << Routes::RouteInfo.new(route, engine: engine_name, id: @current_id)
36
+ end
37
+ end
38
+
39
+ def process_engine_routes(routes)
40
+ routes.select { |r| r.app.engine? && r.app.app.name != "RailsDevtools::Engine" }.each do |engine_route|
41
+ engine = engine_route.app.app
42
+ process_single_engine(engine: engine)
43
+ end
44
+ end
45
+
46
+ def process_single_engine(engine:)
47
+ valid_engine_routes = engine.routes.routes.select { |r| valid_route?(r) }
48
+ add_routes(valid_engine_routes, engine_name: engine.name)
49
+
50
+ nested_routes = engine.routes.routes
51
+ nested_routes.select { |r| r.app.respond_to?(:engine?) && r.app.engine? }.each do |nested_engine_route|
52
+ nested_engine = nested_engine_route.app.app
53
+ process_single_engine(engine: nested_engine)
54
+ end
55
+ end
56
+
57
+ def app_routes
58
+ rails_routes.select { |r| valid_route?(r) }
59
+ end
60
+
61
+ def valid_route?(route)
62
+ wrapped_route = ActionDispatch::Routing::RouteWrapper.new(route)
63
+ !rails_route?(wrapped_route) &&
64
+ !turbo_route?(wrapped_route) &&
65
+ !wrapped_route.internal?
66
+ end
67
+
68
+ def rails_routes
69
+ @rails_routes ||= Rails.application.routes.routes
70
+ end
71
+
72
+ def rails_route?(route)
73
+ return true if route.path.include?("rails/")
74
+
75
+ route.name&.include?("rails")
76
+ end
77
+
78
+ def turbo_route?(route)
79
+ route.name&.start_with?("turbo")
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,30 @@
1
+ module RailsDevtools
2
+ module Routes
3
+ class ControllerInfo
4
+ attr_reader :action
5
+
6
+ def initialize(controller_name: nil, action: nil)
7
+ @controller_name = controller_name
8
+ @action = action
9
+ end
10
+
11
+ def file_path
12
+ full_class_name.underscore + ".rb"
13
+ end
14
+
15
+ def full_class_name
16
+ @full_class_name ||= [@controller_name, "controller"].join("_").camelize
17
+ end
18
+
19
+ def controller
20
+ @controller ||= full_class_name.safe_constantize
21
+ end
22
+
23
+ def action_exists?
24
+ return false unless controller
25
+
26
+ controller.action_methods.include?(@action)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module RailsDevtools
2
+ module Routes
3
+ class EngineInfo
4
+ def initialize(engine_name)
5
+ @engine_name = engine_name
6
+ end
7
+
8
+ def engine
9
+ return Rails.application if @engine_name == "Application"
10
+
11
+ @engine_name.constantize
12
+ end
13
+
14
+ def engine?
15
+ @engine_name != "Application"
16
+ end
17
+
18
+ def name
19
+ @engine_name
20
+ end
21
+
22
+ def path
23
+ @path ||= engine.routes.find_script_name({})
24
+ end
25
+
26
+ def helper_prefix
27
+ return "" unless engine?
28
+
29
+ path.split("/").last.underscore
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class RouteInfo
6
+ attr_reader :id
7
+
8
+ def initialize(route, id:, engine: "Application")
9
+ @route = route
10
+ @wrapped_route = ActionDispatch::Routing::RouteWrapper.new(route)
11
+ @engine = engine
12
+ @id = id
13
+ end
14
+
15
+ delegate :controller, :action, :constraints, :endpoint, to: :@wrapped_route
16
+
17
+ def segments
18
+ @wrapped_route.parts.reject { |p| p == :format }
19
+ end
20
+
21
+ def controller_info
22
+ @controller_info ||= ControllerInfo.new(
23
+ controller_name: controller,
24
+ action: action
25
+ )
26
+ end
27
+
28
+ def name
29
+ @name ||= route_name
30
+ end
31
+
32
+ def kind
33
+ @kind ||=
34
+ if engine?
35
+ "engine"
36
+ elsif rack_app?
37
+ "rack_app"
38
+ elsif redirection?
39
+ "redirection"
40
+ elsif inline?
41
+ "inline"
42
+ else
43
+ "controller"
44
+ end
45
+ end
46
+
47
+ def engine?
48
+ @route.app.respond_to?(:engine?) && @route.app.engine?
49
+ end
50
+
51
+ def verb
52
+ return "?" if rack_app? || engine?
53
+ @wrapped_route.verb.presence || "ALL"
54
+ end
55
+
56
+ def redirection?
57
+ return false if inline?
58
+
59
+ @route.app&.app.respond_to?(:redirect?) && @route.app.app.redirect?
60
+ end
61
+
62
+ def rack_app?
63
+ return false if inline?
64
+ return false if redirection?
65
+ return false if engine?
66
+
67
+ @route.app.app.respond_to?(:call) &&
68
+ !@route.app.app.is_a?(ActionDispatch::Routing::RouteSet)
69
+ end
70
+
71
+ def inline?
72
+ endpoint.include?("Proc/Lambda")
73
+ end
74
+
75
+ def controller?
76
+ [inline?, redirection?, rack_app?].none?
77
+ end
78
+
79
+ RedirectionInfo = Data.define(:status, :block)
80
+
81
+ def redirection_info
82
+ return unless redirection?
83
+
84
+ @redirection_info ||= RedirectionInfo.new(
85
+ status: @route.app.app.status,
86
+ block: @route.app.app.block
87
+ )
88
+ end
89
+
90
+ def path
91
+ return @wrapped_route.path if @engine == "Application"
92
+ engine_info.path + @wrapped_route.path
93
+ end
94
+
95
+ def engine_info
96
+ @engine_info ||= EngineInfo.new(@engine)
97
+ end
98
+
99
+ private
100
+
101
+ def route_name
102
+ return "Inline route to #{path.gsub('(.:format)', '')}" if inline?
103
+ return @wrapped_route.name if @wrapped_route.name.present?
104
+
105
+ matching_route = engine_info.engine.routes.routes.find do |r|
106
+ r.path.spec.to_s == @wrapped_route.path
107
+ end
108
+
109
+ if matching_route.name.blank?
110
+ return [
111
+ @wrapped_route.defaults[:controller],
112
+ @wrapped_route.defaults[:action]
113
+ ].join("_")
114
+ end
115
+
116
+ matching_route.name
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class ApplicationLayout < ApplicationView
5
+ include Phlex::Rails::Layout
6
+ include Phlex::Rails::Helpers::ContentFor
7
+ include Phlex::Rails::Helpers::StripTags
8
+ include Phlex::Rails::Helpers::JavascriptIncludeTag
9
+
10
+ def view_template(&block)
11
+ doctype
12
+
13
+ html(data_theme: "nord") do
14
+ head do
15
+ title do
16
+ content_for?(:title) ? strip_tags(yield(:title)) : "Maxime Souillat"
17
+ end
18
+
19
+ meta(name: "apple-mobile-web-app-title", content: "Maxime Souillat")
20
+ meta(name: "viewport", content: "width=device-width,initial-scale=1")
21
+
22
+ csrf_meta_tags
23
+ csp_meta_tag
24
+
25
+ importmap_tag
26
+ preload_tags
27
+ script(type: "module") { "import 'application' ;".html_safe }
28
+
29
+ script(src: "https://cdn.tailwindcss.com")
30
+ link(
31
+ href: "https://cdn.jsdelivr.net/npm/daisyui@4.12.14/dist/full.min.css",
32
+ rel: "stylesheet",
33
+ type: "text/css"
34
+ )
35
+ end
36
+
37
+ body do
38
+ main(class: "h-screen flex flex-col") do
39
+ div(class: "grow lg:flex") do
40
+ render Components::Ui::Menu
41
+ right_drawer(&block)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def importmap_tag
51
+ script(type: "importmap", data_turbo_track: "reload") do
52
+ RailsDevtools.importmap.to_json.html_safe
53
+ end
54
+ end
55
+
56
+ def preload_tags
57
+ RailsDevtools.importmap.preloads.each do |preload|
58
+ link(rel: "modulepreload", href: preload.path)
59
+ end
60
+ end
61
+
62
+ def right_drawer(&block)
63
+ render Components::Ui::Drawer.new(id: "right_drawer", direction: "right") do |right_drawer|
64
+ right_drawer.content { page_content(&block) }
65
+ right_drawer.drawer_side do
66
+ div(class: "p-4 bg-base-200 text-base-content min-h-full flex flex-col") do
67
+ div(class: "flex flex-none justify-end mb-8") do
68
+ label(
69
+ for: "right_drawer",
70
+ aria_label: "close sidebar",
71
+ class: "btn bnt-square btn-outline btn-xs"
72
+ ) do
73
+ render Components::Lucide::Close.new(width: 16, height: 16)
74
+ end
75
+ end
76
+
77
+ div(class: "flex flex-col mt-20 grow") do
78
+ turbo_frame_tag("drawer_content", class: "flex flex-col h-full grow")
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def page_content(&)
86
+ turbo_frame_tag("flash_messages")
87
+ div(class: "mt-4 mb-16 max-w-screen-2xl mx-4", &)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class ApplicationView < Components::ApplicationComponent
5
+ end
6
+ end
@@ -0,0 +1,24 @@
1
+ # # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class ApplicationComponent < Phlex::HTML
6
+ include Phlex::Rails::Helpers::TurboFrameTag
7
+ include Phlex::Rails::Helpers::Routes
8
+ include Phlex::Rails::Helpers::ClassNames
9
+ include Phlex::Rails::Helpers::LinkTo
10
+ include Phlex::Rails::Helpers::T
11
+ include Phlex::Rails::Helpers::ContentFor
12
+ include Phlex::Rails::Helpers::ButtonTo
13
+ include Phlex::Rails::Helpers::ImageTag
14
+ include Phlex::Rails::Helpers::DOMID
15
+
16
+ if Rails.env.development?
17
+ def before_template
18
+ comment { "Before #{self.class.name}" }
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ module RailsDevtools
2
+ module Components
3
+ class FlashMessage < Components::ApplicationComponent
4
+ def initialize(message:)
5
+ @message = message
6
+ end
7
+
8
+ def view_template
9
+ div(
10
+ class: "transition transform duration-1000 hidden",
11
+ data: {
12
+ controller: "notification",
13
+ notification_delay_value: "2000",
14
+ transition_enter_from: "opacity-0 translate-x-6",
15
+ transition_enter_to: "opacity-100 translate-x-0",
16
+ transition_leave_from: "opacity-100 translate-x-0",
17
+ transition_leave_to: "opacity-0 translate-x-6"
18
+ }
19
+ ) do
20
+ div(class: "toast toast-top toast-end") do
21
+ div(role: "alert", class: "alert alert-success") do
22
+ span { @message }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Base < Components::ApplicationComponent
6
+ attr_reader :width, :height, :stroke
7
+
8
+ def initialize(width: 24, height: 24)
9
+ @width = width.to_s
10
+ @height = height.to_s
11
+ end
12
+
13
+ def view_template
14
+ raise NotImplementedError, "You must implement the view_template method"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Close < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-x"
18
+ ) do |s|
19
+ s.path(d: "M18 6 6 18")
20
+ s.path(d: "m6 6 12 12")
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Database < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-database"
18
+ ) do |s|
19
+ s.ellipse(cx: "12", cy: "5", rx: "9", ry: "3")
20
+ s.path(d: "M3 5V19A9 3 0 0 0 21 19V5")
21
+ s.path(d: "M3 12A9 3 0 0 0 21 12")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::ExternalLink < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-external-link"
18
+ ) do |s|
19
+ s.path(d: "M15 3h6v6")
20
+ s.path(d: "M10 14 21 3")
21
+ s.path(d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Images < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-images"
18
+ ) do |s|
19
+ s.path(d: "M18 22H4a2 2 0 0 1-2-2V6")
20
+ s.path(d: "m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18")
21
+ s.circle(cx: "12", cy: "8", r: "2")
22
+ s.rect(width: "16", height: "16", x: "6", y: "2", rx: "2")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Menu < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-menu"
18
+ ) do |s|
19
+ s.line(x1: "4", x2: "20", y1: "12", y2: "12")
20
+ s.line(x1: "4", x2: "20", y1: "6", y2: "6")
21
+ s.line(x1: "4", x2: "20", y1: "18", y2: "18")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Components
5
+ class Lucide::Package < Lucide::Base
6
+ def view_template
7
+ svg(
8
+ xmlns: "http://www.w3.org/2000/svg",
9
+ width: width,
10
+ height: height,
11
+ viewbox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ stroke_width: "2",
15
+ stroke_linecap: "round",
16
+ stroke_linejoin: "round",
17
+ class: "lucide lucide-package"
18
+ ) do |s|
19
+ s.path(
20
+ d:
21
+ "M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"
22
+ )
23
+ s.path(d: "M12 22V12")
24
+ s.path(d: "m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7")
25
+ s.path(d: "m7.5 4.27 9 5.15")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end