@cdc/data-bite 4.24.2 → 4.24.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.
- package/dist/cdcdatabite.js +9158 -5287
- package/examples/sankey/data-2.json +6 -0
- package/examples/sankey/data.json +6 -0
- package/examples/sankey-example-data.json +110 -0
- package/index.html +9 -2
- package/package.json +3 -3
- package/src/CdcDataBite.tsx +85 -13
- package/src/components/EditorPanel.jsx +10 -79
- package/src/components/GradientBite.jsx +23 -0
- package/src/scss/bite.scss +16 -11
- package/src/scss/editor-panel.scss +1 -1
- package/src/scss/kpi.scss +68 -0
- package/src/scss/main.scss +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "data-bite",
|
|
3
|
+
"data": [
|
|
4
|
+
{
|
|
5
|
+
"Text": "Number of EMS Responses",
|
|
6
|
+
"Value": "467136"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"dataBite": "",
|
|
10
|
+
"dataFunction": "Max",
|
|
11
|
+
"dataColumn": "Value",
|
|
12
|
+
"bitePosition": "Left",
|
|
13
|
+
"biteFontSize": 24,
|
|
14
|
+
"fontSize": "medium",
|
|
15
|
+
"biteBody": "",
|
|
16
|
+
"imageData": {
|
|
17
|
+
"display": "none",
|
|
18
|
+
"url": "",
|
|
19
|
+
"alt": "",
|
|
20
|
+
"options": []
|
|
21
|
+
},
|
|
22
|
+
"dataFormat": {
|
|
23
|
+
"roundToPlace": "",
|
|
24
|
+
"commas": true,
|
|
25
|
+
"prefix": "",
|
|
26
|
+
"suffix": ""
|
|
27
|
+
},
|
|
28
|
+
"biteStyle": "gradient",
|
|
29
|
+
"filters": [],
|
|
30
|
+
"subtext": "",
|
|
31
|
+
"title": "Total number of suicide EMS responses",
|
|
32
|
+
"theme": "theme-blue",
|
|
33
|
+
"shadow": false,
|
|
34
|
+
"visual": {
|
|
35
|
+
"border": false,
|
|
36
|
+
"accent": false,
|
|
37
|
+
"background": false,
|
|
38
|
+
"hideBackgroundColor": false,
|
|
39
|
+
"borderColorTheme": false
|
|
40
|
+
},
|
|
41
|
+
"general": {
|
|
42
|
+
"isCompactStyle": false
|
|
43
|
+
},
|
|
44
|
+
"showTitle": true,
|
|
45
|
+
"enableTooltips": true,
|
|
46
|
+
"enableStoryNodes": true,
|
|
47
|
+
"legend": {
|
|
48
|
+
"hide": true
|
|
49
|
+
},
|
|
50
|
+
"heights": {
|
|
51
|
+
"vertical": 300,
|
|
52
|
+
"horizontal": 369.59999999999997
|
|
53
|
+
},
|
|
54
|
+
"xAxis": {
|
|
55
|
+
"anchors": [],
|
|
56
|
+
"type": "categorical",
|
|
57
|
+
"showTargetLabel": true,
|
|
58
|
+
"targetLabel": "Target",
|
|
59
|
+
"hideAxis": true,
|
|
60
|
+
"hideLabel": true,
|
|
61
|
+
"hideTicks": true,
|
|
62
|
+
"size": "59",
|
|
63
|
+
"tickRotation": 0,
|
|
64
|
+
"min": "",
|
|
65
|
+
"max": "",
|
|
66
|
+
"labelColor": "#333",
|
|
67
|
+
"tickLabelColor": "#333",
|
|
68
|
+
"tickColor": "#333",
|
|
69
|
+
"numTicks": "",
|
|
70
|
+
"labelOffset": 180,
|
|
71
|
+
"axisPadding": 0,
|
|
72
|
+
"target": 0,
|
|
73
|
+
"dataKey": "Disposition",
|
|
74
|
+
"label": "X Axis Example Label"
|
|
75
|
+
},
|
|
76
|
+
"series": [
|
|
77
|
+
{
|
|
78
|
+
"dataKey": "Type of Treatment",
|
|
79
|
+
"type": "Bar"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"dataKey": "Final Outcome",
|
|
83
|
+
"type": "Bar"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"dataKey": "Number of Patients",
|
|
87
|
+
"type": "Bar"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"table": {
|
|
91
|
+
"label": "Sankey Data Table",
|
|
92
|
+
"expanded": true,
|
|
93
|
+
"limitHeight": false,
|
|
94
|
+
"height": "",
|
|
95
|
+
"caption": "",
|
|
96
|
+
"showDownloadUrl": true,
|
|
97
|
+
"showDataTableLink": true,
|
|
98
|
+
"indexLabel": "Disposition",
|
|
99
|
+
"download": true,
|
|
100
|
+
"showVertical": true,
|
|
101
|
+
"show": true
|
|
102
|
+
},
|
|
103
|
+
"footnotes": "**Counts fewer than 20 are suppressed for confidentiality reasons.<br></br><br><strong>Footnotes</strong></br> 2022 Biospatial Emergency Medical Services (EMS) records. Biospatial combines electronic EMS patient care records with other electronic healthcare data. EMS records are generated by medics to document prehospital care and collected according to the National EMS Information System (NEMSIS) standard. Currently the Biospatial platform receives EMS data from 24 full states and 18 partial states.",
|
|
104
|
+
"visualizationType": "Sankey",
|
|
105
|
+
"validated": 4.23,
|
|
106
|
+
"runtime": {
|
|
107
|
+
"uniqueId": 1706633133063,
|
|
108
|
+
"editorErrorMessage": ""
|
|
109
|
+
}
|
|
110
|
+
}
|
package/index.html
CHANGED
|
@@ -6,15 +6,22 @@
|
|
|
6
6
|
<style>
|
|
7
7
|
body {
|
|
8
8
|
margin: 0;
|
|
9
|
+
border-top: none !important;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.cdc-open-viz-module {
|
|
13
|
+
min-height: 100vh;
|
|
9
14
|
}
|
|
10
15
|
</style>
|
|
16
|
+
<link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/contrib/libs/bootstrap/latest/css/bootstrap.min.css?_=39423" />
|
|
17
|
+
<link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/4.0/assets/css/app.min.css?_=39423" />
|
|
11
18
|
</head>
|
|
12
19
|
<body>
|
|
13
20
|
<!-- Original -->
|
|
14
|
-
<div class="react-container" data-config="/examples/example-
|
|
21
|
+
<!-- <div class="react-container" data-config="/examples/sankey-example-data.json"></div> -->
|
|
15
22
|
|
|
16
23
|
<!-- DATA PRESENTATION GALLERY: https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/data_bites.html#examples -->
|
|
17
|
-
|
|
24
|
+
<div class="react-container" data-config="/examples/gallery/calculated-average.json"></div>
|
|
18
25
|
<!-- <div class="react-container" data-config="/examples/gallery/calculated-with-pic.json"></div> -->
|
|
19
26
|
<div class="react-container" data-config="/examples/gallery/max-value.json"></div>
|
|
20
27
|
<!-- <div class="react-container" data-config="/examples/gallery/sum-of-data.json"></div> -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/data-bite",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.4",
|
|
4
4
|
"description": "React component for displaying a single piece of data in a card module",
|
|
5
5
|
"moduleName": "CdcDataBite",
|
|
6
6
|
"main": "dist/cdcdatabite",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@cdc/core": "^4.24.
|
|
29
|
+
"@cdc/core": "^4.24.4",
|
|
30
30
|
"chroma": "0.0.1",
|
|
31
31
|
"chroma-js": "^2.1.0",
|
|
32
32
|
"html-react-parser": "^3.0.8",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"react": "^18.2.0",
|
|
40
40
|
"react-dom": "^18.2.0"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "1843b4632140d582af6a87606374cbd4fe25ad5c"
|
|
43
43
|
}
|
package/src/CdcDataBite.tsx
CHANGED
|
@@ -10,6 +10,8 @@ import EditorPanel from './components/EditorPanel'
|
|
|
10
10
|
import Loading from '@cdc/core/components/Loading'
|
|
11
11
|
import Title from '@cdc/core/components/ui/Title'
|
|
12
12
|
import CircleCallout from './components/CircleCallout'
|
|
13
|
+
import GradientBite from './components/GradientBite'
|
|
14
|
+
import Layout from '@cdc/core/components/Layout'
|
|
13
15
|
|
|
14
16
|
// external
|
|
15
17
|
import ResizeObserver from 'resize-observer-polyfill'
|
|
@@ -447,13 +449,75 @@ const CdcDataBite = (props: CdcDataBiteProps) => {
|
|
|
447
449
|
break
|
|
448
450
|
}
|
|
449
451
|
|
|
450
|
-
const
|
|
452
|
+
const missingRequiredSections = () => {
|
|
453
|
+
//Whether to show error message if something is required to show a data-bite and isn't filled in
|
|
454
|
+
return false
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const Error = () => {
|
|
458
|
+
const styles = {
|
|
459
|
+
position: 'absolute',
|
|
460
|
+
background: 'white',
|
|
461
|
+
zIndex: '999',
|
|
462
|
+
height: '100vh',
|
|
463
|
+
width: '100%',
|
|
464
|
+
display: 'flex',
|
|
465
|
+
justifyContent: 'center',
|
|
466
|
+
alignItems: 'center',
|
|
467
|
+
gridArea: 'content'
|
|
468
|
+
}
|
|
469
|
+
return (
|
|
470
|
+
<section className='waiting' style={styles}>
|
|
471
|
+
<section className='waiting-container'>
|
|
472
|
+
<h3>Error With Configuration</h3>
|
|
473
|
+
<p>{config.runtime.editorErrorMessage}</p>
|
|
474
|
+
</section>
|
|
475
|
+
</section>
|
|
476
|
+
)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const Confirm = () => {
|
|
480
|
+
const styles = {
|
|
481
|
+
position: 'absolute',
|
|
482
|
+
background: 'white',
|
|
483
|
+
zIndex: '999',
|
|
484
|
+
height: '100vh',
|
|
485
|
+
width: '100%',
|
|
486
|
+
display: 'flex',
|
|
487
|
+
justifyContent: 'center',
|
|
488
|
+
alignItems: 'center',
|
|
489
|
+
gridArea: 'content'
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return (
|
|
493
|
+
<section className='waiting' style={styles}>
|
|
494
|
+
<section className='waiting-container'>
|
|
495
|
+
<h3>Finish Configuring</h3>
|
|
496
|
+
<p>Set all required options to the left and confirm below to display a preview of the chart.</p>
|
|
497
|
+
<button
|
|
498
|
+
className='btn'
|
|
499
|
+
style={{ margin: '1em auto' }}
|
|
500
|
+
disabled={missingRequiredSections()}
|
|
501
|
+
onClick={e => {
|
|
502
|
+
e.preventDefault()
|
|
503
|
+
updateConfig({ ...config, newViz: false })
|
|
504
|
+
}}
|
|
505
|
+
>
|
|
506
|
+
I'm Done
|
|
507
|
+
</button>
|
|
508
|
+
</section>
|
|
509
|
+
</section>
|
|
510
|
+
)
|
|
511
|
+
}
|
|
451
512
|
|
|
513
|
+
const showBite = undefined !== dataColumn && undefined !== dataFunction
|
|
452
514
|
body = (
|
|
453
515
|
<>
|
|
454
516
|
{isEditor && <EditorPanel />}
|
|
455
|
-
<
|
|
456
|
-
<div className={
|
|
517
|
+
<Layout.Responsive isEditor={isEditor}>
|
|
518
|
+
<div className={`${contentClasses.join(' ')}`}>
|
|
519
|
+
{!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
|
|
520
|
+
{(!config.dataColumn || !config.dataFunction) && <Confirm />}
|
|
457
521
|
<Title config={config} title={title} isDashboard={isDashboard} classes={['bite-header', `${config.theme}`]} />
|
|
458
522
|
<div className={`bite ${biteClasses.join(' ')}`}>
|
|
459
523
|
<div className={`bite-content-container ${contentClasses.join(' ')}`}>
|
|
@@ -495,21 +559,28 @@ const CdcDataBite = (props: CdcDataBiteProps) => {
|
|
|
495
559
|
</div>
|
|
496
560
|
</div>
|
|
497
561
|
{link && link}
|
|
498
|
-
</
|
|
562
|
+
</Layout.Responsive>
|
|
499
563
|
</>
|
|
500
564
|
)
|
|
501
565
|
}
|
|
502
566
|
|
|
503
|
-
let classNames = ['cove', 'cdc-open-viz-module', 'type-data-bite', currentViewport, config.theme, 'font-' + config.fontSize]
|
|
504
|
-
if (isEditor) {
|
|
505
|
-
classNames.push('is-editor')
|
|
506
|
-
}
|
|
507
|
-
|
|
508
567
|
return (
|
|
509
568
|
<Context.Provider value={{ config, updateConfig, loading, data: config.data, setParentConfig, isDashboard }}>
|
|
510
|
-
|
|
511
|
-
{
|
|
512
|
-
|
|
569
|
+
{biteStyle !== 'gradient' && (
|
|
570
|
+
<Layout.VisualizationWrapper ref={outerContainerRef} config={config} isEditor={isEditor} showEditorPanel={config?.showEditorPanel}>
|
|
571
|
+
{body}
|
|
572
|
+
</Layout.VisualizationWrapper>
|
|
573
|
+
)}
|
|
574
|
+
{'gradient' === biteStyle && (
|
|
575
|
+
<Layout.VisualizationWrapper ref={outerContainerRef} config={config} isEditor={isEditor} showEditorPanel={config?.showEditorPanel}>
|
|
576
|
+
{isEditor && <EditorPanel />}
|
|
577
|
+
<Layout.Responsive isEditor={isEditor}>
|
|
578
|
+
{!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
|
|
579
|
+
{(!config.dataColumn || !config.dataFunction) && <Confirm />}
|
|
580
|
+
<GradientBite label={config.title} value={calculateDataBite()} />
|
|
581
|
+
</Layout.Responsive>
|
|
582
|
+
</Layout.VisualizationWrapper>
|
|
583
|
+
)}
|
|
513
584
|
</Context.Provider>
|
|
514
585
|
)
|
|
515
586
|
}
|
|
@@ -535,7 +606,8 @@ export const BITE_LOCATIONS = {
|
|
|
535
606
|
split: 'Split Graphic and Message',
|
|
536
607
|
title: 'Value above Message',
|
|
537
608
|
body: 'Value before Message',
|
|
538
|
-
end: 'Value after Message'
|
|
609
|
+
end: 'Value after Message',
|
|
610
|
+
gradient: 'Gradient'
|
|
539
611
|
}
|
|
540
612
|
|
|
541
613
|
export const IMAGE_POSITION_LEFT = 'Left'
|
|
@@ -8,7 +8,9 @@ import WarningImage from '@cdc/core/assets/icon-warning-circle.svg'
|
|
|
8
8
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
9
9
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
10
10
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
11
|
+
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
11
12
|
import { BITE_LOCATIONS, DATA_FUNCTIONS, IMAGE_POSITIONS, DATA_OPERATORS } from '../CdcDataBite'
|
|
13
|
+
import Layout from '@cdc/core/components/Layout'
|
|
12
14
|
|
|
13
15
|
const TextField = memo(({ label, section = null, subsection = null, fieldName, updateField, value: stateValue, tooltip, type = 'input', i = null, min = null, max = null, ...attributes }) => {
|
|
14
16
|
const [value, setValue] = useState(stateValue)
|
|
@@ -128,49 +130,11 @@ const Select = memo(({ label, value, options, fieldName, section = null, subsect
|
|
|
128
130
|
const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
|
|
129
131
|
|
|
130
132
|
const EditorPanel = memo(() => {
|
|
131
|
-
const { config, updateConfig, loading, data, setParentConfig, isDashboard } = useContext(Context)
|
|
133
|
+
const { config, updateConfig, loading, data, setParentConfig, isDashboard, isEditor } = useContext(Context)
|
|
132
134
|
|
|
133
135
|
const [displayPanel, setDisplayPanel] = useState(true)
|
|
134
|
-
const enforceRestrictions = updatedConfig => {
|
|
135
|
-
//If there are any dependencies between fields, etc../
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const updateField = (section, subsection, fieldName, newValue) => {
|
|
139
|
-
// Top level
|
|
140
|
-
if (null === section && null === subsection) {
|
|
141
|
-
let updatedConfig = { ...config, [fieldName]: newValue }
|
|
142
|
-
|
|
143
|
-
if ('filterColumn' === fieldName) {
|
|
144
|
-
updatedConfig.filterValue = ''
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
enforceRestrictions(updatedConfig)
|
|
148
|
-
|
|
149
|
-
updateConfig(updatedConfig)
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const isArray = Array.isArray(config[section])
|
|
154
|
-
|
|
155
|
-
let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
|
|
156
|
-
|
|
157
|
-
if (null !== subsection) {
|
|
158
|
-
if (isArray) {
|
|
159
|
-
sectionValue = [...config[section]]
|
|
160
|
-
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
|
|
161
|
-
} else if (typeof newValue === 'string') {
|
|
162
|
-
sectionValue[subsection] = newValue
|
|
163
|
-
} else {
|
|
164
|
-
sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
let updatedConfig = { ...config, [section]: sectionValue }
|
|
169
|
-
|
|
170
|
-
enforceRestrictions(updatedConfig)
|
|
171
136
|
|
|
172
|
-
|
|
173
|
-
}
|
|
137
|
+
const updateField = updateFieldFactory(config, updateConfig, true)
|
|
174
138
|
|
|
175
139
|
const missingRequiredSections = () => {
|
|
176
140
|
//Whether to show error message if something is required to show a data-bite and isn't filled in
|
|
@@ -190,39 +154,10 @@ const EditorPanel = memo(() => {
|
|
|
190
154
|
|
|
191
155
|
const onBackClick = () => {
|
|
192
156
|
setDisplayPanel(!displayPanel)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
<section className='waiting'>
|
|
198
|
-
<section className='waiting-container'>
|
|
199
|
-
<h3>Error With Configuration</h3>
|
|
200
|
-
<p>{config.runtime.editorErrorMessage}</p>
|
|
201
|
-
</section>
|
|
202
|
-
</section>
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const Confirm = () => {
|
|
207
|
-
return (
|
|
208
|
-
<section className='waiting'>
|
|
209
|
-
<section className='waiting-container'>
|
|
210
|
-
<h3>Finish Configuring</h3>
|
|
211
|
-
<p>Set all required options to the left and confirm below to display a preview of the chart.</p>
|
|
212
|
-
<button
|
|
213
|
-
className='btn'
|
|
214
|
-
style={{ margin: '1em auto' }}
|
|
215
|
-
disabled={missingRequiredSections()}
|
|
216
|
-
onClick={e => {
|
|
217
|
-
e.preventDefault()
|
|
218
|
-
updateConfig({ ...config, newViz: false })
|
|
219
|
-
}}
|
|
220
|
-
>
|
|
221
|
-
I'm Done
|
|
222
|
-
</button>
|
|
223
|
-
</section>
|
|
224
|
-
</section>
|
|
225
|
-
)
|
|
157
|
+
updateConfig({
|
|
158
|
+
...config,
|
|
159
|
+
showEditorPanel: !displayPanel
|
|
160
|
+
})
|
|
226
161
|
}
|
|
227
162
|
|
|
228
163
|
const convertStateToConfig = () => {
|
|
@@ -339,11 +274,7 @@ const EditorPanel = memo(() => {
|
|
|
339
274
|
|
|
340
275
|
return (
|
|
341
276
|
<ErrorBoundary component='EditorPanel'>
|
|
342
|
-
|
|
343
|
-
{(!config.dataColumn || !config.dataFunction) && <Confirm />}
|
|
344
|
-
<button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} />
|
|
345
|
-
<section className={displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}>
|
|
346
|
-
<div className='heading-2'>Configure Data Bite</div>
|
|
277
|
+
<Layout.Sidebar isEditor={true} config={config} title='Configure Data Bites' onBackClick={onBackClick} displayPanel={displayPanel}>
|
|
347
278
|
<section className='form-container'>
|
|
348
279
|
<form>
|
|
349
280
|
<Accordion allowZeroExpanded={true}>
|
|
@@ -701,7 +632,7 @@ const EditorPanel = memo(() => {
|
|
|
701
632
|
</Accordion>
|
|
702
633
|
</form>
|
|
703
634
|
</section>
|
|
704
|
-
</
|
|
635
|
+
</Layout.Sidebar>
|
|
705
636
|
</ErrorBoundary>
|
|
706
637
|
)
|
|
707
638
|
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import '../scss/kpi.scss'
|
|
3
|
+
|
|
4
|
+
export const KPIComponent = ({ label, value }) => {
|
|
5
|
+
return (
|
|
6
|
+
<div className='cove-component__content kpi-container'>
|
|
7
|
+
<div className='kpi-content'>
|
|
8
|
+
<div className='label-container'>
|
|
9
|
+
<span className='label'>
|
|
10
|
+
<strong>{label}</strong>
|
|
11
|
+
</span>
|
|
12
|
+
</div>
|
|
13
|
+
<div className='value-container'>
|
|
14
|
+
<span className='value'>
|
|
15
|
+
<strong>{value}</strong>
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default KPIComponent
|
package/src/scss/bite.scss
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
@import '../../../core/styles/variables';
|
|
2
2
|
|
|
3
|
-
&.is-editor {
|
|
4
|
-
position: relative;
|
|
5
|
-
.cove-component__inner {
|
|
6
|
-
margin: 3em auto 0;
|
|
7
|
-
max-width: 35em;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
3
|
&.theme-blue {
|
|
11
4
|
.bite-value {
|
|
12
5
|
color: $primary;
|
|
@@ -76,14 +69,27 @@
|
|
|
76
69
|
// TODO after v2 refactor remove header reference colors
|
|
77
70
|
// Use .font-color/.bg-color, etc. in color definitions or something similar
|
|
78
71
|
// Remove box shadows if we're no longer using them
|
|
79
|
-
.cove-
|
|
72
|
+
.sidebar + .cove-component__content .bite-content-container:not(.component--hide-background-color) {
|
|
73
|
+
margin: 3em auto 0;
|
|
74
|
+
max-width: 35em;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sidebar + .cove-component__content .bite-content-container:not(.component--hide-background-color) {
|
|
78
|
+
background-color: white;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.cove-component__content {
|
|
80
82
|
// Visual: Shadow
|
|
81
83
|
&.shadow {
|
|
82
84
|
box-shadow: rgba(0, 0, 0, 0.2) 0 3px 10px;
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
.cove-component__inner {
|
|
88
|
+
padding: 1rem !important;
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
// General: Bite Style > Graphic
|
|
86
|
-
|
|
92
|
+
&.bite__style--graphic {
|
|
87
93
|
.bite-content {
|
|
88
94
|
flex: 1;
|
|
89
95
|
}
|
|
@@ -135,7 +141,6 @@
|
|
|
135
141
|
border-top-left-radius: 3px;
|
|
136
142
|
border-top-right-radius: 3px;
|
|
137
143
|
}
|
|
138
|
-
|
|
139
144
|
.bite-content-container.component--hideBackgroundColor {
|
|
140
145
|
background: transparent;
|
|
141
146
|
}
|
|
@@ -231,7 +236,7 @@
|
|
|
231
236
|
|
|
232
237
|
.cove-component__content {
|
|
233
238
|
display: flex;
|
|
234
|
-
padding: 1em;
|
|
239
|
+
padding: 1em !important;
|
|
235
240
|
justify-content: space-between;
|
|
236
241
|
|
|
237
242
|
.bite-content {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
.kpi-container {
|
|
2
|
+
border-radius: 10px;
|
|
3
|
+
border: 1px solid rgba(0, 0, 0, 0.25) !important;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
|
|
6
|
+
display: flex;
|
|
7
|
+
padding: 5px !important;
|
|
8
|
+
height: 70px;
|
|
9
|
+
width: 100%;
|
|
10
|
+
position: relative;
|
|
11
|
+
display: flex;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.kpi-content {
|
|
15
|
+
background: linear-gradient(90deg, rgba(8, 132, 136, 1) 19%, rgba(255, 255, 255, 1) 74%);
|
|
16
|
+
border-radius: 10px;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex: 1;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.label-container,
|
|
22
|
+
.value-container {
|
|
23
|
+
display: flex;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
align-items: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.label-container {
|
|
30
|
+
padding-left: 30px !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.value-container {
|
|
34
|
+
justify-content: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.label {
|
|
38
|
+
color: white;
|
|
39
|
+
font-size: 18px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.value {
|
|
43
|
+
color: brown;
|
|
44
|
+
font-size: 24px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//small
|
|
48
|
+
@media only screen and (min-width: 768px) and (max-width: 991px) {
|
|
49
|
+
.label {
|
|
50
|
+
font-size: 14px;
|
|
51
|
+
}
|
|
52
|
+
.value {
|
|
53
|
+
font-size: 20px;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//xs
|
|
57
|
+
@media only screen and (max-width: 767px) {
|
|
58
|
+
.label-container {
|
|
59
|
+
justify-content: flex-start;
|
|
60
|
+
padding-left: 10px !important;
|
|
61
|
+
}
|
|
62
|
+
.label {
|
|
63
|
+
font-size: 10px;
|
|
64
|
+
}
|
|
65
|
+
.value {
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
}
|
|
68
|
+
}
|