plutonium 0.16.1 → 0.16.4

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.
@@ -1,7 +1,5 @@
1
1
  # Building a Blog with Plutonium
2
2
 
3
- # Building a Blog with Plutonium
4
-
5
3
  > **Quick Links:**
6
4
  > - 🔍 [Tutorial Demo](https://github.com/radioactive-labs/plutonium-app)
7
5
  > - 📂 [Tutorial Source Code](https://github.com/radioactive-labs/plutonium-app)
@@ -0,0 +1,7 @@
1
+ after_bundle do
2
+ # Run the plutonium install
3
+ rails_command "app:template LOCATION=https://radioactive-labs.github.io/plutonium-core/templates/plutonium.rb"
4
+
5
+ # Enliten!
6
+ rails_command "app:template LOCATION=https://raw.githubusercontent.com/thedumbtechguy/enlitenment/main/template.rb"
7
+ end
@@ -29,7 +29,7 @@ module Pu
29
29
  end
30
30
 
31
31
  def install_dependencies
32
- run "yarn add @radioactive-labs/plutonium flowbite @tailwindcss/forms @tailwindcss/typography flowbite-typography postcss-cli cssnano"
32
+ run "yarn add @radioactive-labs/plutonium flowbite @tailwindcss/forms @tailwindcss/typography flowbite-typography postcss-cli cssnano marked"
33
33
  end
34
34
 
35
35
  def configure_application
@@ -17,14 +17,15 @@ module.exports = {
17
17
  throw Error(`unsupported plugin: ${plugin}: ${(typeof plugin)}`)
18
18
  }
19
19
  })),
20
- theme: plutoniumTailwindConfig.theme,
20
+ theme: plutoniumTailwindConfig.merge(
21
+ {
22
+ },
23
+ plutoniumTailwindConfig.theme
24
+ ),
21
25
  content: [
22
- `${__dirname}/app/**/*.rb`,
23
- `${__dirname}/app/views/**/*.html.erb`,
24
- `${__dirname}/app/helpers/**/*.rb`,
26
+ `${__dirname}/app/**/*.{erb,haml,html,slim,rb}`,
25
27
  `${__dirname}/app/assets/stylesheets/**/*.css`,
26
28
  `${__dirname}/app/javascript/**/*.js`,
27
- `${__dirname}/packages/**/app/**/*.rb`,
28
- `${__dirname}/packages/**/app/views/**/*.html.erb`,
29
+ `${__dirname}/packages/**/app/**/*.{erb,haml,html,slim,rb}`,
29
30
  ].concat(plutoniumTailwindConfig.content),
30
31
  }
