@propbinder/mobile-design 0.0.2 → 0.0.21

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 (123) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +12596 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +3214 -0
  4. package/package.json +39 -12
  5. package/ng-package.json +0 -7
  6. package/src/animations/page-transitions.ts +0 -86
  7. package/src/assets/fonts/Brockmann-Bold.otf +0 -0
  8. package/src/assets/fonts/Brockmann-BoldItalic.otf +0 -0
  9. package/src/assets/fonts/Brockmann-Medium.otf +0 -0
  10. package/src/assets/fonts/Brockmann-MediumItalic.otf +0 -0
  11. package/src/assets/fonts/Brockmann-Regular.otf +0 -0
  12. package/src/assets/fonts/Brockmann-RegularItalic.otf +0 -0
  13. package/src/assets/fonts/Brockmann-SemiBold.otf +0 -0
  14. package/src/assets/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  15. package/src/assets/fonts/Brockmann_desktop_license.pdf +0 -0
  16. package/src/assets/fonts/brockmann-medium-webfont.woff2 +0 -0
  17. package/src/assets/fonts/brockmann-regular-webfont.woff2 +0 -0
  18. package/src/assets/fonts/brockmann-semibold-webfont.woff2 +0 -0
  19. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -83
  20. package/src/components/action-list-item/index.ts +0 -2
  21. package/src/components/app-layout/ds-mobile-app-layout.css +0 -343
  22. package/src/components/app-layout/ds-mobile-app-layout.ts +0 -271
  23. package/src/components/app-layout/index.ts +0 -2
  24. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -130
  25. package/src/components/avatar-with-badge/index.ts +0 -2
  26. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -273
  27. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -110
  28. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -167
  29. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -656
  30. package/src/components/bottom-sheet/index.ts +0 -3
  31. package/src/components/comment/ds-mobile-comment.ts +0 -516
  32. package/src/components/comment/index.ts +0 -2
  33. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  34. package/src/components/contact-list-item/index.ts +0 -2
  35. package/src/components/content/ds-mobile-content.ts +0 -158
  36. package/src/components/content/index.ts +0 -2
  37. package/src/components/ds-mobile-tabs.css +0 -372
  38. package/src/components/ds-mobile-tabs.ts +0 -217
  39. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  40. package/src/components/file-attachment/index.ts +0 -2
  41. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -98
  42. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -514
  43. package/src/components/handbook-detail-modal/index.ts +0 -3
  44. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -130
  45. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -444
  46. package/src/components/handbook-folder/index.ts +0 -4
  47. package/src/components/header-content/ds-mobile-header-content.ts +0 -211
  48. package/src/components/header-content/index.ts +0 -2
  49. package/src/components/index.ts +0 -45
  50. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -269
  51. package/src/components/inline-photo/index.ts +0 -1
  52. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.css +0 -60
  53. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -280
  54. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  55. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -197
  56. package/src/components/interactive-list-item-message/index.ts +0 -2
  57. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.css +0 -70
  58. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -594
  59. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  60. package/src/components/interactive-list-item-post/index.ts +0 -13
  61. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -331
  62. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -173
  63. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -464
  64. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -375
  65. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  66. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  67. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -293
  68. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  69. package/src/components/lightbox/index.ts +0 -22
  70. package/src/components/list-item/ds-mobile-list-item.ts +0 -499
  71. package/src/components/list-item/index.ts +0 -2
  72. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  73. package/src/components/list-item-static/index.ts +0 -2
  74. package/src/components/logo/ds-logo.ts +0 -85
  75. package/src/components/logo/index.ts +0 -2
  76. package/src/components/modal/ds-mobile-modal.css +0 -163
  77. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  78. package/src/components/modal/index.ts +0 -8
  79. package/src/components/page-details/ds-mobile-page-details.css +0 -285
  80. package/src/components/page-details/ds-mobile-page-details.ts +0 -128
  81. package/src/components/page-details/index.ts +0 -2
  82. package/src/components/page-main/ds-mobile-page-main.css +0 -346
  83. package/src/components/page-main/ds-mobile-page-main.ts +0 -331
  84. package/src/components/page-main/index.ts +0 -2
  85. package/src/components/post-card/ds-mobile-post-card.ts +0 -685
  86. package/src/components/post-card/ds-mobile-post-pdf-attachment.ts +0 -124
  87. package/src/components/post-card/index.ts +0 -11
  88. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  89. package/src/components/post-composer/index.ts +0 -2
  90. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -104
  91. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -1273
  92. package/src/components/post-detail-modal/index.ts +0 -9
  93. package/src/components/shared/directives/index.ts +0 -2
  94. package/src/components/shared/directives/long-press.directive.ts +0 -208
  95. package/src/components/shared/index.ts +0 -3
  96. package/src/components/shared/mobile-common.css +0 -94
  97. package/src/components/shared/mobile-page-base.css +0 -315
  98. package/src/components/shared/mobile-page-base.ts +0 -70
  99. package/src/components/swiper/ds-mobile-swiper.ts +0 -123
  100. package/src/components/swiper/index.ts +0 -2
  101. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -132
  102. package/src/components/tab-bar/index.ts +0 -2
  103. package/src/components/tabs/ds-mobile-tabs.css +0 -405
  104. package/src/components/tabs/ds-mobile-tabs.ts +0 -204
  105. package/src/components/tabs/index.ts +0 -2
  106. package/src/pages/community.page.ts +0 -768
  107. package/src/pages/handbook.page.ts +0 -298
  108. package/src/pages/home.page.ts +0 -192
  109. package/src/pages/index.ts +0 -9
  110. package/src/pages/inquiries.example.ts +0 -212
  111. package/src/pages/inquiry-detail.example.css +0 -434
  112. package/src/pages/inquiry-detail.example.ts +0 -416
  113. package/src/pages/mobile-tabs-example.component.ts +0 -146
  114. package/src/pages/post-create.page.ts +0 -311
  115. package/src/pages/post-detail.page.ts +0 -295
  116. package/src/pages/whitelabel-demo.page.ts +0 -548
  117. package/src/public-api.ts +0 -5
  118. package/src/services/user.service.ts +0 -35
  119. package/src/services/whitelabel.service.ts +0 -171
  120. package/src/styles/ionic.css +0 -673
  121. package/tsconfig.lib.json +0 -17
  122. package/tsconfig.lib.prod.json +0 -9
  123. package/tsconfig.spec.json +0 -13
