panda-core 0.2.3 → 0.2.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,423 +1,89 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fileutils"
4
- require "digest"
5
- require "json"
6
-
7
3
  namespace :panda do
8
4
  namespace :core do
9
5
  namespace :assets do
10
- desc "Compile Panda Core assets for distribution"
6
+ desc "Compile Panda Core assets for development (overwrites panda-core.css)"
11
7
  task :compile do
12
8
  puts "🐼 Compiling Panda Core assets..."
13
- puts "Rails.root: #{Rails.root}"
14
- puts "Working directory: #{Dir.pwd}"
15
9
 
16
10
  # Create output directory
17
- output_dir = Rails.root.join("tmp", "panda_core_assets")
11
+ output_dir = Panda::Core::Engine.root.join("public", "panda-core-assets")
18
12
  FileUtils.mkdir_p(output_dir)
19
13
 
20
- version = Panda::Core::VERSION
21
- puts "Version: #{version}"
22
- puts "Output directory: #{output_dir}"
23
-
24
- # Compile JavaScript bundle
25
- js_bundle = compile_javascript_bundle(version)
26
- js_file = output_dir.join("panda-core-#{version}.js")
27
- File.write(js_file, js_bundle)
28
- puts "✅ JavaScript compiled: #{js_file} (#{File.size(js_file)} bytes)"
29
-
30
- # Compile CSS bundle (for core UI components)
31
- css_bundle = compile_css_bundle(version)
32
- if css_bundle && !css_bundle.strip.empty?
33
- css_file = output_dir.join("panda-core-#{version}.css")
34
- File.write(css_file, css_bundle)
35
- puts "✅ CSS compiled: #{css_file} (#{File.size(css_file)} bytes)"
36
- end
37
-
38
- # Create manifest file
39
- manifest = create_asset_manifest(version)
40
- manifest_file = output_dir.join("manifest.json")
41
- File.write(manifest_file, JSON.pretty_generate(manifest))
42
- puts "✅ Manifest created: #{manifest_file}"
43
-
44
- # Copy assets to public directory for testing
45
- test_asset_dir = Rails.root.join("public", "panda-core-assets")
46
- FileUtils.mkdir_p(test_asset_dir)
47
-
48
- js_file_name = "panda-core-#{version}.js"
49
- css_file_name = "panda-core-#{version}.css"
50
-
51
- # Copy JavaScript file
52
- if File.exist?(output_dir.join(js_file_name))
53
- FileUtils.cp(output_dir.join(js_file_name), test_asset_dir.join(js_file_name))
54
- puts "✅ Copied JavaScript to test location: #{test_asset_dir.join(js_file_name)}"
55
- end
56
-
57
- # Copy CSS file
58
- if File.exist?(output_dir.join(css_file_name))
59
- FileUtils.cp(output_dir.join(css_file_name), test_asset_dir.join(css_file_name))
60
- puts "✅ Copied CSS to test location: #{test_asset_dir.join(css_file_name)}"
61
- end
62
-
63
- # Copy manifest
64
- if File.exist?(output_dir.join("manifest.json"))
65
- FileUtils.cp(output_dir.join("manifest.json"), test_asset_dir.join("manifest.json"))
66
- puts "✅ Copied manifest to test location: #{test_asset_dir.join("manifest.json")}"
67
- end
14
+ # Compile CSS using Tailwind CSS v4
15
+ compile_css_development(output_dir)
68
16
 
69
17
  puts "🎉 Asset compilation complete!"
70
18
  puts "📁 Output directory: #{output_dir}"
71
- puts "📁 Test assets directory: #{test_asset_dir}"
19
+ puts ""
20
+ puts "💡 CSS is served via Rack middleware from Core gem at /panda-core-assets/panda-core.css"
21
+ puts " No need to copy to CMS or other apps - they load it from Core automatically!"
72
22
  end
73
- end
74
- end
75
- end
76
-
77
- private
78
-
79
- def compile_javascript_bundle(version)
80
- puts "Creating Panda Core JavaScript bundle..."
81
-
82
- bundle = []
83
- bundle << "// Panda Core JavaScript Bundle v#{version}"
84
- bundle << "// Compiled: #{Time.now.utc.iso8601}"
85
- bundle << "// Core UI components and authentication"
86
- bundle << ""
87
23
 
88
- # Add Stimulus setup for core
89
- bundle << create_stimulus_setup
24
+ desc "Compile and version Panda Core assets for release"
25
+ task :release do
26
+ puts "🐼 Compiling Panda Core assets for release..."
90
27
 
