rails_modal_manager 1.0.34 → 1.0.35

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65672101a104fe19120730ac9bfefc6add2e1e0f3e592b9741c9f83d7ed3a46a
4
- data.tar.gz: 00b57148c22f0ac9b18fea481813facf1020be7f7e36d979faadfc91cbcb4234
3
+ metadata.gz: 72c527ec9681356bcf4c0f3b9fd1d8c337a31764a79ff1a57801ec28bdc1cfef
4
+ data.tar.gz: c333ca2a7be2f4140f76e81ad5ad4d028524a90c7155001cfec70b4f064d511a
5
5
  SHA512:
6
- metadata.gz: c50a37a75ea2cb8a16edddcd2cd8ad394d8d6e859fa9d735943b64dd71f7509344f17ba9460678eaa9cdaeb89d14828b6678ec617c8cf2d799c2abd31d176b6b
7
- data.tar.gz: 56b5d8e7e1be002a2d926ae4e18e5d7a73ffd0a8518d1714a08cc42dc141ccd0ed17138b4791b68949fc8728e13ea028391a13bd59accf8530d9b905871d3c3f
6
+ metadata.gz: 0dd3f943bd13e8227f971ae76a52438b505a7412a684bd50c5ffcd56249dc6c4d38216b5f1bd690f640731c478a9fb7ec68ef857f8df697d7c02748f6487eccc
7
+ data.tar.gz: 5b3198913d43cdf59998c1602babdd3bbbae1ecb4976983a218a664d8ca57f0946e686fdfe51ec2e1c6c3a6b02397f199a4a96494812cedc9387ab4338d29681
@@ -23,6 +23,16 @@
23
23
  --rmm-header-text: #1e293b;
24
24
  --rmm-header-height: 56px;
25
25
 
