@smartnet360/svelte-components 0.0.43 → 0.0.44
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.
|
@@ -341,16 +341,21 @@
|
|
|
341
341
|
{/snippet}
|
|
342
342
|
|
|
343
343
|
<div class="chart-component" bind:this={componentElement}>
|
|
344
|
-
<!-- Global Controls
|
|
345
|
-
{#if showGlobalControls
|
|
346
|
-
<GlobalControls
|
|
344
|
+
<!-- Floating Global Controls (renders as fixed position overlay) -->
|
|
345
|
+
{#if showGlobalControls}
|
|
346
|
+
<GlobalControls
|
|
347
|
+
controls={globalControls}
|
|
348
|
+
onUpdate={handleControlsUpdate}
|
|
349
|
+
isExpanded={showControlsPanel}
|
|
350
|
+
onToggle={() => showControlsPanel = !showControlsPanel}
|
|
351
|
+
/>
|
|
347
352
|
{/if}
|
|
348
353
|
|
|
349
354
|
<!-- Always render the main content (tabs or scrollspy) -->
|
|
350
355
|
{#if mode === 'tabs'}
|
|
351
356
|
<!-- Tab Mode with Navigation -->
|
|
352
357
|
<div class="tabs-container">
|
|
353
|
-
<!-- Tab Navigation
|
|
358
|
+
<!-- Tab Navigation -->
|
|
354
359
|
<div class="nav-tabs-wrapper">
|
|
355
360
|
<ul class="nav nav-tabs" role="tablist">
|
|
356
361
|
{#each layout.sections as section, index}
|
|
@@ -369,21 +374,6 @@
|
|
|
369
374
|
</li>
|
|
370
375
|
{/each}
|
|
371
376
|
</ul>
|
|
372
|
-
|
|
373
|
-
<!-- Controls Toggle Button -->
|
|
374
|
-
{#if showGlobalControls}
|
|
375
|
-
<button
|
|
376
|
-
class="btn btn-sm btn-outline-secondary controls-toggle"
|
|
377
|
-
onclick={() => showControlsPanel = !showControlsPanel}
|
|
378
|
-
title={showControlsPanel ? "Hide Controls" : "Show Controls"}
|
|
379
|
-
type="button"
|
|
380
|
-
>
|
|
381
|
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
|
382
|
-
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
|
|
383
|
-
</svg>
|
|
384
|
-
<span class="ms-1">{showControlsPanel ? 'Hide' : 'Show'} Controls</span>
|
|
385
|
-
</button>
|
|
386
|
-
{/if}
|
|
387
377
|
</div>
|
|
388
378
|
|
|
389
379
|
<!-- Tab Content -->
|
|
@@ -402,7 +392,7 @@
|
|
|
402
392
|
{:else if mode === 'scrollspy'}
|
|
403
393
|
<!-- ScrollSpy Mode with Navigation -->
|
|
404
394
|
<div class="scrollspy-container">
|
|
405
|
-
<!-- ScrollSpy Navigation
|
|
395
|
+
<!-- ScrollSpy Navigation -->
|
|
406
396
|
<nav class="scrollspy-nav">
|
|
407
397
|
<div class="nav-wrapper">
|
|
408
398
|
<ul class="nav nav-pills">
|
|
@@ -418,21 +408,6 @@
|
|
|
418
408
|
</li>
|
|
419
409
|
{/each}
|
|
420
410
|
</ul>
|
|
421
|
-
|
|
422
|
-
<!-- Controls Toggle Button -->
|
|
423
|
-
{#if showGlobalControls}
|
|
424
|
-
<button
|
|
425
|
-
class="btn btn-sm btn-outline-secondary controls-toggle"
|
|
426
|
-
onclick={() => showControlsPanel = !showControlsPanel}
|
|
427
|
-
title={showControlsPanel ? "Hide Controls" : "Show Controls"}
|
|
428
|
-
type="button"
|
|
429
|
-
>
|
|
430
|
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
|
431
|
-
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
|
|
432
|
-
</svg>
|
|
433
|
-
<!-- <span class="ms-1">{showControlsPanel ? 'Hide' : 'Show'} Controls</span> -->
|
|
434
|
-
</button>
|
|
435
|
-
{/if}
|
|
436
411
|
</div>
|
|
437
412
|
</nav>
|
|
438
413
|
|
|
@@ -722,11 +697,10 @@
|
|
|
722
697
|
max-height: 100%; /* Constrain to slot */
|
|
723
698
|
}
|
|
724
699
|
|
|
725
|
-
/* Tab navigation wrapper
|
|
700
|
+
/* Tab navigation wrapper */
|
|
726
701
|
.nav-tabs-wrapper {
|
|
727
702
|
display: flex;
|
|
728
703
|
align-items: center;
|
|
729
|
-
gap: 1rem;
|
|
730
704
|
border-bottom: 1px solid #dee2e6;
|
|
731
705
|
}
|
|
732
706
|
|
|
@@ -736,25 +710,7 @@
|
|
|
736
710
|
margin-bottom: 0;
|
|
737
711
|
}
|
|
738
712
|
|
|
739
|
-
|
|
740
|
-
display: flex;
|
|
741
|
-
align-items: center;
|
|
742
|
-
gap: 0.25rem;
|
|
743
|
-
white-space: nowrap;
|
|
744
|
-
border-radius: 0.25rem;
|
|
745
|
-
transition: all 0.2s ease;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
.controls-toggle:hover {
|
|
749
|
-
background-color: #f8f9fa;
|
|
750
|
-
border-color: #6c757d;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
.controls-toggle svg {
|
|
754
|
-
flex-shrink: 0;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
/* ScrollSpy navigation wrapper with toggle button */
|
|
713
|
+
/* ScrollSpy navigation wrapper */
|
|
758
714
|
.scrollspy-nav .nav-wrapper {
|
|
759
715
|
display: flex;
|
|
760
716
|
align-items: center;
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
interface Props {
|
|
7
7
|
controls: GlobalChartControls;
|
|
8
8
|
onUpdate: (controls: GlobalChartControls) => void;
|
|
9
|
+
isExpanded?: boolean;
|
|
10
|
+
onToggle?: () => void;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
let { controls, onUpdate }: Props = $props();
|
|
13
|
+
let { controls, onUpdate, isExpanded = false, onToggle }: Props = $props();
|
|
12
14
|
|
|
13
15
|
function updateControls(updates: Partial<GlobalChartControls>) {
|
|
14
16
|
onUpdate({
|
|
@@ -48,178 +50,377 @@
|
|
|
48
50
|
}
|
|
49
51
|
</script>
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
class="btn-check"
|
|
77
|
-
name="maWindow"
|
|
78
|
-
id="maWindowAuto"
|
|
79
|
-
checked={controls.movingAverage.windowOverride === undefined}
|
|
80
|
-
onchange={() => updateMovingAverage({ windowOverride: undefined })}
|
|
81
|
-
/>
|
|
82
|
-
<label class="btn btn-outline-primary" for="maWindowAuto">Auto</label>
|
|
83
|
-
|
|
84
|
-
<input
|
|
85
|
-
type="radio"
|
|
86
|
-
class="btn-check"
|
|
87
|
-
name="maWindow"
|
|
88
|
-
id="maWindow7"
|
|
89
|
-
checked={controls.movingAverage.windowOverride === 7}
|
|
90
|
-
onchange={() => updateMovingAverage({ windowOverride: 7 })}
|
|
91
|
-
/>
|
|
92
|
-
<label class="btn btn-outline-primary" for="maWindow7">7</label>
|
|
93
|
-
|
|
94
|
-
<input
|
|
95
|
-
type="radio"
|
|
96
|
-
class="btn-check"
|
|
97
|
-
name="maWindow"
|
|
98
|
-
id="maWindow14"
|
|
99
|
-
checked={controls.movingAverage.windowOverride === 14}
|
|
100
|
-
onchange={() => updateMovingAverage({ windowOverride: 14 })}
|
|
101
|
-
/>
|
|
102
|
-
<label class="btn btn-outline-primary" for="maWindow14">14</label>
|
|
53
|
+
<!-- Floating Controls Container -->
|
|
54
|
+
<div class="floating-controls-wrapper">
|
|
55
|
+
<!-- Toggle Button (always visible) -->
|
|
56
|
+
<button
|
|
57
|
+
class="floating-toggle-btn"
|
|
58
|
+
onclick={onToggle}
|
|
59
|
+
title={isExpanded ? "Hide Controls" : "Show Controls"}
|
|
60
|
+
type="button"
|
|
61
|
+
aria-expanded={isExpanded}
|
|
62
|
+
aria-label="Toggle chart controls"
|
|
63
|
+
>
|
|
64
|
+
<svg width="18" height="18" fill="currentColor" viewBox="0 0 16 16">
|
|
65
|
+
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
|
|
66
|
+
</svg>
|
|
67
|
+
<svg
|
|
68
|
+
class="chevron"
|
|
69
|
+
class:expanded={isExpanded}
|
|
70
|
+
width="12"
|
|
71
|
+
height="12"
|
|
72
|
+
fill="currentColor"
|
|
73
|
+
viewBox="0 0 16 16"
|
|
74
|
+
>
|
|
75
|
+
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
|
|
76
|
+
</svg>
|
|
77
|
+
</button>
|
|
103
78
|
|
|
79
|
+
<!-- Controls Panel (expandable) -->
|
|
80
|
+
{#if isExpanded}
|
|
81
|
+
<div class="floating-controls-panel">
|
|
82
|
+
<div class="controls-section">
|
|
83
|
+
<!-- Top Row: Markers and Legend side by side -->
|
|
84
|
+
<div class="controls-row">
|
|
85
|
+
<!-- Markers Toggle -->
|
|
86
|
+
{#if controls.markers}
|
|
87
|
+
<div class="control-group-inline">
|
|
104
88
|
<input
|
|
105
|
-
type="
|
|
89
|
+
type="checkbox"
|
|
106
90
|
class="btn-check"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
onchange={() => updateMovingAverage({ windowOverride: 24 })}
|
|
91
|
+
id="markersToggle"
|
|
92
|
+
checked={controls.markers.enabled}
|
|
93
|
+
onchange={() => updateMarkers({ enabled: !controls.markers!.enabled })}
|
|
111
94
|
/>
|
|
112
|
-
<label class="btn btn-outline-
|
|
95
|
+
<label class="btn btn-outline-secondary btn-sm" for="markersToggle">
|
|
96
|
+
Markers
|
|
97
|
+
</label>
|
|
98
|
+
</div>
|
|
99
|
+
{/if}
|
|
113
100
|
|
|
101
|
+
<!-- Legend Toggle -->
|
|
102
|
+
{#if controls.legend}
|
|
103
|
+
<div class="control-group-inline">
|
|
114
104
|
<input
|
|
115
|
-
type="
|
|
105
|
+
type="checkbox"
|
|
116
106
|
class="btn-check"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
onchange={() => updateMovingAverage({ windowOverride: 30 })}
|
|
107
|
+
id="legendToggle"
|
|
108
|
+
checked={controls.legend.enabled}
|
|
109
|
+
onchange={() => updateLegend({ enabled: !controls.legend!.enabled })}
|
|
121
110
|
/>
|
|
122
|
-
<label class="btn btn-outline-
|
|
111
|
+
<label class="btn btn-outline-secondary btn-sm" for="legendToggle">
|
|
112
|
+
Legend
|
|
113
|
+
</label>
|
|
123
114
|
</div>
|
|
115
|
+
{/if}
|
|
116
|
+
</div>
|
|
124
117
|
|
|
125
|
-
|
|
118
|
+
<!-- Bottom: Moving Average Controls -->
|
|
119
|
+
{#if controls.movingAverage}
|
|
120
|
+
<div class="control-group">
|
|
121
|
+
<!-- MA Enable Toggle Button -->
|
|
126
122
|
<input
|
|
127
123
|
type="checkbox"
|
|
128
124
|
class="btn-check"
|
|
129
|
-
id="
|
|
130
|
-
checked={controls.movingAverage.
|
|
131
|
-
onchange={() => updateMovingAverage({
|
|
125
|
+
id="maToggle"
|
|
126
|
+
checked={controls.movingAverage.enabled}
|
|
127
|
+
onchange={() => updateMovingAverage({ enabled: !controls.movingAverage!.enabled })}
|
|
132
128
|
/>
|
|
133
|
-
<label class="btn btn-outline-primary btn-sm
|
|
134
|
-
|
|
129
|
+
<label class="btn btn-outline-primary btn-sm" for="maToggle">
|
|
130
|
+
Moving Average
|
|
135
131
|
</label>
|
|
132
|
+
|
|
133
|
+
{#if controls.movingAverage.enabled}
|
|
134
|
+
<div class="control-subgroup">
|
|
135
|
+
<!-- MA Window Size -->
|
|
136
|
+
<div class="btn-group btn-group-sm" role="group" aria-label="MA Window">
|
|
137
|
+
<input
|
|
138
|
+
type="radio"
|
|
139
|
+
class="btn-check"
|
|
140
|
+
name="maWindow"
|
|
141
|
+
id="maWindowAuto"
|
|
142
|
+
checked={controls.movingAverage.windowOverride === undefined}
|
|
143
|
+
onchange={() => updateMovingAverage({ windowOverride: undefined })}
|
|
144
|
+
/>
|
|
145
|
+
<label class="btn btn-outline-primary" for="maWindowAuto">Auto</label>
|
|
146
|
+
|
|
147
|
+
<input
|
|
148
|
+
type="radio"
|
|
149
|
+
class="btn-check"
|
|
150
|
+
name="maWindow"
|
|
151
|
+
id="maWindow7"
|
|
152
|
+
checked={controls.movingAverage.windowOverride === 7}
|
|
153
|
+
onchange={() => updateMovingAverage({ windowOverride: 7 })}
|
|
154
|
+
/>
|
|
155
|
+
<label class="btn btn-outline-primary" for="maWindow7">7</label>
|
|
156
|
+
|
|
157
|
+
<input
|
|
158
|
+
type="radio"
|
|
159
|
+
class="btn-check"
|
|
160
|
+
name="maWindow"
|
|
161
|
+
id="maWindow14"
|
|
162
|
+
checked={controls.movingAverage.windowOverride === 14}
|
|
163
|
+
onchange={() => updateMovingAverage({ windowOverride: 14 })}
|
|
164
|
+
/>
|
|
165
|
+
<label class="btn btn-outline-primary" for="maWindow14">14</label>
|
|
166
|
+
|
|
167
|
+
<input
|
|
168
|
+
type="radio"
|
|
169
|
+
class="btn-check"
|
|
170
|
+
name="maWindow"
|
|
171
|
+
id="maWindow24"
|
|
172
|
+
checked={controls.movingAverage.windowOverride === 24}
|
|
173
|
+
onchange={() => updateMovingAverage({ windowOverride: 24 })}
|
|
174
|
+
/>
|
|
175
|
+
<label class="btn btn-outline-primary" for="maWindow24">24</label>
|
|
176
|
+
|
|
177
|
+
<input
|
|
178
|
+
type="radio"
|
|
179
|
+
class="btn-check"
|
|
180
|
+
name="maWindow"
|
|
181
|
+
id="maWindow30"
|
|
182
|
+
checked={controls.movingAverage.windowOverride === 30}
|
|
183
|
+
onchange={() => updateMovingAverage({ windowOverride: 30 })}
|
|
184
|
+
/>
|
|
185
|
+
<label class="btn btn-outline-primary" for="maWindow30">30</label>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<!-- Show Original Toggle Button -->
|
|
189
|
+
<input
|
|
190
|
+
type="checkbox"
|
|
191
|
+
class="btn-check"
|
|
192
|
+
id="showOriginal"
|
|
193
|
+
checked={controls.movingAverage.showOriginal}
|
|
194
|
+
onchange={() => updateMovingAverage({ showOriginal: !controls.movingAverage!.showOriginal })}
|
|
195
|
+
/>
|
|
196
|
+
<label class="btn btn-outline-primary btn-sm ms-2" for="showOriginal">
|
|
197
|
+
Show Original
|
|
198
|
+
</label>
|
|
199
|
+
</div>
|
|
200
|
+
{/if}
|
|
136
201
|
</div>
|
|
137
202
|
{/if}
|
|
138
203
|
</div>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<!-- Markers Toggle -->
|
|
142
|
-
{#if controls.markers}
|
|
143
|
-
<div class="control-group">
|
|
144
|
-
<input
|
|
145
|
-
type="checkbox"
|
|
146
|
-
class="btn-check"
|
|
147
|
-
id="markersToggle"
|
|
148
|
-
checked={controls.markers.enabled}
|
|
149
|
-
onchange={() => updateMarkers({ enabled: !controls.markers!.enabled })}
|
|
150
|
-
/>
|
|
151
|
-
<label class="btn btn-outline-secondary btn-sm" for="markersToggle">
|
|
152
|
-
Markers
|
|
153
|
-
</label>
|
|
154
|
-
</div>
|
|
155
|
-
{/if}
|
|
156
|
-
|
|
157
|
-
<!-- Legend Toggle -->
|
|
158
|
-
{#if controls.legend}
|
|
159
|
-
<div class="control-group">
|
|
160
|
-
<input
|
|
161
|
-
type="checkbox"
|
|
162
|
-
class="btn-check"
|
|
163
|
-
id="legendToggle"
|
|
164
|
-
checked={controls.legend.enabled}
|
|
165
|
-
onchange={() => updateLegend({ enabled: !controls.legend!.enabled })}
|
|
166
|
-
/>
|
|
167
|
-
<label class="btn btn-outline-secondary btn-sm" for="legendToggle">
|
|
168
|
-
Legend
|
|
169
|
-
</label>
|
|
170
|
-
</div>
|
|
171
|
-
{/if}
|
|
172
|
-
|
|
173
|
-
</div>
|
|
204
|
+
</div>
|
|
205
|
+
{/if}
|
|
174
206
|
</div>
|
|
175
207
|
|
|
176
208
|
<style>
|
|
177
|
-
/*
|
|
178
|
-
.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
209
|
+
/* Floating Controls Wrapper - positioned in top-right */
|
|
210
|
+
.floating-controls-wrapper {
|
|
211
|
+
position: fixed;
|
|
212
|
+
top: 0.5rem;
|
|
213
|
+
right: 0.5rem;
|
|
214
|
+
z-index: 1000;
|
|
215
|
+
display: flex;
|
|
216
|
+
flex-direction: column;
|
|
217
|
+
align-items: flex-end;
|
|
218
|
+
gap: 0.5rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* Toggle Button - Always visible */
|
|
222
|
+
.floating-toggle-btn {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
gap: 0.375rem;
|
|
226
|
+
padding: 0.5rem 0.75rem;
|
|
227
|
+
background: rgba(255, 255, 255, 0.95);
|
|
228
|
+
backdrop-filter: blur(10px);
|
|
229
|
+
-webkit-backdrop-filter: blur(10px);
|
|
230
|
+
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
231
|
+
border-radius: 8px;
|
|
232
|
+
box-shadow:
|
|
233
|
+
0 2px 8px rgba(0, 0, 0, 0.08),
|
|
234
|
+
0 4px 16px rgba(0, 0, 0, 0.04);
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
183
237
|
font-size: 0.875rem;
|
|
238
|
+
font-weight: 500;
|
|
239
|
+
color: #495057;
|
|
240
|
+
opacity: 0.5;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.floating-toggle-btn:hover {
|
|
244
|
+
background: rgba(255, 255, 255, 1);
|
|
245
|
+
border-color: rgba(0, 0, 0, 0.12);
|
|
246
|
+
box-shadow:
|
|
247
|
+
0 4px 12px rgba(0, 0, 0, 0.12),
|
|
248
|
+
0 8px 24px rgba(0, 0, 0, 0.08);
|
|
249
|
+
transform: translateY(-1px);
|
|
250
|
+
opacity: 1;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.floating-toggle-btn:active {
|
|
254
|
+
transform: translateY(0);
|
|
255
|
+
box-shadow:
|
|
256
|
+
0 1px 4px rgba(0, 0, 0, 0.08),
|
|
257
|
+
0 2px 8px rgba(0, 0, 0, 0.04);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.floating-toggle-btn .chevron {
|
|
261
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
262
|
+
opacity: 0.6;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.floating-toggle-btn .chevron.expanded {
|
|
266
|
+
transform: rotate(180deg);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Floating Controls Panel - Glass-morphism style */
|
|
270
|
+
.floating-controls-panel {
|
|
271
|
+
background: rgba(255, 255, 255, 0.95);
|
|
272
|
+
backdrop-filter: blur(12px);
|
|
273
|
+
-webkit-backdrop-filter: blur(12px);
|
|
274
|
+
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
275
|
+
border-radius: 12px;
|
|
276
|
+
box-shadow:
|
|
277
|
+
0 4px 16px rgba(0, 0, 0, 0.1),
|
|
278
|
+
0 8px 32px rgba(0, 0, 0, 0.08);
|
|
279
|
+
padding: 1rem;
|
|
280
|
+
min-width: 320px;
|
|
281
|
+
max-width: 480px;
|
|
282
|
+
opacity: 1;
|
|
283
|
+
animation: slideIn 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.floating-controls-panel:hover {
|
|
287
|
+
opacity: 1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
@keyframes slideIn {
|
|
291
|
+
from {
|
|
292
|
+
opacity: 0;
|
|
293
|
+
transform: translateY(-8px);
|
|
294
|
+
}
|
|
295
|
+
to {
|
|
296
|
+
opacity: 1;
|
|
297
|
+
transform: translateY(0);
|
|
298
|
+
}
|
|
184
299
|
}
|
|
185
300
|
|
|
186
301
|
.controls-section {
|
|
302
|
+
display: flex;
|
|
303
|
+
flex-direction: column;
|
|
304
|
+
gap: 1rem;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Horizontal row for Markers and Legend at top */
|
|
308
|
+
.controls-row {
|
|
187
309
|
display: flex;
|
|
188
310
|
align-items: center;
|
|
189
|
-
gap:
|
|
190
|
-
|
|
311
|
+
gap: 0.75rem;
|
|
312
|
+
padding-bottom: 0.75rem;
|
|
313
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
|
191
314
|
}
|
|
192
315
|
|
|
193
|
-
|
|
316
|
+
/* Inline control group for horizontal layout */
|
|
317
|
+
.control-group-inline {
|
|
194
318
|
display: flex;
|
|
195
319
|
align-items: center;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Vertical control group for Moving Average */
|
|
323
|
+
.control-group {
|
|
324
|
+
display: flex;
|
|
325
|
+
flex-direction: column;
|
|
196
326
|
gap: 0.75rem;
|
|
197
327
|
}
|
|
198
328
|
|
|
329
|
+
.control-group > label:first-of-type {
|
|
330
|
+
font-weight: 500;
|
|
331
|
+
}
|
|
332
|
+
|
|
199
333
|
.control-subgroup {
|
|
200
334
|
display: flex;
|
|
335
|
+
flex-wrap: wrap;
|
|
201
336
|
align-items: center;
|
|
202
337
|
gap: 0.5rem;
|
|
203
|
-
padding-left: 0.
|
|
204
|
-
|
|
338
|
+
padding-left: 0.75rem;
|
|
339
|
+
padding-top: 0.5rem;
|
|
340
|
+
border-left: 2px solid rgba(0, 0, 0, 0.08);
|
|
205
341
|
}
|
|
206
342
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
343
|
+
/* Bootstrap button overrides for better integration */
|
|
344
|
+
.floating-controls-panel :global(.btn-sm) {
|
|
345
|
+
padding: 0.375rem 0.75rem;
|
|
346
|
+
font-size: 0.8125rem;
|
|
210
347
|
font-weight: 500;
|
|
348
|
+
border-radius: 6px;
|
|
349
|
+
transition: all 150ms ease;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.floating-controls-panel :global(.btn-outline-primary) {
|
|
353
|
+
border-color: rgba(13, 110, 253, 0.3);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.floating-controls-panel :global(.btn-outline-primary:hover) {
|
|
357
|
+
background-color: rgba(13, 110, 253, 0.1);
|
|
358
|
+
border-color: rgba(13, 110, 253, 0.5);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.floating-controls-panel :global(.btn-check:checked + .btn-outline-primary) {
|
|
362
|
+
background-color: #0d6efd;
|
|
363
|
+
border-color: #0d6efd;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.floating-controls-panel :global(.btn-outline-secondary) {
|
|
367
|
+
border-color: rgba(108, 117, 125, 0.3);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.floating-controls-panel :global(.btn-outline-secondary:hover) {
|
|
371
|
+
background-color: rgba(108, 117, 125, 0.1);
|
|
372
|
+
border-color: rgba(108, 117, 125, 0.5);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.floating-controls-panel :global(.btn-check:checked + .btn-outline-secondary) {
|
|
376
|
+
background-color: #6c757d;
|
|
377
|
+
border-color: #6c757d;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.floating-controls-panel :global(.btn-group) {
|
|
381
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
|
382
|
+
border-radius: 6px;
|
|
383
|
+
overflow: hidden;
|
|
211
384
|
}
|
|
212
385
|
|
|
213
386
|
/* Responsive adjustments */
|
|
214
387
|
@media (max-width: 768px) {
|
|
215
|
-
.controls-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
388
|
+
.floating-controls-wrapper {
|
|
389
|
+
top: 0.5rem;
|
|
390
|
+
right: 0.5rem;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.floating-controls-panel {
|
|
394
|
+
min-width: 280px;
|
|
395
|
+
max-width: calc(100vw - 2rem);
|
|
396
|
+
padding: 0.875rem;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.control-subgroup {
|
|
400
|
+
padding-left: 0.5rem;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* Dark mode support (optional - activate if needed) */
|
|
405
|
+
@media (prefers-color-scheme: dark) {
|
|
406
|
+
.floating-toggle-btn {
|
|
407
|
+
background: rgba(33, 37, 41, 0.95);
|
|
408
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
409
|
+
color: #f8f9fa;
|
|
219
410
|
}
|
|
220
|
-
|
|
411
|
+
|
|
412
|
+
.floating-toggle-btn:hover {
|
|
413
|
+
background: rgba(33, 37, 41, 1);
|
|
414
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.floating-controls-panel {
|
|
418
|
+
background: rgba(33, 37, 41, 0.95);
|
|
419
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
420
|
+
}
|
|
421
|
+
|
|
221
422
|
.control-subgroup {
|
|
222
|
-
|
|
423
|
+
border-left-color: rgba(255, 255, 255, 0.1);
|
|
223
424
|
}
|
|
224
425
|
}
|
|
225
426
|
</style>
|
|
@@ -2,6 +2,8 @@ import type { GlobalChartControls } from './charts.model.js';
|
|
|
2
2
|
interface Props {
|
|
3
3
|
controls: GlobalChartControls;
|
|
4
4
|
onUpdate: (controls: GlobalChartControls) => void;
|
|
5
|
+
isExpanded?: boolean;
|
|
6
|
+
onToggle?: () => void;
|
|
5
7
|
}
|
|
6
8
|
declare const GlobalControls: import("svelte").Component<Props, {}, "">;
|
|
7
9
|
type GlobalControls = ReturnType<typeof GlobalControls>;
|