91
- # Add TailwindCSS Stimulus components
92
- bundle << create_tailwind_components
93
-
94
- # Add core controllers (theme form controller, etc.)
95
- bundle << compile_core_controllers
96
-
97
- # Add initialization
98
- bundle << create_core_init(version)
28
+ # Get version
29
+ require_relative "../panda/core/version"
30
+ version = Panda::Core::VERSION
31
+ puts "Version: #{version}"
99
32
 
100
- puts "✅ Created JavaScript bundle (#{bundle.join("\n").length} chars)"
101
- bundle.join("\n")
102
- end
33
+ # Create output directory
34
+ output_dir = Panda::Core::Engine.root.join("public", "panda-core-assets")
35
+ FileUtils.mkdir_p(output_dir)
103
36
 
104
- def compile_css_bundle(version)
105
- puts "Creating Panda Core CSS bundle..."
37
+ # Compile CSS with versioning
38
+ compile_css_release(output_dir, version)
106
39
 
107
- bundle = []
108
- bundle << "/* Panda Core CSS Bundle v#{version} */"
109
- bundle << "/* Compiled: #{Time.now.utc.iso8601} */"
110
- bundle << ""
40
+ puts "🎉 Release asset compilation complete!"
41
+ puts "📁 Output directory: #{output_dir}"
42
+ puts "📦 Versioned: panda-core-#{version}.css"
43
+ puts "🔗 Symlink: panda-core.css -> panda-core-#{version}.css"
44
+ end
111
45
 
112
- # Add core UI component styles
113
- bundle << "/* Core UI Components */"
114
- bundle << ".panda-core-admin {"
115
- bundle << " font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;"
116
- bundle << "}"
117
- bundle << ""
118
- bundle << ".panda-core-button {"
119
- bundle << " display: inline-flex;"
120
- bundle << " align-items: center;"
121
- bundle << " padding: 0.5rem 1rem;"
122
- bundle << " border-radius: 0.375rem;"
123
- bundle << " font-weight: 500;"
124
- bundle << "}"
125
- bundle << ""
126
- bundle << ".panda-core-container {"
127
- bundle << " padding: 1.5rem;"
128
- bundle << " background: white;"
129
- bundle << " border-radius: 0.5rem;"
130
- bundle << "}"
131
- bundle << ""
46
+ def compile_css_development(output_dir)
47
+ puts "Compiling Tailwind CSS (development mode)..."
132
48
 
133
- puts "✅ Created CSS bundle (#{bundle.join("\n").length} chars)"
134
- bundle.join("\n")
135
- end
49
+ engine_root = Panda::Core::Engine.root
50
+ input_file = engine_root.join("app/assets/tailwind/application.css")
51
+ output_file = output_dir.join("panda-core.css")
136
52
 
137
- def create_stimulus_setup
138
- [
139
- "// Stimulus setup and polyfill for Panda Core",
140
- "window.Stimulus = window.Stimulus || {",
141
- " controllers: new Map(),",
142
- " register: function(name, controller) {",
143
- " this.controllers.set(name, controller);",
144
- " console.log('[Panda Core] Registered controller:', name);",
145
- " // Simple controller connection simulation",
146
- " document.addEventListener('DOMContentLoaded', () => {",
147
- " const elements = document.querySelectorAll(`[data-controller*='${name}']`);",
148
- " elements.forEach(element => {",
149
- " if (controller.connect) {",
150
- " const instance = Object.create(controller);",
151
- " instance.element = element;",
152
- " instance.connect();",
153
- " }",
154
- " });",
155
- " });",
156
- " }",
157
- "};",
158
- "window.pandaCoreStimulus = window.Stimulus;",
159
- ""
160
- ].join("\n")
161
- end
53
+ # Compile directly to unversioned file
54
+ cmd = "bundle exec tailwindcss -i #{input_file} -o #{output_file} --minify"
162
55
 