26
+ /* Header - Depth Colors (Parent/Child/Grandchild) */
27
+ --rmm-header-bg-depth-0: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
+ --rmm-header-text-depth-0: #ffffff;
29
+ --rmm-header-bg-depth-1: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
30
+ --rmm-header-text-depth-1: #ffffff;
31
+ --rmm-header-bg-depth-2: linear-gradient(135deg, #fc4a1a 0%, #f7b733 100%);
32
+ --rmm-header-text-depth-2: #ffffff;
33
+ --rmm-header-bg-depth-3: linear-gradient(135deg, #ee0979 0%, #ff6a00 100%);
34
+ --rmm-header-text-depth-3: #ffffff;
35
+
26
36
  /* Footer */
27
37
  --rmm-footer-bg: #f8fafc;
28
38
  --rmm-footer-border: rgba(0, 0, 0, 0.1);
@@ -110,6 +120,16 @@
110
120
  --rmm-header-border: rgba(255, 255, 255, 0.1);
111
121
  --rmm-header-text: #f1f5f9;
112
122
 
123
+ /* Header - Depth Colors (Dark Theme) */
124
+ --rmm-header-bg-depth-0: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
125
+ --rmm-header-text-depth-0: #ffffff;
126
+ --rmm-header-bg-depth-1: linear-gradient(135deg, #0d7377 0%, #14a085 100%);
127
+ --rmm-header-text-depth-1: #ffffff;
128
+ --rmm-header-bg-depth-2: linear-gradient(135deg, #c0392b 0%, #d68910 100%);
129
+ --rmm-header-text-depth-2: #ffffff;
130
+ --rmm-header-bg-depth-3: linear-gradient(135deg, #a0185e 0%, #c0392b 100%);
131
+ --rmm-header-text-depth-3: #ffffff;
132
+
113
133
  --rmm-footer-bg: #0f172a;
114
134
  --rmm-footer-border: rgba(255, 255, 255, 0.1);
115
135
  --rmm-footer-text: #e2e8f0;
@@ -219,13 +239,18 @@
219
239
  }
220
240
 
221
241
  /* Size variants */
222
- .rmm-modal.rmm-size-fit { width: auto; min-width: 150px; }
223
- .rmm-modal.rmm-size-xss { width: 20%; min-width: 200px; }
224
- .rmm-modal.rmm-size-xs { width: 30%; min-width: 280px; }
225
- .rmm-modal.rmm-size-sm { width: 40%; min-width: 360px; }
226
- .rmm-modal.rmm-size-md { width: 50%; min-width: 480px; }
227
- .rmm-modal.rmm-size-lg { width: 60%; min-width: 600px; }
228
- .rmm-modal.rmm-size-xl { width: 70%; min-width: 720px; }
242
+ /* Modal Size Options (PC)
243
+ - width: 브라우저 크기 대비 비율
244
+ - min-width: 1920px 기준 비율, 단 브라우저보다 커지지 않도록 min() 사용
245
+ - max-width: 브라우저보다 커지지 않도록 제한 (20px 여백 확보)
246
+ */
247
+ .rmm-modal.rmm-size-fit { width: auto; min-width: min(200px, calc(100vw - 40px)); max-width: calc(100vw - 40px); }
248
+ .rmm-modal.rmm-size-xss { width: 20%; min-width: min(384px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 20% */
249
+ .rmm-modal.rmm-size-xs { width: 30%; min-width: min(576px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 30% */
250
+ .rmm-modal.rmm-size-sm { width: 40%; min-width: min(768px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 40% */
251
+ .rmm-modal.rmm-size-md { width: 50%; min-width: min(960px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 50% */
252
+ .rmm-modal.rmm-size-lg { width: 60%; min-width: min(1152px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 60% */
253
+ .rmm-modal.rmm-size-xl { width: 70%; min-width: min(1344px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 70% */
229
254
  .rmm-modal.rmm-size-full,
230
255
  .rmm-modal.rmm-size-full.rmm-active,
231
256
  .rmm-modal.rmm-size-full.rmm-position-center,
@@ -470,6 +495,154 @@
470
495
  white-space: nowrap;
471
496
  }
472
497
 
498
+ /* ============================================
499
+ Modal Depth-based Header Colors
500
+ ============================================ */
501
+ /* Depth 0 - Parent Modal (Purple gradient) */
502
+ .rmm-modal.rmm-depth-0 .rmm-header {
503
+ background: var(--rmm-header-bg-depth-0);
504
+ border-bottom-color: rgba(255, 255, 255, 0.2);
505
+ }
506
+
507
+ .rmm-modal.rmm-depth-0 .rmm-header-title {
508
+ color: var(--rmm-header-text-depth-0);
509
+ }
510
+
511
+ .rmm-modal.rmm-depth-0 .rmm-header-btn {
512
+ color: var(--rmm-header-text-depth-0);
513
+ }
514
+
515
+ .rmm-modal.rmm-depth-0 .rmm-header-btn:hover {
516
+ background: rgba(255, 255, 255, 0.15);
517
+ }
518
+
519
+ .rmm-modal.rmm-depth-0 .rmm-header-btn.rmm-close-btn:hover {
520
+ background: rgba(239, 68, 68, 0.9);
521
+ }
522
+
523
+ .rmm-modal.rmm-depth-0 .rmm-drag-handle {
524
+ color: var(--rmm-header-text-depth-0);
525
+ opacity: 0.6;
526
+ }
527
+
528
+ /* Depth 1 - Child Modal (Green gradient) */
529
+ .rmm-modal.rmm-depth-1 .rmm-header {
530
+ background: var(--rmm-header-bg-depth-1);
531
+ border-bottom-color: rgba(255, 255, 255, 0.2);
532
+ }
533
+
534
+ .rmm-modal.rmm-depth-1 .rmm-header-title {
535
+ color: var(--rmm-header-text-depth-1);
536
+ }
537
+
538
+ .rmm-modal.rmm-depth-1 .rmm-header-btn {
539
+ color: var(--rmm-header-text-depth-1);
540
+ }
541
+
542
+ .rmm-modal.rmm-depth-1 .rmm-header-btn:hover {
543
+ background: rgba(255, 255, 255, 0.15);
544
+ }
545
+
546
+ .rmm-modal.rmm-depth-1 .rmm-header-btn.rmm-close-btn:hover {
547
+ background: rgba(239, 68, 68, 0.9);
548
+ }
549
+
550
+ .rmm-modal.rmm-depth-1 .rmm-drag-handle {
551
+ color: var(--rmm-header-text-depth-1);
552
+ opacity: 0.6;
553
+ }
554
+
555
+ /* Depth 2 - Grandchild Modal (Orange gradient) */
556
+ .rmm-modal.rmm-depth-2 .rmm-header {
557
+ background: var(--rmm-header-bg-depth-2);
558
+ border-bottom-color: rgba(255, 255, 255, 0.2);
559
+ }
560
+
561
+ .rmm-modal.rmm-depth-2 .rmm-header-title {
562
+ color: var(--rmm-header-text-depth-2);
563
+ }
564
+
565
+ .rmm-modal.rmm-depth-2 .rmm-header-btn {
566
+ color: var(--rmm-header-text-depth-2);
567
+ }
568
+
569
+ .rmm-modal.rmm-depth-2 .rmm-header-btn:hover {
570
+ background: rgba(255, 255, 255, 0.15);
571
+ }
572
+
573
+ .rmm-modal.rmm-depth-2 .rmm-header-btn.rmm-close-btn:hover {
574
+ background: rgba(239, 68, 68, 0.9);
575
+ }
576
+
577
+ .rmm-modal.rmm-depth-2 .rmm-drag-handle {
578
+ color: var(--rmm-header-text-depth-2);
579
+ opacity: 0.6;
580
+ }
581
+
582
+ /* Depth 3+ - Deep nested modals (Pink/Red gradient) */
583
+ .rmm-modal.rmm-depth-3 .rmm-header,
584
+ .rmm-modal.rmm-depth-4 .rmm-header,
585
+ .rmm-modal.rmm-depth-5 .rmm-header {
586
+ background: var(--rmm-header-bg-depth-3);
587
+ border-bottom-color: rgba(255, 255, 255, 0.2);
588
+ }
589
+
590
+ .rmm-modal.rmm-depth-3 .rmm-header-title,
591
+ .rmm-modal.rmm-depth-4 .rmm-header-title,
592
+ .rmm-modal.rmm-depth-5 .rmm-header-title {
593
+ color: var(--rmm-header-text-depth-3);
594
+ }
595
+
596
+ .rmm-modal.rmm-depth-3 .rmm-header-btn,
597
+ .rmm-modal.rmm-depth-4 .rmm-header-btn,
598
+ .rmm-modal.rmm-depth-5 .rmm-header-btn {
599
+ color: var(--rmm-header-text-depth-3);
600
+ }
601
+
602
+ .rmm-modal.rmm-depth-3 .rmm-header-btn:hover,
603
+ .rmm-modal.rmm-depth-4 .rmm-header-btn:hover,
604
+ .rmm-modal.rmm-depth-5 .rmm-header-btn:hover {
605
+ background: rgba(255, 255, 255, 0.15);
606
+ }
607
+
608
+ .rmm-modal.rmm-depth-3 .rmm-header-btn.rmm-close-btn:hover,
609
+ .rmm-modal.rmm-depth-4 .rmm-header-btn.rmm-close-btn:hover,
610
+ .rmm-modal.rmm-depth-5 .rmm-header-btn.rmm-close-btn:hover {
611
+ background: rgba(239, 68, 68, 0.9);
612
+ }
613
+
614
+ .rmm-modal.rmm-depth-3 .rmm-drag-handle,
615
+ .rmm-modal.rmm-depth-4 .rmm-drag-handle,
616
+ .rmm-modal.rmm-depth-5 .rmm-drag-handle {
617
+ color: var(--rmm-header-text-depth-3);
618
+ opacity: 0.6;
619
+ }
620
+
621
+ /* ============================================
622
+ Custom Header Colors (via CSS variables)
623
+ Usage: style="--rmm-custom-header-bg: #3b82f6; --rmm-custom-header-text: #ffffff;"
624
+ ============================================ */
625
+ .rmm-modal.rmm-custom-header .rmm-header {
626
+ background: var(--rmm-custom-header-bg, var(--rmm-header-bg));
627
+ border-bottom-color: var(--rmm-custom-header-border, var(--rmm-header-border));
628
+ }
629
+
630
+ .rmm-modal.rmm-custom-header .rmm-header-title {
631
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
632
+ }
633
+
634
+ .rmm-modal.rmm-custom-header .rmm-header-btn {
635
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
636
+ }
637
+
638
+ .rmm-modal.rmm-custom-header .rmm-header-btn:hover {
639
+ background: var(--rmm-custom-header-btn-hover, rgba(255, 255, 255, 0.15));
640
+ }
641
+
642
+ .rmm-modal.rmm-custom-header .rmm-drag-handle {
643
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
644
+ }
645
+
473
646
  /* Size controls dropdown */
474
647
  .rmm-size-controls {
475
648
  position: relative;
@@ -1388,6 +1561,58 @@
1388
1561
  }
1389
1562
  }
1390
1563
 
1564
+ /* MD, LG, XL 사이즈는 768px이 아닌 각자의 min-width 기준으로 모바일 스타일 적용
1565
+ - MD: 960px 이상에서는 데스크톱 스타일 유지
1566
+ - LG: 1152px 이상에서는 데스크톱 스타일 유지
1567
+ - XL: 1344px 이상에서는 데스크톱 스타일 유지
1568
+ */
1569
+ @media (min-width: 769px) {
1570
+ /* MD: 769px ~ 960px 범위에서도 min-width 적용 */
1571
+ .rmm-modal.rmm-size-md {
1572
+ width: 50% !important;
1573
+ min-width: min(960px, calc(100vw - 40px)) !important;
1574
+ max-width: calc(100vw - 40px) !important;
1575
+ left: 50% !important;
1576
+ right: auto !important;
1577
+ }
1578
+ .rmm-modal.rmm-size-md.rmm-position-center {
1579
+ transform: translate(-50%, -50%) !important;
1580
+ }
1581
+ .rmm-modal.rmm-size-md.rmm-position-center.rmm-active {
1582
+ transform: translate(-50%, -50%) scale(1) !important;
1583
+ }
1584
+
1585
+ /* LG: 769px ~ 1152px 범위에서도 min-width 적용 */
1586
+ .rmm-modal.rmm-size-lg {
1587
+ width: 60% !important;
1588
+ min-width: min(1152px, calc(100vw - 40px)) !important;
1589
+ max-width: calc(100vw - 40px) !important;
1590
+ left: 50% !important;
1591
+ right: auto !important;
1592
+ }
1593
+ .rmm-modal.rmm-size-lg.rmm-position-center {
1594
+ transform: translate(-50%, -50%) !important;
1595
+ }
1596
+ .rmm-modal.rmm-size-lg.rmm-position-center.rmm-active {
1597
+ transform: translate(-50%, -50%) scale(1) !important;
1598
+ }
1599
+
1600
+ /* XL: 769px ~ 1344px 범위에서도 min-width 적용 */
1601
+ .rmm-modal.rmm-size-xl {
1602
+ width: 70% !important;
1603
+ min-width: min(1344px, calc(100vw - 40px)) !important;
1604
+ max-width: calc(100vw - 40px) !important;
1605
+ left: 50% !important;
1606
+ right: auto !important;
1607
+ }
1608
+ .rmm-modal.rmm-size-xl.rmm-position-center {
1609
+ transform: translate(-50%, -50%) !important;
1610
+ }
1611
+ .rmm-modal.rmm-size-xl.rmm-position-center.rmm-active {
1612
+ transform: translate(-50%, -50%) scale(1) !important;
1613
+ }
1614
+ }
1615
+
1391
1616
  /* ============================================
1392
1617
  Drag Handle
1393
1618
  ============================================ */
@@ -37,6 +37,10 @@ export default class extends Controller {
37
37
  confirmClose: { type: Boolean, default: false },
38
38
  confirmCloseMessage: { type: String, default: "정말 닫으시겠습니까?" },
39
39
  mobileDefaultMaximized: { type: Boolean, default: false },
40
+ // Custom header colors
41
+ headerBg: String, // Custom header background color (e.g., "#3b82f6" or "linear-gradient(135deg, #667eea, #764ba2)")
42
+ headerText: String, // Custom header text color (e.g., "#ffffff")
43
+ headerBorder: String, // Custom header border color (e.g., "#2563eb")
40
44
  }
41
45
 
42
46
  connect() {
@@ -328,6 +332,9 @@ export default class extends Controller {
328
332
  // Apply initial size and position
329
333
  this.applyStyles()
330
334
 
335
+ // Apply depth class for visual hierarchy (parent/child/grandchild)
336
+ this.applyDepthClass()
337
+
331
338
  // Start animation
332
339
  requestAnimationFrame(() => {
333
340
  modal.classList.add('rmm-active')
@@ -340,6 +347,46 @@ export default class extends Controller {
340
347
  })
341
348
  }
342
349
 
350
+ /**
351
+ * Apply depth-based CSS class for visual hierarchy
352
+ * Depth 0 (root): rmm-depth-0
353
+ * Depth 1 (child): rmm-depth-1
354
+ * Depth 2 (grandchild): rmm-depth-2
355
+ * Depth 3+ (great-grandchild): rmm-depth-3
356
+ *
357
+ * Also applies custom header colors if specified via data attributes
358
+ */
359
+ applyDepthClass() {
360
+ const modal = this.element
361
+ const modalId = this.effectiveModalId
362
+ const depth = modalStore.getModalDepth(modalId)
363
+
364
+ // Remove existing depth classes
365
+ modal.classList.remove('rmm-depth-0', 'rmm-depth-1', 'rmm-depth-2', 'rmm-depth-3')
366
+
367
+ // Check for custom header colors
368
+ const hasCustomHeader = this.hasHeaderBgValue || this.hasHeaderTextValue || this.hasHeaderBorderValue
369
+
370
+ if (hasCustomHeader) {
371
+ // Apply custom header colors via CSS variables
372
+ modal.classList.add('rmm-custom-header')
373
+
374
+ if (this.hasHeaderBgValue && this.headerBgValue) {
375
+ modal.style.setProperty('--rmm-custom-header-bg', this.headerBgValue)
376
+ }
377
+ if (this.hasHeaderTextValue && this.headerTextValue) {
378
+ modal.style.setProperty('--rmm-custom-header-text', this.headerTextValue)
379
+ }
380
+ if (this.hasHeaderBorderValue && this.headerBorderValue) {
381
+ modal.style.setProperty('--rmm-custom-header-border', this.headerBorderValue)
382
+ }
383
+ } else {
384
+ // Apply depth class (only if no custom header colors)
385
+ const depthClass = `rmm-depth-${Math.min(depth, 3)}`
386
+ modal.classList.add(depthClass)
387
+ }
388
+ }
389
+
343
390
  hideModal(callback) {
344
391
  const modal = this.element
345
392
  const overlay = this.getOverlay()
@@ -23,14 +23,16 @@ export const MODAL_CONSTANTS = {
23
23
  export const CASCADE_OFFSET = { x: 30, y: 30 };
24
24
 
25
25
  // Size configurations (matching React version)
26
+ // min-width: 1920px 기준 비율 적용 (브라우저가 작아져도 이 이하로 줄어들지 않음)
27
+ // max-width는 CSS에서 calc(100vw - 40px)로 처리하여 브라우저 벗어남 방지
26
28
  export const SIZE_CONFIG = {
27
- fit: { width: 'auto', minWidth: '150px', height: 'auto' },
28
- xss: { width: '20%', minWidth: '200px', height: 'auto' },
29
- xs: { width: '30%', minWidth: '280px', height: 'auto' },
30
- sm: { width: '40%', minWidth: '360px', height: 'auto' },
31
- md: { width: '50%', minWidth: '480px', height: 'auto' },
32
- lg: { width: '60%', minWidth: '600px', height: 'auto' },
33
- xl: { width: '70%', minWidth: '720px', height: 'auto' },
29
+ fit: { width: 'auto', minWidth: '200px', height: 'auto' },
30
+ xss: { width: '20%', minWidth: '384px', height: 'auto' }, // 1920 * 20%
31
+ xs: { width: '30%', minWidth: '576px', height: 'auto' }, // 1920 * 30%
32
+ sm: { width: '40%', minWidth: '768px', height: 'auto' }, // 1920 * 40%
33
+ md: { width: '50%', minWidth: '960px', height: 'auto' }, // 1920 * 50%
34
+ lg: { width: '60%', minWidth: '1152px', height: 'auto' }, // 1920 * 60%
35
+ xl: { width: '70%', minWidth: '1344px', height: 'auto' }, // 1920 * 70%
34
36
  full: { width: '100%', minWidth: '100%', height: '100%' },
35
37
  };
36
38
 
@@ -490,6 +492,20 @@ class ModalStore {
490
492
  return [...this.getModalChain(config.parentModalId), modalId];
491
493
  }
492
494
 
495
+ /**
496
+ * Get the depth of a modal in the parent-child hierarchy
497
+ * Root modals (no parent) have depth 0, children have depth 1, grandchildren depth 2, etc.
498
+ * @param {string} modalId - The modal ID to get depth for
499
+ * @returns {number} The depth level (0 for root, 1 for child, 2 for grandchild, etc.)
500
+ */
501
+ getModalDepth(modalId) {
502
+ const config = this.activeModals[modalId];
503
+ if (!config || !config.parentModalId) {
504
+ return 0;
505
+ }
506
+ return 1 + this.getModalDepth(config.parentModalId);
507
+ }
508
+
493
509
  getModalGroupSize(modalId) {
494
510
  const rootId = this.getRootModal(modalId);
495
511
  const descendants = this.getAllDescendants(rootId);
@@ -42,6 +42,9 @@
42
42
  footer_buttons: Array - Footer buttons (default: [])
43
43
  extra_class: String - Additional CSS classes (default: "")
44
44
  extra_data: Hash - Additional data attributes (default: {})
45
+ header_bg: String - Custom header background (e.g., "#3b82f6" or "linear-gradient(135deg, #667eea, #764ba2)")
46
+ header_text: String - Custom header text color (e.g., "#ffffff")
47
+ header_border: String - Custom header border color (e.g., "#2563eb")
45
48
  %>
46
49
  <%
47
50
  # Default values
@@ -86,6 +89,9 @@
86
89
  extra_class ||= ""
87
90
  extra_data ||= {}
88
91
  mobile_default_maximized ||= false
92
+ header_bg ||= nil
93
+ header_text ||= nil
94
+ header_border ||= nil
89
95
 
90
96
  # Build CSS classes
91
97
  modal_classes = ["rmm-modal", "rmm-size-#{size}", "rmm-position-#{position}"]
@@ -122,6 +128,9 @@
122
128
  data_attrs[:rmm_modal_persistent_id_value] = persistent_id if persistent_id
123
129
  data_attrs[:rmm_modal_max_width_value] = max_width if max_width
124
130
  data_attrs[:rmm_modal_max_height_value] = max_height if max_height
131
+ data_attrs[:rmm_modal_header_bg_value] = header_bg if header_bg
132
+ data_attrs[:rmm_modal_header_text_value] = header_text if header_text
133
+ data_attrs[:rmm_modal_header_border_value] = header_border if header_border
125
134
  data_attrs.merge!(extra_data)
126
135
  %>
127
136
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsModalManager
4
- VERSION = "1.0.34"
4
+ VERSION = "1.0.35"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_modal_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.34
4
+ version: 1.0.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - reshacs