@@ -0,0 +1,169 @@
1
+ require "phlexi-menu"
2
+
3
+ module Plutonium
4
+ module UI
5
+ # A sidebar navigation component that renders a max depth of 2 levels
6
+ # Provides collapsible menu sections and is compatible with turbo-permanent
7
+ class SidebarMenu < Phlexi::Menu::Component
8
+ include Plutonium::UI::Component::Behaviour
9
+
10
+ DEFAULT_MAX_DEPTH = 2
11
+
12
+ class Theme < Theme
13
+ def self.theme
14
+ super.merge({
15
+ # Base container styles
16
+ nav: "space-y-2 pb-6 mb-6",
17
+ items_container: "space-y-2",
18
+
19
+ # Item wrapper styles
20
+ item_wrapper: "w-full transition-colors duration-200 ease-in-out",
21
+ item_parent: nil,
22
+
23
+ # Link and button base styles
24
+ item_link: "flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group",
25
+ item_span: "flex items-center p-2 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700",
26
+
27
+ # Label and content styles
28
+ item_label: "flex-1 ml-3 text-left whitespace-nowrap",
29
+
30
+ # Badge styles
31
+ leading_badge: "inline-flex justify-center items-center w-5 h-5 text-xs font-semibold rounded-full text-primary-800 bg-primary-100 dark:bg-primary-200 dark:text-primary-800",
32
+ trailing_badge: "inline-flex justify-center items-center px-2 ml-3 text-sm font-medium text-gray-800 bg-gray-200 rounded-full dark:bg-gray-700 dark:text-gray-300",
33
+
34
+ # Icon styles
35
+ icon_wrapper: "shrink-0 w-6 h-6 flex items-center justify-center",
36
+ icon: "text-gray-400 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white",
37
+
38
+ # Collapse icon styles
39
+ collapse_icon: "w-6 h-6 ml-auto transition-transform duration-200",
40
+ collapse_icon_expanded: "transform rotate-180",
41
+
42
+ # Submenu styles
43
+ sub_items_container: "hidden py-2 space-y-2",
44
+
45
+ # Due to how we use turbo frames, we can't set active states
46
+ active: nil
47
+ })
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ # def render_items(items, depth = 0)
54
+ # return if depth >= @max_depth
55
+ # return if items.empty?
56
+
57
+ # if depth.zero?
58
+ # ul(class: themed(:items_container, depth)) do
59
+ # items.each do |item|
60
+ # render_item_wrapper(item, depth)
61
+ # end
62
+ # end
63
+ # else
64
+ # # Use collapsible rendering for nested levels
65
+ # ul(
66
+ # id: generate_menu_id(items.first&.options&.dig(:parent)),
67
+ # class: themed(:sub_items_container, depth),
68
+ # data: { "resource-collapse-target": "menu" }
69
+ # ) do
70
+ # items.each do |item|
71
+ # render_item_wrapper(item, depth)
72
+ # end
73
+ # end
74
+ # end
75
+ # end
76
+
77
+ def render_item_wrapper(item, depth)
78
+ wrapper_attrs = {
79
+ class: tokens(themed(:item_wrapper, depth)),
80
+ data: {}
81
+ }
82
+
83
+ if nested?(item, depth)
84
+ wrapper_attrs[:data][:controller] = "resource-collapse"
85
+ wrapper_attrs[:data]["resource-collapse-active-class"] = themed(:collapse_icon_expanded)
86
+ wrapper_attrs[:id] = generate_item_id(item)
87
+
88
+ # # Store parent reference for nested items
89
+ # item.items.each { |child| child.options[:parent] = item }
90
+ end
91
+
92
+ li(**wrapper_attrs) do
93
+ render_item_content(item, depth)
94
+ render_items(item.items, depth + 1) if nested?(item, depth)
95
+ end
96
+ end
97
+
98
+ def render_item_content(item, depth)
99
+ if nested?(item, depth)
100
+ render_collapsible_button(item, depth)
101
+ else
102
+ render_item_link(item, depth)
103
+ end
104
+ end
105
+
106
+ # def render_item_link(item, depth)
107
+ # if item.url
108
+ # a(href: item.url, class: themed(:item_link, depth)) do
109
+ # render_item_interior(item, depth)
110
+ # end
111
+ # else
112
+ # span(class: themed(:item_span, depth)) do
113
+ # render_item_interior(item, depth)
114
+ # end
115
+ # end
116
+ # end
117
+
118
+ def render_collapsible_button(item, depth)
119
+ button(
120
+ type: "button",
121
+ class: themed(:item_span, depth),
122
+ data: {
123
+ "resource-collapse-target": "trigger",
124
+ "action": "resource-collapse#toggle"
125
+ },
126
+ aria: {
127
+ controls: generate_menu_id(item),
128
+ expanded: "false"
129
+ }
130
+ ) do
131
+ render_item_interior(item, depth)
132
+ render_collapse_icon(depth)
133
+ end
134
+ end
135
+
136
+ def render_collapse_icon(depth)
137
+ svg(
138
+ class: themed(:collapse_icon, depth),
139
+ fill: "currentColor",
140
+ viewBox: "0 0 20 20",
141
+ xmlns: "http://www.w3.org/2000/svg",
142
+ aria: { hidden: true }
143
+ ) do |s|
144
+ s.path(
145
+ fill_rule: "evenodd",
146
+ d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z",
147
+ clip_rule: "evenodd"
148
+ )
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ def generate_item_id(item)
155
+ "sidebar-menu-item-#{item.label.to_s.parameterize}"
156
+ end
157
+
158
+ def generate_menu_id(item)
159
+ # return nil unless item
160
+ "#{generate_item_id(item)}-menu"
161
+ end
162
+
163
+ # # Override to disable active state for turbo-permanent compatibility
164
+ # def active_class(item, depth = 0)
165
+ # nil
166
+ # end
167
+ end
168
+ end
169
+ end
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- VERSION = "0.16.1"
2
+ VERSION = "0.16.4"
3
3
  NEXT_MAJOR_VERSION = VERSION.split(".").tap { |v|
4
4
  v[1] = v[1].to_i + 1
5
5
  v[2] = 0
data/package-lock.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@radioactive-labs/plutonium",
9
- "version": "0.1.16",
9
+ "version": "0.2.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@hotwired/stimulus": "^3.2.2",
13
13
  "@hotwired/turbo": "^8.0.4",
14
14
  "dompurify": "^3.2.2",
15
15
  "flowbite": "^2.3.0",
16
- "lodash.debounce": "^4.0.8"
16
+ "lodash.debounce": "^4.0.8",
17
+ "marked": "^15.0.3"
17
18
  },