163
- def create_tailwind_components
164
- [
165
- "// TailwindCSS Stimulus Components (simplified for Core)",
166
- "const Alert = {",
167
- " static: {",
168
- " values: { dismissAfter: Number }",
169
- " },",
170
- " connect() {",
171
- " console.log('[Panda Core] Alert controller connected');",
172
- " const dismissAfter = this.dismissAfterValue || 5000;",
173
- " setTimeout(() => {",
174
- " if (this.element && this.element.remove) {",
175
- " this.element.remove();",
176
- " }",
177
- " }, dismissAfter);",
178
- " },",
179
- " close() {",
180
- " console.log('[Panda Core] Alert closed manually');",
181
- " if (this.element && this.element.remove) {",
182
- " this.element.remove();",
183
- " }",
184
- " }",
185
- "};",
186
- "",
187
- "const Dropdown = {",
188
- " connect() {",
189
- " console.log('[Panda Core] Dropdown controller connected');",
190
- " },",
191
- " toggle() {",
192
- " console.log('[Panda Core] Dropdown toggled');",
193
- " }",
194
- "};",
195
- "",
196
- "const Modal = {",
197
- " connect() {",
198
- " console.log('[Panda Core] Modal controller connected');",
199
- " },",
200
- " open() {",
201
- " console.log('[Panda Core] Modal opened');",
202
- " if (this.element && this.element.showModal) {",
203
- " this.element.showModal();",
204
- " }",
205
- " },",
206
- " close() {",
207
- " console.log('[Panda Core] Modal closed');",
208
- " if (this.element && this.element.close) {",
209
- " this.element.close();",
210
- " }",
211
- " }",
212
- "};",
213
- "",
214
- "const Slideover = {",
215
- " static: {",
216
- " targets: ['dialog'],",
217
- " values: { open: Boolean }",
218
- " },",
219
- " connect() {",
220
- " console.log('[Panda Core] Slideover controller connected');",
221
- " this.dialogTarget = this.element.querySelector('[data-slideover-target=\"dialog\"]') ||",
222
- " this.element.querySelector('dialog');",
223
- " if (this.openValue) {",
224
- " this.open();",
225
- " }",
226
- " },",
227
- " open() {",
228
- " console.log('[Panda Core] Slideover opening');",
229
- " if (this.dialogTarget && this.dialogTarget.showModal) {",
230
- " this.dialogTarget.showModal();",
231
- " }",
232
- " },",
233
- " close() {",
234
- " console.log('[Panda Core] Slideover closing');",
235
- " if (this.dialogTarget) {",
236
- " this.dialogTarget.setAttribute('closing', '');",
237
- " Promise.all(",
238
- " this.dialogTarget.getAnimations ? ",
239
- " this.dialogTarget.getAnimations().map(animation => animation.finished) : []",
240
- " ).then(() => {",
241
- " this.dialogTarget.removeAttribute('closing');",
242
- " if (this.dialogTarget.close) {",
243
- " this.dialogTarget.close();",
244
- " }",
245
- " });",
246
- " }",
247
- " },",
248
- " show() {",
249
- " this.open();",
250
- " },",
251
- " hide() {",
252
- " this.close();",
253
- " },",
254
- " backdropClose(event) {",
255
- " if (event.target.nodeName === 'DIALOG') {",
256
- " this.close();",
257
- " }",
258
- " }",
259
- "};",
260
- "",
261
- "const Toggle = {",
262
- " static: {",
263
- " values: { open: { type: Boolean, default: false } }",
264
- " },",
265
- " connect() {",
266
- " console.log('[Panda Core] Toggle controller connected');",
267
- " },",
268
- " toggle() {",
269
- " this.openValue = !this.openValue;",
270
- " }",
271
- "};",
272
- "",
273
- "const Tabs = {",
274
- " connect() {",
275
- " console.log('[Panda Core] Tabs controller connected');",
276
- " }",
277
- "};",
278
- "",
279
- "const Popover = {",
280
- " connect() {",
281
- " console.log('[Panda Core] Popover controller connected');",
282
- " }",
283
- "};",
284
- "",
285
- "const Autosave = {",
286
- " connect() {",
287
- " console.log('[Panda Core] Autosave controller connected');",
288
- " }",
289
- "};",
290
- "",
291
- "const ColorPreview = {",
292
- " connect() {",
293
- " console.log('[Panda Core] ColorPreview controller connected');",
294
- " }",
295
- "};",
296
- "",
297
- "// Register TailwindCSS components",
298
- "Stimulus.register('alert', Alert);",
299
- "Stimulus.register('dropdown', Dropdown);",
300
- "Stimulus.register('modal', Modal);",
301
- "Stimulus.register('slideover', Slideover);",
302
- "Stimulus.register('toggle', Toggle);",
303
- "Stimulus.register('tabs', Tabs);",
304
- "Stimulus.register('popover', Popover);",
305
- "Stimulus.register('autosave', Autosave);",
306
- "Stimulus.register('color-preview', ColorPreview);",
307
- ""
308
- ].join("\n")
309
- end
310
-
311
- def compile_core_controllers
312
- puts "Compiling Core controllers..."
56
+ if system(cmd)
57
+ puts "✅ CSS compiled: #{output_file} (#{File.size(output_file)} bytes)"
58
+ else
59
+ puts " CSS compilation failed"
60
+ exit 1
61
+ end
62
+ end
313
63
 
