plutonium 0.15.13 → 0.15.15

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/plutonium.css +1 -1
  3. data/app/assets/plutonium.js +155 -4
  4. data/app/assets/plutonium.js.map +4 -4
  5. data/app/assets/plutonium.min.js +8 -8
  6. data/app/assets/plutonium.min.js.map +4 -4
  7. data/app/views/components/resource_header/resource_header_component.rb +1 -1
  8. data/app/views/components/resource_layout/resource_layout_component.html.erb +6 -2
  9. data/app/views/layouts/resource.html.erb +1 -14
  10. data/app/views/layouts/rodauth.html.erb +2 -18
  11. data/app/views/plutonium/_resource_header.html.erb +4 -2
  12. data/app/views/plutonium/_resource_sidebar.html.erb +1 -1
  13. data/docs/public/templates/plutonium.rb +6 -12
  14. data/lib/generators/pu/gem/standard/standard_generator.rb +14 -1
  15. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +1 -1
  16. data/lib/plutonium/ui/color_mode_selector.rb +86 -0
  17. data/lib/plutonium/ui/component/kit.rb +2 -0
  18. data/lib/plutonium/ui/component/methods.rb +2 -0
  19. data/lib/plutonium/ui/dyna_frame/host.rb +2 -2
  20. data/lib/plutonium/ui/form/query.rb +4 -2
  21. data/lib/plutonium/ui/layout/base.rb +135 -0
  22. data/lib/plutonium/ui/layout/header.rb +121 -0
  23. data/lib/plutonium/ui/layout/resource_layout.rb +26 -0
  24. data/lib/plutonium/ui/layout/rodauth_layout.rb +34 -0
  25. data/lib/plutonium/ui/layout/sidebar.rb +56 -0
  26. data/lib/plutonium/ui/table/resource.rb +1 -1
  27. data/lib/plutonium/version.rb +1 -1
  28. data/lib/plutonium.rb +1 -1
  29. data/lib/rodauth/features/case_insensitive_login.rb +10 -4
  30. data/package-lock.json +2 -2
  31. data/package.json +1 -1
  32. data/src/js/controllers/header_controller.js +184 -0
  33. data/src/js/controllers/register_controllers.js +4 -2
  34. data/src/js/controllers/{resource_header_controller.js → sidebar_controller.js} +2 -2
  35. metadata +25 -4
  36. /data/lib/rodauth/{loader.rb → plugins.rb} +0 -0
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plutonium
4
+ module UI
5
+ module Layout
6
+ # A sidebar navigation component that provides a responsive layout with light/dark mode toggle
7
+ # @example Basic usage with navigation content
8
+ # render Sidebar.new do
9
+ # ...
10
+ # end
11
+ class Sidebar < Base
12
+ include Phlex::Slotable
13
+
14
+ # Renders the sidebar navigation template
15
+ # @yield [void] The block containing sidebar content
16
+ # @return [void]
17
+ def view_template(&)
18
+ render_sidebar_container do
19
+ render_content(&) if block_given?
20
+ render_color_mode_controls
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # @private
27
+ def render_sidebar_container(&)
28
+ aside(
29
+ id: "sidebar-navigation",
30
+ aria: {label: "Sidebar Navigation"},
31
+ data: {controller: :sidebar},
32
+ class: "fixed top-0 left-0 z-40 w-64 h-screen pt-14 transition-transform -translate-x-full lg:translate-x-0",
33
+ &
34
+ )
35
+ end
36
+
37
+ # @private
38
+ def render_content(&)
39
+ div(
40
+ id: "sidebar-navigation-content",
41
+ data: {turbo_permanent: true},
42
+ class: "overflow-y-auto py-5 px-3 h-full bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700",
43
+ &
44
+ )
45
+ end
46
+
47
+ # @private
48
+ def render_color_mode_controls
49
+ div(class: "hidden absolute bottom-0 left-0 justify-center p-4 space-x-4 w-full lg:flex bg-white dark:bg-gray-800 z-20 border-r border-gray-200 dark:border-gray-700") do
50
+ render ColorModeSelector.new
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -94,7 +94,7 @@ module Plutonium
94
94
  end
95
95
 
96
96
  def render_footer