18
19
  "devDependencies": {
19
20
  "@tailwindcss/forms": "^0.5.7",
@@ -4514,10 +4515,9 @@
4514
4515
  "license": "MIT"
4515
4516
  },
4516
4517
  "node_modules/marked": {
4517
- "version": "13.0.3",
4518
- "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz",
4519
- "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==",
4520
- "dev": true,
4518
+ "version": "15.0.3",
4519
+ "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.3.tgz",
4520
+ "integrity": "sha512-Ai0cepvl2NHnTcO9jYDtcOEtVBNVYR31XnEA3BndO7f5As1wzpcOceSUM8FDkNLJNIODcLpDTWay/qQhqbuMvg==",
4521
4521
  "license": "MIT",
4522
4522
  "bin": {
4523
4523
  "marked": "bin/marked.js"
@@ -4600,6 +4600,19 @@
4600
4600
  "dev": true,
4601
4601
  "license": "(MPL-2.0 OR Apache-2.0)"
4602
4602
  },
4603
+ "node_modules/mermaid/node_modules/marked": {
4604
+ "version": "13.0.3",
4605
+ "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz",
4606
+ "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==",
4607
+ "dev": true,
4608
+ "license": "MIT",
4609
+ "bin": {
4610
+ "marked": "bin/marked.js"
4611
+ },
4612
+ "engines": {
4613
+ "node": ">= 18"
4614
+ }
4615
+ },
4603
4616
  "node_modules/micromark-util-character": {
4604
4617
  "version": "2.1.0",
4605
4618
  "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "description": "Core assets for the Plutonium gem",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",
@@ -22,7 +22,8 @@
22
22
  "@hotwired/turbo": "^8.0.4",
23
23
  "dompurify": "^3.2.2",
24
24
  "flowbite": "^2.3.0",
25
- "lodash.debounce": "^4.0.8"
25
+ "lodash.debounce": "^4.0.8",
26
+ "marked": "^15.0.3"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@tailwindcss/forms": "^0.5.7",
@@ -1,6 +1,4 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
- import { Collapse } from 'flowbite';
3
-
4
2
 
5
3
  // Connects to data-controller="resource-collapse"
6
4
  export default class extends Controller {
@@ -9,22 +7,32 @@ export default class extends Controller {
9
7
  connect() {
10
8
  console.log(`resource-collapse connected: ${this.element}`)
11
9
 
12
- this.collapse = new Collapse(this.menuTarget, this.triggerTarget);
13
- }
10
+ // Default to false if the data attribute isn't set
11
+ if (!this.element.hasAttribute('data-visible')) {
12
+ this.element.setAttribute('data-visible', 'false')
13
+ }
14
14
 
15
- disconnect() {
16
- this.collapse = null
15
+ // Set initial state
16
+ this.#updateState()
17
17
  }
18
18
 
19
19
  toggle() {
20
- this.collapse.toggle()
21
- }
22
-
23
- show() {
24
- this.collapse.show()
20
+ const isVisible = this.element.getAttribute('data-visible') === 'true'
21
+ this.element.setAttribute('data-visible', (!isVisible).toString())
22
+ this.#updateState()
25
23
  }
26
24
 
27
- hide() {
28
- this.collapse.hide()
25
+ #updateState() {
26
+ const isVisible = this.element.getAttribute('data-visible') === 'true'
27
+
28
+ if (isVisible) {
29
+ this.menuTarget.classList.remove('hidden')
30
+ this.triggerTarget.setAttribute('aria-expanded', 'true')
31
+ this.dispatch('expand')
32
+ } else {
33
+ this.menuTarget.classList.add('hidden')
34
+ this.triggerTarget.setAttribute('aria-expanded', 'false')
35
+ this.dispatch('collapse')
36
+ }
29
37
  }
30
38
  }
data/tailwind.options.js CHANGED
@@ -248,6 +248,52 @@ export const safelist = [
248
248
  },
249
249
  ]
250
250
 
251
+ export const merge = function (...configs) {
252
+ function isObject(item) {
253
+ return item && typeof item === 'object' && !Array.isArray(item);
254
+ }
255
+
256
+ function mergeArrays(target, source) {
257
+ // Combine arrays and remove duplicates for simple values
258
+ if (target.every(item => typeof item === 'string')) {
259
+ return [...new Set([...target, ...source])];
260
+ }
261
+ // For arrays of objects or complex types, concatenate
262
+ return [...target, ...source];
263
+ }
264
+
265
+ function deepMerge(target, source) {
266
+ if (!isObject(target) || !isObject(source)) {
267
+ return source;
268
+ }
269
+
270
+ const output = { ...target };
271
+
272
+ Object.keys(source).forEach(key => {
273
+ const targetValue = output[key];
274
+ const sourceValue = source[key];
275
+
276
+ if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
277
+ output[key] = mergeArrays(targetValue, sourceValue);
278
+ } else if (isObject(targetValue) && isObject(sourceValue)) {
279
+ // Handle function properties (like theme functions in Tailwind)
280
+ if (typeof targetValue === 'function' || typeof sourceValue === 'function') {
281
+ output[key] = sourceValue;
282
+ } else {
283
+ output[key] = deepMerge(targetValue, sourceValue);
284
+ }
285
+ } else {
286
+ output[key] = sourceValue;
287
+ }
288
+ });
289
+
290
+ return output;
291
+ }
292
+
293
+ // Reduce all configs into a single merged config
294
+ return configs.reduce((merged, config) => deepMerge(merged, config), {});
295
+ }
296
+
251
297
  // // Object.keys(colors).forEach((color) => {
252
298
  // // if (typeof colors[color] === 'object') {
253
299
  // // Object.keys(colors[color]).forEach((shade) => {
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.16.1
4
+ version: 0.16.4
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-12-02 00:00:00.000000000 Z
11
+ date: 2024-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -254,6 +254,20 @@ dependencies:
254
254
  - - ">="
255
255
  - !ruby/object:Gem::Version
256
256
  version: '0'
257
+ - !ruby/object:Gem::Dependency
258
+ name: phlexi-menu
259
+ requirement: !ruby/object:Gem::Requirement
260
+ requirements:
261
+ - - ">="
262
+ - !ruby/object:Gem::Version
263
+ version: '0'
264
+ type: :runtime
265
+ prerelease: false
266
+ version_requirements: !ruby/object:Gem::Requirement
267
+ requirements:
268
+ - - ">="
269
+ - !ruby/object:Gem::Version
270
+ version: '0'
257
271
  - !ruby/object:Gem::Dependency
258
272
  name: tailwind_merge
259
273
  requirement: !ruby/object:Gem::Requirement
@@ -1080,6 +1094,7 @@ files:
1080
1094
  - docs/public/plutonium.png
1081
1095
  - docs/public/site.webmanifest
1082
1096
  - docs/public/templates/base.rb
1097
+ - docs/public/templates/pluton8.rb
1083
1098
  - docs/public/templates/plutonium.rb
1084
1099
  - docs/public/tutorial/plutonium-association-panel.png
1085
1100
  - docs/public/tutorial/plutonium-dashboard.png
@@ -1433,6 +1448,7 @@ files:
1433
1448
  - lib/plutonium/ui/page/show.rb
1434
1449
  - lib/plutonium/ui/page_header.rb
1435
1450
  - lib/plutonium/ui/panel.rb
1451
+ - lib/plutonium/ui/sidebar_menu.rb
1436
1452
  - lib/plutonium/ui/skeleton_table.rb
1437
1453
  - lib/plutonium/ui/table/base.rb
1438
1454
  - lib/plutonium/ui/table/components/pagy_info.rb