314
- bundle = []
315
- bundle << "// Core Controllers"
316
-
317
- # Add theme form controller
318
- bundle << [
319
- "// Theme Form Controller",
320
- "const ThemeFormController = {",
321
- " connect() {",
322
- " console.log('[Panda Core] Theme form controller connected');",
323
- " // Ensure submit button is enabled",
324
- " const submitButton = this.element.querySelector('input[type=\"submit\"], button[type=\"submit\"]');",
325
- " if (submitButton) submitButton.disabled = false;",
326
- " },",
327
- " updateTheme(event) {",
328
- " const newTheme = event.target.value;",
329
- " document.documentElement.dataset.theme = newTheme;",
330
- " console.log('[Panda Core] Theme updated to:', newTheme);",
331
- " }",
332
- "};",
333
- "",
334
- "Stimulus.register('theme-form', ThemeFormController);",
335
- ""
336
- ].join("\n")
64
+ def compile_css_release(output_dir, version)
65
+ puts "Compiling Tailwind CSS (release mode)..."
337
66
 
338
- bundle.join("\n")
339
- end
67
+ engine_root = Panda::Core::Engine.root
68
+ input_file = engine_root.join("app/assets/tailwind/application.css")
69
+ versioned_file = output_dir.join("panda-core-#{version}.css")
340
70
 
341
- def create_core_init(version)
342
- [
343
- "// Panda Core Initialization",
344
- "// Immediate execution marker for CI debugging",
345
- "window.pandaCoreScriptExecuted = true;",
346
- "console.log('[Panda Core] Script execution started');",
347
- "",
348
- "(function() {",
349
- " 'use strict';",
350
- " ",
351
- " try {",
352
- " console.log('[Panda Core] Full JavaScript bundle v#{version} loaded');",
353
- " ",
354
- " // Mark as loaded immediately",
355
- " window.pandaCoreVersion = '#{version}';",
356
- " window.pandaCoreLoaded = true;",
357
- " window.pandaCoreFullBundle = true;",
358
- " window.pandaCoreStimulus = window.Stimulus;",
359
- " ",
360
- " // Also set on document for iframe context issues",
361
- " if (window.document) {",
362
- " window.document.pandaCoreLoaded = true;",
363
- " }",
364
- " ",
365
- " // Initialize on DOM ready",
366
- " if (document.readyState === 'loading') {",
367
- " document.addEventListener('DOMContentLoaded', initializePandaCore);",
368
- " } else {",
369
- " initializePandaCore();",
370
- " }",
371
- " ",
372
- " function initializePandaCore() {",
373
- " console.log('[Panda Core] Initializing controllers...');",
374
- " ",
375
- " // Trigger controller connections for existing elements",
376
- " if (window.Stimulus && window.Stimulus.controllers) {",
377
- " window.Stimulus.controllers.forEach((controller, name) => {",
378
- " const elements = document.querySelectorAll(`[data-controller*='${name}']`);",
379
- " console.log(`[Panda Core] Found ${elements.length} elements for controller: ${name}`);",
380
- " elements.forEach(element => {",
381
- " if (controller.connect) {",
382
- " const instance = Object.create(controller);",
383
- " instance.element = element;",
384
- " // Add target helpers",
385
- " instance.targets = instance.targets || {};",
386
- " controller.connect.call(instance);",
387
- " }",
388
- " });",
389
- " });",
390
- " }",
391
- " }",
392
- " } catch (error) {",
393
- " console.error('[Panda Core] Error during initialization:', error);",
394
- " // Still mark as loaded to prevent test failures",
395
- " window.pandaCoreLoaded = true;",
396
- " window.pandaCoreError = error.message;",
397
- " }",
398
- "})();",
399
- ""
400
- ].join("\n")
401
- end
71
+ # Compile to versioned file
72
+ cmd = "bundle exec tailwindcss -i #{input_file} -o #{versioned_file} --minify"
402
73
 
403
- def create_asset_manifest(version)
404
- output_dir = Rails.root.join("tmp", "panda_core_assets")
74
+ if system(cmd)
75
+ puts "✅ CSS compiled: #{versioned_file} (#{File.size(versioned_file)} bytes)"
405
76
 