97
- div(class: "sticky dyna:static bottom-[-2px] mt-1 p-4 pb-6 w-full z-50 bg-gray-50 dark:bg-gray-900") {
97
+ div(class: "lg:sticky lg:dyna:static bottom-[-2px] mt-1 p-4 pb-6 w-full z-30 bg-gray-50 dark:bg-gray-900") {
98
98
  TableInfo(pagy_instance)
99
99
  TablePagination(pagy_instance)
100
100
  }
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- VERSION = "0.15.13"
2
+ VERSION = "0.15.15"
3
3
  NEXT_MAJOR_VERSION = VERSION.split(".").tap { |v|
4
4
  v[1] = v[1].to_i + 1
5
5
  v[2] = 0
data/lib/plutonium.rb CHANGED
@@ -10,7 +10,7 @@ require "phlexi-form"
10
10
  require "phlexi-table"
11
11
 
12
12
  require_relative "plutonium/configuration"
13
- require_relative "rodauth/loader"
13
+ require_relative "rodauth/plugins" if defined?(Rodauth)
14
14
 
15
15
  # Plutonium module
16
16
  #
@@ -1,15 +1,21 @@
1
1
  require "rodauth"
2
2
 
3
+ # A plugin to enable case insensitive logins on Rodauth.
4
+ # It does that by downcasing any login inputs.
5
+ # Should not be enabled on existing installations unless logins are downcased in the database.
6
+ # See https://github.com/jeremyevans/rodauth/discussions/451
3
7
  module Rodauth
4
8
  Feature.define(:case_insensitive_login, :CaseInsensitiveLogin) do
5
9
  def param(key)
6
- value = super
7
- value&.downcase! if [login_param, login_confirm_param].include?(key)
8
- value
10
+ if [login_param, login_confirm_param].include?(key)
11
+ super.downcase
12
+ else
13
+ super
14
+ end
9
15
  end
10
16
 
11
17
  def account_from_login(login)
12
- super(login&.downcase)
18
+ super(login.downcase)
13
19
  end
14
20
  end
15
21
  end
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@radioactive-labs/plutonium",
9
- "version": "0.1.7",
9
+ "version": "0.1.8",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@hotwired/stimulus": "^3.2.2",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Core assets for the Plutonium gem",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",
@@ -0,0 +1,184 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["open", "close"]
5
+ static outlets = ["sidebar"]
6
+ static values = {
7
+ placement: { type: String, default: "left" },
8
+ bodyScrolling: { type: Boolean, default: false },
9
+ backdrop: { type: Boolean, default: true },
10
+ edge: { type: Boolean, default: false },
11
+ edgeOffset: { type: String, default: "bottom-[60px]" }
12
+ }
13
+ static classes = {
14
+ backdrop: "bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-30"
15
+ }
16
+
17
+ initialize() {
18
+ this.visible = false
19
+ this.handleEscapeKey = this.handleEscapeKey.bind(this)
20
+ }
21
+
22
+ connect() {
23
+ document.addEventListener("keydown", this.handleEscapeKey)
24
+ }
25
+
26
+ sidebarOutletConnected() {
27
+ this.#setupDrawer(this.sidebarOutlet.element)
28
+ }
29
+
30
+ disconnect() {
31
+ this.#removeBackdrop()
32
+ document.removeEventListener("keydown", this.handleEscapeKey)
33
+ if (!this.bodyScrollingValue) {
34
+ document.body.classList.remove("overflow-hidden")
35
+ }
36
+ }
37
+
38
+ #setupDrawer(drawerElement) {
39
+ drawerElement.setAttribute("aria-hidden", "true")
40
+ drawerElement.classList.add("transition-transform")
41
+
42
+ // Add base placement classes
43
+ this.#getPlacementClasses(this.placementValue).base.forEach(className => {
44
+ drawerElement.classList.add(className)
45
+ })
46
+ }
47
+
48
+ toggleDrawer() {
49
+ this.visible ? this.hideDrawer() : this.showDrawer()
50
+ }
51
+
52
+ showDrawer() {
53
+ if (this.edgeValue) {
54
+ this.#toggleEdgePlacementClasses(`${this.placementValue}-edge`, true)
55
+ } else {
56
+ this.#togglePlacementClasses(this.placementValue, true)
57
+ }
58
+
59
+ // Toggle visibility and ARIA attributes of icons
60
+ this.openTarget.classList.add("hidden")
61
+ this.openTarget.setAttribute("aria-hidden", "true")
62
+
63
+ this.closeTarget.classList.remove("hidden")
64
+ this.closeTarget.setAttribute("aria-hidden", "false")
65
+
66
+ // Rest of the method stays same...
67
+ this.sidebarOutlet.element.setAttribute("aria-modal", "true")
68
+ this.sidebarOutlet.element.setAttribute("role", "dialog")
69
+ this.sidebarOutlet.element.removeAttribute("aria-hidden")
70
+
71
+ if (!this.bodyScrollingValue) {
72
+ document.body.classList.add("overflow-hidden")
73
+ }
74
+
75
+ if (this.backdropValue) {
76
+ this.#createBackdrop()
77
+ }
78
+
79
+ this.visible = true
80
+ this.dispatch("show")
81
+ }
82
+
83
+ hideDrawer() {
84
+ if (this.edgeValue) {
85
+ this.#toggleEdgePlacementClasses(`${this.placementValue}-edge`, false)
86
+ } else {
87
+ this.#togglePlacementClasses(this.placementValue, false)
88
+ }
89
+
90
+ // Toggle visibility and ARIA attributes of icons
91
+ this.openTarget.classList.remove("hidden")
92
+ this.openTarget.setAttribute("aria-hidden", "false")
93
+
94
+ this.closeTarget.classList.add("hidden")
95
+ this.closeTarget.setAttribute("aria-hidden", "true")
96
+
97
+ // Rest of the method stays same...
98
+ this.sidebarOutlet.element.setAttribute("aria-hidden", "true")
99
+ this.sidebarOutlet.element.removeAttribute("aria-modal")
100
+ this.sidebarOutlet.element.removeAttribute("role")
101
+
102
+ if (!this.bodyScrollingValue) {
103
+ document.body.classList.remove("overflow-hidden")
104
+ }
105
+
106
+ if (this.backdropValue) {
107
+ this.#removeBackdrop()
108
+ }
109
+
110
+ this.visible = false
111
+ this.dispatch("hide")
112
+ }
113
+
114
+ handleEscapeKey(event) {
115
+ if (event.key === "Escape" && this.visible) {
116
+ this.hideDrawer()
117
+ }
118
+ }
119
+
120
+ #createBackdrop() {
121
+ if (!this.visible) {
122
+ const backdrop = document.createElement("div")
123
+ backdrop.setAttribute("data-drawer-backdrop", "")
124
+ backdrop.classList.add(...this.constructor.classes.backdrop.split(" "))
125
+ backdrop.addEventListener("click", () => this.hideDrawer())
126
+ document.body.appendChild(backdrop)
127
+ }
128
+ }
129
+
130
+ #removeBackdrop() {
131
+ const backdrop = document.querySelector("[data-drawer-backdrop]")
132
+ if (backdrop) {
133
+ backdrop.remove()
134
+ }
135
+ }
136
+
137
+ #getPlacementClasses(placement) {
138
+ const placements = {
139
+ top: {
140
+ base: ["top-0", "left-0", "right-0"],
141
+ active: ["transform-none"],
142
+ inactive: ["-translate-y-full"]
143
+ },
144
+ right: {
145
+ base: ["right-0", "top-0"],
146
+ active: ["transform-none"],
147
+ inactive: ["translate-x-full"]
148
+ },
149
+ bottom: {
150
+ base: ["bottom-0", "left-0", "right-0"],
151
+ active: ["transform-none"],
152
+ inactive: ["translate-y-full"]
153
+ },
154
+ left: {
155
+ base: ["left-0", "top-0"],
156
+ active: ["transform-none"],
157
+ inactive: ["-translate-x-full"]
158
+ },
159
+ "bottom-edge": {
160
+ base: ["left-0", "top-0"],
161
+ active: ["transform-none"],
162
+ inactive: ["translate-y-full", this.edgeOffsetValue]
163
+ }
164
+ }
165
+
166
+ return placements[placement] || placements.left
167
+ }
168
+
169
+ #togglePlacementClasses(placement, show) {
170
+ const classes = this.#getPlacementClasses(placement)
171
+
172
+ if (show) {
173
+ classes.active.forEach(c => this.sidebarOutlet.element.classList.add(c))
174
+ classes.inactive.forEach(c => this.sidebarOutlet.element.classList.remove(c))
175
+ } else {
176
+ classes.active.forEach(c => this.sidebarOutlet.element.classList.remove(c))
177
+ classes.inactive.forEach(c => this.sidebarOutlet.element.classList.add(c))
178
+ }
179
+ }
180
+
181
+ #toggleEdgePlacementClasses(placement, show) {
182
+ this.#togglePlacementClasses(placement, show)
183
+ }
184
+ }
@@ -5,9 +5,10 @@ import NavGridMenuController from "./nav_grid_menu_controller.js"
5
5
  import NavUserSectionController from "./nav_user_section_controller.js"