@@ -1,9 +0,0 @@
1
- /**
2
- * Mobile Post Detail Modal Module
3
- *
4
- * Service and component for displaying posts in a modal
5
- */
6
-
7
- export * from './ds-mobile-post-detail-modal';
8
- export * from './ds-mobile-post-detail-modal.service';
9
-
@@ -1,2 +0,0 @@
1
- export * from './long-press.directive';
2
-
@@ -1,208 +0,0 @@
1
- import {
2
- Directive,
3
- Output,
4
- EventEmitter,
5
- HostListener,
6
- Input,
7
- OnDestroy
8
- } from '@angular/core';
9
- import { Haptics, ImpactStyle } from '@capacitor/haptics';
10
-
11
- /**
12
- * DsMobileLongPressDirective
13
- *
14
- * A reusable directive for handling long press interactions on mobile devices.
15
- * Provides haptic feedback and prevents long press when touching interactive elements.
16
- *
17
- * Features:
18
- * - Configurable duration and movement threshold
19
- * - Automatic haptic feedback (with fallback to navigator.vibrate)
20
- * - Excludes interactive elements (buttons, links, inputs)
21
- * - Handles touchmove cancellation
22
- * - Context menu support (right-click on desktop)
23
- *
24
- * @example
25
- * ```html
26
- * <!-- Basic usage -->
27
- * <div dsMobileLongPress (longPress)="handleLongPress()">
28
- * Long press me
29
- * </div>
30
- *
31
- * <!-- Custom duration and threshold -->
32
- * <div
33
- * dsMobileLongPress
34
- * [longPressDuration]="800"
35
- * [moveThreshold]="15"
36
- * [excludeSelectors]="'button, a, .no-longpress'"
37
- * (longPress)="showContextMenu()">
38
- * Custom long press
39
- * </div>
40
- * ```
41
- */
42
- @Directive({
43
- selector: '[dsMobileLongPress]',
44
- standalone: true
45
- })
46
- export class DsMobileLongPressDirective implements OnDestroy {
47
- /**
48
- * Duration in milliseconds to trigger long press
49
- * @default 500
50
- */
51
- @Input() longPressDuration = 500;
52
-
53
- /**
54
- * Maximum movement in pixels before canceling long press
55
- * @default 10
56
- */
57
- @Input() moveThreshold = 10;
58
-
59
- /**
60
- * CSS selectors to exclude from long press detection
61
- * @default 'button, a, input, select, textarea, [role="button"]'
62
- */
63
- @Input() excludeSelectors = 'button, a, input, select, textarea, [role="button"]';
64
-
65
- /**
66
- * Haptic feedback style (Light, Medium, Heavy)
67
- * @default ImpactStyle.Medium
68
- */
69
- @Input() hapticStyle: ImpactStyle = ImpactStyle.Medium;
70
-
71
- /**
72
- * Enable/disable haptic feedback
73
- * @default true
74
- */
75
- @Input() enableHaptics = true;
76
-
77
- /**
78
- * Emits when long press is triggered
79
- */
80
- @Output() longPress = new EventEmitter<void>();
81
-
82
- /**
83
- * Emits when long press starts (timer begins)
84
- */
85
- @Output() longPressStart = new EventEmitter<void>();
86
-
87
- /**
88
- * Emits when long press is cancelled
89
- */
90
- @Output() longPressCancel = new EventEmitter<void>();
91
-
92
- private longPressTimer: any = null;
93
- private longPressTriggered = false;
94
- private touchStartX = 0;
95
- private touchStartY = 0;
96
-
97
- /**
98
- * Handle touch start for long press detection
99
- */
100
- @HostListener('touchstart', ['$event'])
101
- handleTouchStart(event: TouchEvent): void {
102
- // Don't start long press if touching interactive elements
103
- const target = event.target as HTMLElement;
104
- if (target.closest(this.excludeSelectors)) {
105
- return;
106
- }
107
-
108
- this.longPressTriggered = false;
109
- this.touchStartX = event.touches[0].clientX;
110
- this.touchStartY = event.touches[0].clientY;
111
-
112
- // Emit start event
113
- this.longPressStart.emit();
114
-
115
- // Start long press timer
116
- this.longPressTimer = setTimeout(async () => {
117
- this.longPressTriggered = true;
118
- this.longPress.emit();
119
-
120
- // Haptic feedback for long press
121
- if (this.enableHaptics) {
122
- await this.triggerHaptics();
123
- }
124
- }, this.longPressDuration);
125
- }
126
-
127
- /**
128
- * Handle touch end to clear long press timer
129
- */
130
- @HostListener('touchend', ['$event'])
131
- handleTouchEnd(event: TouchEvent): void {
132
- if (this.longPressTimer) {
133
- clearTimeout(this.longPressTimer);
134
- this.longPressTimer = null;
135
-
136
- if (!this.longPressTriggered) {
137
- this.longPressCancel.emit();
138
- }
139
- }
140
-
141
- // Prevent normal click if long press was triggered
142
- if (this.longPressTriggered) {
143
- event.preventDefault();
144
- event.stopPropagation();
145
- this.longPressTriggered = false;
146
- }
147
- }
148
-
149
- /**
150
- * Handle touch move to cancel long press if moved too much
151
- */
152
- @HostListener('touchmove', ['$event'])
153
- handleTouchMove(event: TouchEvent): void {
154
- if (!this.longPressTimer) return;
155
-
156
- const touch = event.touches[0];
157
- const deltaX = Math.abs(touch.clientX - this.touchStartX);
158
- const deltaY = Math.abs(touch.clientY - this.touchStartY);
159
-
160
- // Cancel long press if moved too far
161
- if (deltaX > this.moveThreshold || deltaY > this.moveThreshold) {
162
- clearTimeout(this.longPressTimer);
163
- this.longPressTimer = null;
164
- this.longPressTriggered = false;
165
- this.longPressCancel.emit();
166
- }
167
- }
168
-
169
- /**
170
- * Handle context menu (right-click on desktop) to trigger long press action
171
- */
172
- @HostListener('contextmenu', ['$event'])
173
- handleContextMenu(event: Event): void {
174
- event.preventDefault();
175
- this.longPress.emit();
176
- }
177
-
178
- /**
179
- * Trigger haptic feedback
180
- */
181
- private async triggerHaptics(): Promise<void> {
182
- try {
183
- await Haptics.impact({ style: this.hapticStyle });
184
- } catch {
185
- // Fallback to Web Vibration API if Capacitor Haptics is not available
186
- if ('vibrate' in navigator) {
187
- // Map haptic styles to vibration durations
188
- const vibrationMap = {
189
- [ImpactStyle.Light]: 30,
190
- [ImpactStyle.Medium]: 50,
191
- [ImpactStyle.Heavy]: 80
192
- };
193
- navigator.vibrate(vibrationMap[this.hapticStyle] || 50);
194
- }
195
- }
196
- }
197
-
198
- /**
199
- * Cleanup on destroy
200
- */
201
- ngOnDestroy(): void {
202
- if (this.longPressTimer) {
203
- clearTimeout(this.longPressTimer);
204
- this.longPressTimer = null;
205
- }
206
- }
207
- }
208
-
@@ -1,3 +0,0 @@
1
- export * from './mobile-page-base';
2
- export * from './directives';
3
-
@@ -1,94 +0,0 @@
1
- /**
2
- * Mobile Common Styles
3
- * Shared CSS classes used across multiple mobile components
4
- *
5
- * IMPORTANT: Import this file via styleUrls in components that use these classes.
6
- */
7
-
8
- /* Author Details Container */
9
- .author-details {
10
- display: flex;
11
- flex-direction: column;
12
- gap: 2px;
13
- min-width: 0;
14
- flex: 1;
15
- }
16
-
17
- /* Author Name */
18
- .author-name {
19
- font-family: 'Brockmann', sans-serif;
20
- font-size: var(--font-size-sm);
21
- font-weight: 600;
22
- line-height: 20px;
23
- letter-spacing: -0.3px;
24
- color: var(--color-text-primary, #1a1a1a);
25
- white-space: nowrap;
26
- overflow: hidden;
27
- text-overflow: ellipsis;
28
- }
29
-
30
- /* Author Meta (role, timestamp, etc.) */
31
- .author-meta {
32
- font-family: 'Brockmann', sans-serif;
33
- font-size: var(--font-size-xs);
34
- font-weight: 400;
35
- line-height: 1.2;
36
- letter-spacing: -0.26px;
37
- color: var(--color-text-tertiary, #737373);
38
- display: flex;
39
- align-items: center;
40
- gap: 6px;
41
- }
42
-
43
- .author-meta .separator {
44
- color: var(--color-text-tertiary, #a0a0a0);
45
- }
46
-
47
- /* Variants for lightbox/overlay contexts (white text on dark bg) */
48
- .lightbox-context .author-name,
49
- .overlay-context .author-name {
50
- color: rgba(255, 255, 255, 0.95);
51
- }
52
-
53
- .lightbox-context .author-meta,
54
- .overlay-context .author-meta {
55
- color: rgba(255, 255, 255, 0.7);
56
- }
57
-
58
- .lightbox-context .author-meta .separator,
59
- .overlay-context .author-meta .separator {
60
- color: rgba(255, 255, 255, 0.5);
61
- }
62
-
63
- /* Section Headlines */
64
- .section-headline {
65
- font-size: var(--font-size-sm);
66
- font-weight: 600;
67
- color: var(--text-color-default-primary);
68
- padding: 16px 0;
69
- margin: 0;
70
- letter-spacing: -0.2px;
71
- display: flex;
72
- align-items: center;
73
- gap: 6px;
74
- }
75
-
76
- /* Empty State Text */
77
- .empty-state-title {
78
- font-family: 'Brockmann', sans-serif;
79
- font-size: var(--font-size-base);
80
- font-weight: 600;
81
- line-height: 1.3;
82
- color: var(--text-color-default-primary, #202227);
83
- margin: 0 0 8px 0;
84
- }
85
-
86
- .empty-state-description {
87
- font-family: 'Brockmann', sans-serif;
88
- font-size: var(--font-size-sm);
89
- font-weight: 400;
90
- line-height: 1.4;
91
- color: var(--text-color-default-secondary, #545B66);
92
- margin: 0;
93
- }
94
-
@@ -1,315 +0,0 @@
1
- /* ============================================
2
- MOBILE PAGE BASE STYLES
3
- Shared styles for mobile pages
4
- Import this in your page component's styleUrls
5
- ============================================ */
6
-
7
- /* ============================================
8
- ION-CONTENT
9
- ============================================ */
10
-
11
- ion-content {
12
- --background: transparent;
13
- --padding-top: 0;
14
- --padding-start: 0;
15
- --padding-end: 0;
16
- --padding-bottom: 0;
17
- border-radius: 24px 24px 0 0;
18
- overflow: hidden;
19
- }
20
-
21
- ion-content::part(scroll) {
22
- -webkit-overflow-scrolling: touch;
23
- overscroll-behavior-y: none;
24
- }
25
-
26
- /* Desktop/Tablet adjustments */
27
- @media (min-width: 768px) {
28
- ion-content {
29
- border-radius: 16px 16px 0 0;
30
- }
31
- }
32
-
33
- /* ============================================
34
- ION-HEADER
35
- ============================================ */
36
-
37
- ion-header {
38
- background: transparent;
39
- box-shadow: none;
40
- height: 72px;
41
- min-height: 72px;
42
- }
43
-
44
- ion-header ion-toolbar {
45
- --background: transparent;
46
- --border-width: 0;
47
- --box-shadow: none;
48
- --padding-top: 0;
49
- --padding-bottom: 0;
50
- --padding-start: 0;
51
- --padding-end: 0;
52
- --min-height: 72px;
53
- height: 100%;
54
- min-height: 72px;
55
- padding: 0;
56
- }
57
-
58
- ion-header ion-toolbar::part(native) {
59
- height: 100%;
60
- min-height: 72px;
61
- padding: 0;
62
- }
63
-
64
- ion-header ion-toolbar .toolbar-container {
65
- height: 100%;
66
- min-height: 72px;
67
- display: flex;
68
- align-items: center;
69
- }
70
-
71
- ion-header ion-toolbar .toolbar-container > * {
72
- height: 100%;
73
- display: flex;
74
- align-items: center;
75
- padding-left: 0;
76
- padding-right: 0;
77
- }
78
-
79
- /* Hide header on desktop when using ds-mobile-tabs top bar */
80
- @media (min-width: 768px) {
81
- ion-header {
82
- display: none;
83
- height: auto;
84
- }
85
- }
86
-
87
- /* ============================================
88
- REFRESHER
89
- ============================================ */
90
-
91
- ion-refresher {
92
- z-index: 0;
93
- }
94
-
95
- ion-refresher-content {
96
- --color: white;
97
- }
98
-
99
- /* ============================================
100
- HEADER VARIANTS
101
- ============================================ */
102
-
103
- .header-home {
104
- display: flex;
105
- align-items: center;
106
- justify-content: space-between;
107
- padding: 12px 16px;
108
- background: var(--color-brand-secondary);
109
- position: relative;
110
- height: 100%;
111
- }
112
-
113
- .header-home__title {
114
- position: absolute;
115
- left: 50%;
116
- transform: translateX(-50%) translateY(-100%);
117
- font-size: var(--font-size-base);
118
- font-weight: 600;
119
- color: white;
120
- opacity: 0;
121
- transition: transform 0.6s ease, opacity 0.6s ease;
122
- margin: 0;
123
- padding: 0;
124
- --color: white;
125
- }
126
-
127
- .header-home__actions {
128
- display: flex;
129
- align-items: center;
130
- gap: 8px;
131
- }
132
-
133
- .logomark {
134
- height: 28px;
135
- width: auto;
136
- flex-shrink: 0;
137
- }
138
-
139
- /* Condensed header - hidden by default on mobile */
140
- ion-header[collapse="condense"] {
141
- display: none;
142
- }
143
-
144
- /* Show title in top header when scrolled past condensed header */
145
- .header-scrolled .header-home__title {
146
- opacity: 1;
147
- transform: translateX(-50%) translateY(0);
148
- }
149
-
150
- @media (min-width: 768px) {
151
- .header-home {
152
- padding: 16px 24px;
153
- }
154
-
155
- .logomark {
156
- height: 32px;
157
- }
158
-
159
- /* Hide title on desktop - not needed */
160
- .header-home__title {
161
- display: none;
162
- }
163
-
164
- /* Hide condensed header on desktop */
165
- ion-header[collapse="condense"] {
166
- display: none;
167
- }
168
- }
169
-
170
- /* ============================================
171
- EXPANDABLE HEADER
172
- ============================================ */
173
-
174
- .header-expandable {
175
- background: var(--color-brand-secondary);
176
- padding: 24px 16px;
177
- color: white;
178
- position: sticky;
179
- top: 0;
180
- z-index: 10;
181
- }
182
-
183
- .header-expandable-inner {
184
- display: flex;
185
- flex-direction: column;
186
- gap: 16px;
187
- max-width: 640px;
188
- margin: 0 auto;
189
- }
190
-
191
- @media (min-width: 768px) {
192
- .header-expandable {
193
- padding: 32px var(--content-padding-md);
194
- }
195
- }
196
-
197
- @media (min-width: 992px) {
198
- .header-expandable {
199
- padding-left: var(--content-padding-lg);
200
- padding-right: var(--content-padding-lg);
201
- }
202
- }
203
-
204
- @media (min-width: 1440px) {
205
- .header-expandable {
206
- padding-left: var(--content-padding-xl);
207
- padding-right: var(--content-padding-xl);
208
- }
209
- }
210
-
211
- @media (min-width: 1768px) {
212
- .header-expandable {
213
- padding-left: var(--content-padding-2xl);
214
- padding-right: var(--content-padding-2xl);
215
- }
216
- }
217
-
218
- @media (min-width: 1920px) {
219
- .header-expandable {
220
- padding-left: var(--content-padding-3xl);
221
- padding-right: var(--content-padding-3xl);
222
- }
223
- }
224
-
225
- .header-expandable__text {
226
- margin-bottom: 0;
227
- }
228
-
229
- .header-expandable__title {
230
- font-size: var(--font-size-2xl);
231
- font-weight: 600;
232
- color: white;
233
- margin: 0 0 8px 0;
234
- }
235
-
236
- @media (min-width: 768px) {
237
- .header-expandable__title {
238
- font-size: var(--font-size-3xl);
239
- }
240
- }
241
-
242
- .header-expandable__subtitle {
243
- font-size: var(--font-size-sm);
244
- font-weight: 400;
245
- color: white;
246
- opacity: 0.85;
247
- margin: 0;
248
- }
249
-
250
- @media (min-width: 768px) {
251
- .header-expandable__subtitle {
252
- font-size: var(--font-size-base);
253
- }
254
- }
255
-
256
- /* ============================================
257
- CONTENT WRAPPER
258
- ============================================ */
259
-
260
- .content-wrapper {
261
- position: relative;
262
- z-index: 10;
263
- background: var(--color-background-neutral-primary);
264
- border-radius: 24px 24px 0 0;
265
- padding: 0;
266
- }
267
-
268
- @media (min-width: 768px) {
269
- .content-wrapper {
270
- border-radius: 16px 16px 0 0;
271
- width: 100%;
272
- }
273
- }
274
-
275
- .content-inner {
276
- padding: 20px 16px;
277
- }
278
-
279
- @media (min-width: 768px) {
280
- .content-inner {
281
- padding: 32px var(--content-padding-md);
282
- max-width: calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));
283
- margin: 0 auto;
284
- width: 100%;
285
- }
286
- }
287
-
288
- @media (min-width: 992px) {
289
- .content-inner {
290
- padding: 32px var(--content-padding-lg);
291
- max-width: calc(var(--content-max-width-md) + (var(--content-padding-md) * 2));
292
- }
293
- }
294
-
295
- @media (min-width: 1440px) {
296
- .content-inner {
297
- padding: 32px var(--content-padding-lg);
298
- max-width: calc(var(--content-max-width-lg) + (var(--content-padding-lg) * 2));
299
- }
300
- }
301
-
302
- @media (min-width: 1768px) {
303
- .content-inner {
304
- /* Keep xl max-width, only increase padding */
305
- padding: 32px var(--content-padding-2xl);
306
- }
307
- }
308
-
309
- @media (min-width: 1920px) {
310
- .content-inner {
311
- /* Keep xl max-width, only increase padding */
312
- padding: 32px var(--content-padding-3xl);
313
- }
314
- }
315
-
@@ -1,70 +0,0 @@
1
- import { input, computed, Directive } from '@angular/core';
2
-
3
- /**
4
- * Content width preset values
5
- * - 'narrow' - 640px max width (reading content)
6
- * - 'standard' - 1024px max width (default)
7
- * - 'wide' - 1440px max width (dashboards)
8
- * - 'full' - 100% width (no max)
9
- */
10
- export type ContentWidth = 'narrow' | 'standard' | 'wide' | 'full';
11
-
12
- /**
13
- * MobilePageBase
14
- *
15
- * Shared base class for mobile page components (ds-mobile-page-main, ds-mobile-page-details).
16
- * Provides consistent content width control across all page types.
17
- *
18
- * **Padding Strategy:**
19
- * - All pages use 20px horizontal padding globally
20
- * - For tappable lists, use negative margins (e.g., margin: 0 -8px) to create full-width sections
21
- * - This approach simplifies padding management and provides consistency
22
- *
23
- * @internal This is a base class and should not be used directly.
24
- */
25
- @Directive()
26
- export abstract class MobilePageBase {
27
- /**
28
- * Maximum content width (desktop only)
29
- *
30
- * **Options:**
31
- * - `'narrow'` (640px) - For reading content, forms
32
- * - `'standard'` (1024px) - Default for most pages
33
- * - `'wide'` (1440px) - For dashboards, tables
34
- * - `'full'` - No max-width constraint
35
- *
36
- * **Note:** Only applies on desktop (>= 768px). Mobile is always full width.
37
- *
38
- * @default 'standard'
39
- *
40
- * @example
41
- * ```html
42
- * <!-- Narrow reading layout -->
43
- * <ds-mobile-page-main title="Article" contentWidth="narrow">
44
- *
45
- * <!-- Wide dashboard -->
46
- * <ds-mobile-page-main title="Dashboard" contentWidth="wide">
47
- * ```
48
- */
49
- contentWidth = input<ContentWidth>('standard');
50
-
51
- /**
52
- * Resolved max-width value (computed)
53
- * Maps preset values to pixel values
54
- *
55
- * @internal
56
- */
57
- protected maxWidthValue = computed(() => {
58
- const w = this.contentWidth();
59
-
60
- const widthMap: Record<ContentWidth, string> = {
61
- 'narrow': '640px',
62
- 'standard': '1024px',
63
- 'wide': '1440px',
64
- 'full': '100%'
65
- };
66
-
67
- return widthMap[w];
68
- });
69
- }
70
-