406
- files = Dir.glob(output_dir.join("*")).reject { |f| File.basename(f) == "manifest.json" }.map do |file|
407
- {
408
- filename: File.basename(file),
409
- size: File.size(file),
410
- sha256: Digest::SHA256.file(file).hexdigest
411
- }
77
+ # Create/update unversioned symlink
78
+ symlink = output_dir.join("panda-core.css")
79
+ FileUtils.rm_f(symlink) if File.exist?(symlink)
80
+ FileUtils.ln_sf(File.basename(versioned_file), symlink)
81
+ puts "✅ Created symlink: #{symlink} -> #{File.basename(versioned_file)}"
82
+ else
83
+ puts "❌ CSS compilation failed"
84
+ exit 1
85
+ end
86
+ end
87
+ end
412
88
  end
413
-
414
- {
415
- version: version,
416
- compiled_at: Time.now.utc.iso8601,
417
- files: files,
418
- cdn_base_url: "https://github.com/tastybamboo/panda-core/releases/download/v#{version}/",
419
- integrity: {
420
- algorithm: "sha256"
421
- }
422
- }
423
89
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Provide consistent namespacing for Panda tasks
4
+ # Rails auto-generates panda_core:* tasks from the module name,
5
+ # but we want to use panda:core:* for consistency across all Panda gems
6
+
7
+ namespace :panda do
8
+ namespace :core do
9
+ namespace :install do
10
+ desc "Copy migrations from panda-core to application"
11
+ task :migrations do
12
+ Rake::Task["panda_core:install:migrations"].invoke
13
+ end
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tasty Bamboo
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-09-01 00:00:00.000000000 Z
12
+ date: 2025-10-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: importmap-rails
@@ -372,6 +372,8 @@ files:
372
372
  - LICENSE
373
373
  - README.md
374
374
  - Rakefile
375
+ - app/assets/tailwind/application.css
376
+ - app/assets/tailwind/tailwind.config.js
375
377
  - app/builders/panda/core/form_builder.rb
376
378
  - app/components/panda/core/admin/button_component.rb
377
379
  - app/components/panda/core/admin/container_component.html.erb
@@ -393,6 +395,7 @@ files:
393
395
  - app/controllers/panda/core/admin_controller.rb
394
396
  - app/controllers/panda/core/application_controller.rb
395
397
  - app/helpers/panda/core/asset_helper.rb
398
+ - app/helpers/panda/core/sessions_helper.rb
396
399
  - app/javascript/panda/core/application.js
397
400
  - app/javascript/panda/core/controllers/index.js
398
401
  - app/javascript/panda/core/controllers/theme_form_controller.js
@@ -402,6 +405,7 @@ files:
402
405
  - app/models/panda/core/current.rb
403
406
  - app/models/panda/core/user.rb
404
407
  - app/views/layouts/panda/core/admin.html.erb
408
+ - app/views/panda/core/admin/dashboard/_default_content.html.erb
405
409
  - app/views/panda/core/admin/dashboard/show.html.erb
406
410
  - app/views/panda/core/admin/my_profile/edit.html.erb
407
411
  - app/views/panda/core/admin/sessions/new.html.erb
@@ -409,6 +413,9 @@ files:
409
413
  - app/views/panda/core/admin/shared/_flash.html.erb
410
414
  - app/views/panda/core/admin/shared/_sidebar.html.erb
411
415
  - app/views/panda/core/admin/shared/_slideover.html.erb
416
+ - app/views/panda/core/shared/_footer.html.erb
417
+ - app/views/panda/core/shared/_header.html.erb
418
+ - config/importmap.rb
412
419
  - config/initializers/panda_core.rb
413
420
  - config/routes.rb
414
421
  - db/migrate/20250809000001_create_panda_core_users.rb
@@ -418,6 +425,7 @@ files:
418
425
  - lib/generators/panda/core/dev_tools/templates/spec_support_panda_core_helpers.rb
419
426
  - lib/generators/panda/core/dev_tools_generator.rb
420
427
  - lib/generators/panda/core/install_generator.rb
428
+ - lib/generators/panda/core/templates/README
421
429
  - lib/generators/panda/core/templates/initializer.rb
422
430
  - lib/generators/panda/core/templates_generator.rb
423
431
  - lib/panda/core.rb
@@ -442,6 +450,7 @@ files:
442
450
  - lib/tasks/assets.rake
443
451
  - lib/tasks/panda/core/migrations.rake
444
452
  - lib/tasks/panda_core.rake
453
+ - lib/tasks/panda_core_tasks.rake
445
454
  homepage: https://github.com/tastybamboo/panda-core
446
455
  licenses:
447
456
  - BSD-3-Clause