6
6
  import NavUserLinkController from "./nav_user_link_controller.js"
7
7
  import NavUserController from "./nav_user_controller.js"
8
- import ResourceHeaderController from "./resource_header_controller.js"
8
+ import HeaderController from "./header_controller.js"
9
9
  import SidebarMenuItemController from "./sidebar_menu_item_controller.js"
10
10
  import SidebarMenuController from "./sidebar_menu_controller.js"
11
+ import SidebarController from "./sidebar_controller.js"
11
12
  import HasManyPanelController from "./has_many_panel_controller.js"
12
13
  import NestedResourceFormFieldsController from "./nested_resource_form_fields_controller.js"
13
14
  import ToolbarController from "./toolbar_controller.js"
@@ -29,9 +30,10 @@ export default function (application) {
29
30
  application.register("nav-user-section", NavUserSectionController)
30
31
  application.register("nav-user-link", NavUserLinkController)
31
32
  application.register("nav-user", NavUserController)
32
- application.register("resource-header", ResourceHeaderController)
33
+ application.register("header", HeaderController)
33
34
  application.register("sidebar-menu-item", SidebarMenuItemController)
34
35
  application.register("sidebar-menu", SidebarMenuController)
36
+ application.register("sidebar", SidebarController)
35
37
  application.register("has-many-panel", HasManyPanelController)
36
38
  application.register("nested-resource-form-fields", NestedResourceFormFieldsController)
37
39
  application.register("toolbar", ToolbarController)
@@ -1,8 +1,8 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
2
 
3
- // Connects to data-controller="resource-header"
3
+ // Connects to data-controller="sidebar"
4
4
  export default class extends Controller {
5
5
  connect() {
6
- console.log(`resource-header connected: ${this.element}`)
6
+ console.log(`sidebar connected: ${this.element}`)
7
7
  }
8
8
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutonium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.13
4
+ version: 0.15.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-10 00:00:00.000000000 Z
11
+ date: 2024-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -268,6 +268,20 @@ dependencies:
268
268
  - - ">="
269
269
  - !ruby/object:Gem::Version
270
270
  version: '0'
271
+ - !ruby/object:Gem::Dependency
272
+ name: phlex-slotable
273
+ requirement: !ruby/object:Gem::Requirement
274
+ requirements:
275
+ - - ">="
276
+ - !ruby/object:Gem::Version
277
+ version: '0'
278
+ type: :runtime
279
+ prerelease: false
280
+ version_requirements: !ruby/object:Gem::Requirement
281
+ requirements:
282
+ - - ">="
283
+ - !ruby/object:Gem::Version
284
+ version: '0'
271
285
  - !ruby/object:Gem::Dependency
272
286
  name: rake
273
287
  requirement: !ruby/object:Gem::Requirement
@@ -1364,6 +1378,7 @@ files:
1364
1378
  - lib/plutonium/ui/action_button.rb
1365
1379
  - lib/plutonium/ui/block.rb
1366
1380
  - lib/plutonium/ui/breadcrumbs.rb
1381
+ - lib/plutonium/ui/color_mode_selector.rb
1367
1382
  - lib/plutonium/ui/component/base.rb
1368
1383
  - lib/plutonium/ui/component/behaviour.rb
1369
1384
  - lib/plutonium/ui/component/kit.rb
@@ -1382,6 +1397,11 @@ files:
1382
1397
  - lib/plutonium/ui/form/resource.rb
1383
1398
  - lib/plutonium/ui/form/theme.rb
1384
1399
  - lib/plutonium/ui/frame_navigator_panel.rb
1400
+ - lib/plutonium/ui/layout/base.rb
1401
+ - lib/plutonium/ui/layout/header.rb
1402
+ - lib/plutonium/ui/layout/resource_layout.rb
1403
+ - lib/plutonium/ui/layout/rodauth_layout.rb
1404
+ - lib/plutonium/ui/layout/sidebar.rb
1385
1405
  - lib/plutonium/ui/page/base.rb
1386
1406
  - lib/plutonium/ui/page/edit.rb
1387
1407
  - lib/plutonium/ui/page/index.rb
@@ -1402,7 +1422,7 @@ files:
1402
1422
  - lib/plutonium/ui/table/theme.rb
1403
1423
  - lib/plutonium/version.rb
1404
1424
  - lib/rodauth/features/case_insensitive_login.rb
1405
- - lib/rodauth/loader.rb
1425
+ - lib/rodauth/plugins.rb
1406
1426
  - lib/tasks/create_rodauth_admin.rake
1407
1427
  - package-lock.json
1408
1428
  - package.json
@@ -1420,6 +1440,7 @@ files:
1420
1440
  - src/js/controllers/form_controller.js
1421
1441
  - src/js/controllers/frame_navigator_controller.js
1422
1442
  - src/js/controllers/has_many_panel_controller.js
1443
+ - src/js/controllers/header_controller.js
1423
1444
  - src/js/controllers/interactive_action_form_controller.js
1424
1445
  - src/js/controllers/nav_grid_menu_controller.js
1425
1446
  - src/js/controllers/nav_grid_menu_item_controller.js
@@ -1431,8 +1452,8 @@ files:
1431
1452
  - src/js/controllers/resource_collapse_controller.js
1432
1453
  - src/js/controllers/resource_dismiss_controller.js
1433
1454
  - src/js/controllers/resource_drop_down_controller.js
1434
- - src/js/controllers/resource_header_controller.js
1435
1455
  - src/js/controllers/resource_layout_controller.js
1456
+ - src/js/controllers/sidebar_controller.js
1436
1457
  - src/js/controllers/sidebar_menu_controller.js
1437
1458
  - src/js/controllers/sidebar_menu_item_controller.js
1438
1459
  - src/js/controllers/table_controller.js
File without changes