@cdc/editor 1.4.0 → 1.4.3
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/cdceditor.js +734 -0
- package/example/data-horizontal-filters.json +9 -0
- package/example/data-horizontal-multiseries-filters.json +20 -0
- package/example/data-horizontal-multiseries.json +7 -0
- package/example/data-horizontal.json +5 -0
- package/example/data-vertical-filters.json +11 -0
- package/example/data-vertical-multiseries-filters.json +20 -0
- package/example/data-vertical-multiseries-multirow-filters.json +53 -0
- package/example/data-vertical-multiseries-multirow.json +14 -0
- package/example/data-vertical-multiseries.json +7 -0
- package/example/data-vertical.json +7 -0
- package/example/region-map.json +33 -0
- package/example/valid-county-data.csv +3048 -0
- package/example/valid-county-data.json +3049 -0
- package/example/valid-data-chart.csv +6 -0
- package/example/valid-data-map.csv +59 -0
- package/package.json +14 -12
- package/src/CdcEditor.js +117 -0
- package/src/assets/icons/dashboard.svg +8 -0
- package/src/assets/icons/file-upload-solid.svg +1 -0
- package/src/assets/icons/globe-asia-solid.svg +1 -0
- package/src/assets/icons/link.svg +1 -0
- package/src/assets/icons/upload-solid.svg +1 -0
- package/src/components/ChooseTab.js +103 -0
- package/src/components/ConfigureTab.js +60 -0
- package/src/components/DataImport.js +601 -0
- package/src/components/PreviewDataTable.js +266 -0
- package/src/components/TabPane.js +5 -0
- package/src/components/Tabs.js +62 -0
- package/src/components/modal/Confirmation.js +14 -0
- package/src/components/modal/Modal.js +51 -0
- package/src/components/modal/UseModal.js +10 -0
- package/src/context.js +7 -0
- package/src/index.html +22 -0
- package/src/index.js +17 -0
- package/src/scss/_data-table.scss +15 -0
- package/src/scss/_variables.scss +27 -0
- package/src/scss/choose-vis-tab.scss +70 -0
- package/src/scss/configure-tab.scss +19 -0
- package/src/scss/data-import.scss +212 -0
- package/src/scss/main.scss +166 -0
- package/LICENSE +0 -201
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import React, { useState, useContext, useMemo, useCallback, useEffect, memo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
useTable,
|
|
4
|
+
useBlockLayout,
|
|
5
|
+
useGlobalFilter,
|
|
6
|
+
useSortBy,
|
|
7
|
+
useResizeColumns,
|
|
8
|
+
usePagination
|
|
9
|
+
} from 'react-table';
|
|
10
|
+
import GlobalState from '../context';
|
|
11
|
+
import { useDebounce } from 'use-debounce';
|
|
12
|
+
|
|
13
|
+
// Core
|
|
14
|
+
import validateFipsCodeLength from '@cdc/core/helpers/validateFipsCodeLength';
|
|
15
|
+
|
|
16
|
+
const TableFilter = memo(({globalFilter, setGlobalFilter, disabled = false}) => {
|
|
17
|
+
const [filterValue, setFilterValue ] = useState(globalFilter);
|
|
18
|
+
|
|
19
|
+
const [ debouncedValue ] = useDebounce(filterValue, 200);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if('string' === typeof debouncedValue && debouncedValue !== globalFilter ) {
|
|
23
|
+
setGlobalFilter(debouncedValue ?? '')
|
|
24
|
+
}
|
|
25
|
+
}, [debouncedValue])
|
|
26
|
+
|
|
27
|
+
const onChange = (e) => {
|
|
28
|
+
setFilterValue(e.target.value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<input
|
|
33
|
+
className="filter"
|
|
34
|
+
value={filterValue}
|
|
35
|
+
onChange={onChange}
|
|
36
|
+
type="search"
|
|
37
|
+
placeholder='Filter...'
|
|
38
|
+
disabled={disabled}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const Header = memo(({ globalFilter, data, setGlobalFilter}) => (
|
|
44
|
+
<header className="data-table-header">
|
|
45
|
+
<h2>Data Preview</h2>
|
|
46
|
+
<TableFilter globalFilter={globalFilter || ''} setGlobalFilter={setGlobalFilter} disabled={null === data} />
|
|
47
|
+
</header>
|
|
48
|
+
))
|
|
49
|
+
|
|
50
|
+
const Footer = memo(({previousPage, nextPage, canPreviousPage, canNextPage, pageNumber, totalPages}) => (
|
|
51
|
+
<footer className="data-table-pagination">
|
|
52
|
+
<ul>
|
|
53
|
+
<li>
|
|
54
|
+
<button onClick={() => previousPage()} className="btn btn-prev" disabled={!canPreviousPage} title="Previous Page"></button>
|
|
55
|
+
</li>
|
|
56
|
+
<li>
|
|
57
|
+
<button onClick={() => nextPage()} className="btn btn-next" disabled={!canNextPage} title="Next Page"></button>
|
|
58
|
+
</li>
|
|
59
|
+
</ul>
|
|
60
|
+
<span>
|
|
61
|
+
Page{' '} {pageNumber} of {totalPages}
|
|
62
|
+
</span>
|
|
63
|
+
</footer>
|
|
64
|
+
))
|
|
65
|
+
|
|
66
|
+
const PreviewDataTable = ({ data }) => {
|
|
67
|
+
const [tableData, setTableData] = useState(data ?? []);
|
|
68
|
+
const {setErrors, errorMessages, config} = useContext(GlobalState);
|
|
69
|
+
|
|
70
|
+
const tableColumns = useMemo(() => {
|
|
71
|
+
const columns = tableData.columns ?? [];
|
|
72
|
+
if ( columns.length > 0 && columns.includes("") ) {
|
|
73
|
+
// todo find a way to call the errors. Currently they are in DataImport.js
|
|
74
|
+
// maybe these can be moved to a file? but then we need a way to add settings like size...
|
|
75
|
+
setErrors([errorMessages.emptyCols]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return columns.map((columnName, idx) => {
|
|
79
|
+
const columnConfig = {
|
|
80
|
+
id: `column-${columnName}`,
|
|
81
|
+
accessor: row => row[columnName],
|
|
82
|
+
Header: columnName,
|
|
83
|
+
width: 250
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return columnConfig
|
|
87
|
+
});
|
|
88
|
+
}, [tableData]);
|
|
89
|
+
|
|
90
|
+
// This adds a columns property just like the D3 function for JSON parsing.
|
|
91
|
+
const generateColumns = useCallback((data) => {
|
|
92
|
+
let columns = []
|
|
93
|
+
|
|
94
|
+
data.forEach( (rowObj) => {
|
|
95
|
+
Object.keys(rowObj).forEach( (columnHeading) => {
|
|
96
|
+
if(false === columns.includes(columnHeading)) {
|
|
97
|
+
columns.push(columnHeading)
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// D3 uses a weird quirk where it attaches a named property to an array. Replicating here.
|
|
103
|
+
const newData = [...data];
|
|
104
|
+
|
|
105
|
+
if(Array.isArray(newData)) {
|
|
106
|
+
newData.columns = columns;
|
|
107
|
+
return newData;
|
|
108
|
+
}
|
|
109
|
+
}, [])
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if(!data) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let newData = [...data];
|
|
117
|
+
|
|
118
|
+
newData = generateColumns(newData);
|
|
119
|
+
validateFipsCodeLength(newData)
|
|
120
|
+
setTableData(newData)
|
|
121
|
+
}, [data, generateColumns])
|
|
122
|
+
|
|
123
|
+
const {
|
|
124
|
+
getTableProps,
|
|
125
|
+
getTableBodyProps,
|
|
126
|
+
headerGroups,
|
|
127
|
+
state: { pageIndex, globalFilter },
|
|
128
|
+
prepareRow,
|
|
129
|
+
setGlobalFilter,
|
|
130
|
+
page,
|
|
131
|
+
canPreviousPage,
|
|
132
|
+
canNextPage,
|
|
133
|
+
pageOptions,
|
|
134
|
+
nextPage,
|
|
135
|
+
previousPage,
|
|
136
|
+
} = useTable({ columns: tableColumns, data: tableData, initialState: { pageSize: 25 } }, useBlockLayout, useGlobalFilter, useSortBy, useResizeColumns, usePagination);
|
|
137
|
+
|
|
138
|
+
const NoData = () => (
|
|
139
|
+
<section className="no-data-message">
|
|
140
|
+
<section>
|
|
141
|
+
<h3>No Data</h3>
|
|
142
|
+
<p>Import data to preview</p>
|
|
143
|
+
</section>
|
|
144
|
+
</section>
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const PlaceholderTable = () => {
|
|
148
|
+
return (
|
|
149
|
+
<section className="no-data">
|
|
150
|
+
<NoData />
|
|
151
|
+
<div className="table-container">
|
|
152
|
+
<table className="editor data-table" role="table">
|
|
153
|
+
<thead>
|
|
154
|
+
<tr role="row">
|
|
155
|
+
<th scope="col" colSpan="1" role="columnheader">
|
|
156
|
+
</th>
|
|
157
|
+
<th scope="col" colSpan="1" role="columnheader">
|
|
158
|
+
</th>
|
|
159
|
+
<th scope="col" colSpan="1" role="columnheader">
|
|
160
|
+
</th>
|
|
161
|
+
</tr>
|
|
162
|
+
</thead>
|
|
163
|
+
<tbody>
|
|
164
|
+
<tr role="row">
|
|
165
|
+
<td role="cell"></td>
|
|
166
|
+
<td role="cell"></td>
|
|
167
|
+
<td role="cell"></td>
|
|
168
|
+
</tr>
|
|
169
|
+
<tr role="row">
|
|
170
|
+
<td role="cell"></td>
|
|
171
|
+
<td role="cell"></td>
|
|
172
|
+
<td role="cell"></td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr role="row">
|
|
175
|
+
<td role="cell"></td>
|
|
176
|
+
<td role="cell"></td>
|
|
177
|
+
<td role="cell"></td>
|
|
178
|
+
</tr>
|
|
179
|
+
<tr role="row">
|
|
180
|
+
<td role="cell"></td>
|
|
181
|
+
<td role="cell"></td>
|
|
182
|
+
<td role="cell"></td>
|
|
183
|
+
</tr>
|
|
184
|
+
<tr role="row">
|
|
185
|
+
<td role="cell"></td>
|
|
186
|
+
<td role="cell"></td>
|
|
187
|
+
<td role="cell"></td>
|
|
188
|
+
</tr>
|
|
189
|
+
<tr role="row">
|
|
190
|
+
<td role="cell"></td>
|
|
191
|
+
<td role="cell"></td>
|
|
192
|
+
<td role="cell"></td>
|
|
193
|
+
</tr>
|
|
194
|
+
<tr role="row">
|
|
195
|
+
<td role="cell"></td>
|
|
196
|
+
<td role="cell"></td>
|
|
197
|
+
<td role="cell"></td>
|
|
198
|
+
</tr>
|
|
199
|
+
<tr role="row">
|
|
200
|
+
<td role="cell"></td>
|
|
201
|
+
<td role="cell"></td>
|
|
202
|
+
<td role="cell"></td>
|
|
203
|
+
</tr>
|
|
204
|
+
<tr role="row">
|
|
205
|
+
<td role="cell"></td>
|
|
206
|
+
<td role="cell"></td>
|
|
207
|
+
<td role="cell"></td>
|
|
208
|
+
</tr>
|
|
209
|
+
<tr role="row">
|
|
210
|
+
<td role="cell"></td>
|
|
211
|
+
<td role="cell"></td>
|
|
212
|
+
<td role="cell"></td>
|
|
213
|
+
</tr>
|
|
214
|
+
</tbody>
|
|
215
|
+
</table>
|
|
216
|
+
</div>
|
|
217
|
+
</section>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if(!data) return [<Header key="header" />, <PlaceholderTable key="table" />]
|
|
222
|
+
|
|
223
|
+
const footerProps = {previousPage, nextPage, canPreviousPage, canNextPage, pageNumber: pageIndex + 1, totalPages: pageOptions.length}
|
|
224
|
+
|
|
225
|
+
const Table = () => (
|
|
226
|
+
<>
|
|
227
|
+
<section className="data-table-container">
|
|
228
|
+
<div className="table-container">
|
|
229
|
+
<table className="data-table" {...getTableProps()} aria-hidden="true">
|
|
230
|
+
<thead>
|
|
231
|
+
{headerGroups.map((headerGroup) => (
|
|
232
|
+
<tr {...headerGroup.getHeaderGroupProps()}>
|
|
233
|
+
{headerGroup.headers.map((column) => (
|
|
234
|
+
<th scope="col" {...column.getHeaderProps(column.getSortByToggleProps())} className={column.isSorted ? column.isSortedDesc ? 'sort sort-desc' : 'sort sort-asc' : ''} title={column.Header}>
|
|
235
|
+
{column.render('Header')}
|
|
236
|
+
<div {...column.getResizerProps()} className="resizer" />
|
|
237
|
+
</th>
|
|
238
|
+
))}
|
|
239
|
+
</tr>
|
|
240
|
+
))}
|
|
241
|
+
</thead>
|
|
242
|
+
<tbody {...getTableBodyProps()}>
|
|
243
|
+
{page.map((row) => {
|
|
244
|
+
prepareRow(row);
|
|
245
|
+
return (
|
|
246
|
+
<tr {...row.getRowProps()}>
|
|
247
|
+
{row.cells.map((cell) => (
|
|
248
|
+
<td {...cell.getCellProps()} title={cell.value}>
|
|
249
|
+
{cell.render('Cell')}
|
|
250
|
+
</td>
|
|
251
|
+
))}
|
|
252
|
+
</tr>
|
|
253
|
+
);
|
|
254
|
+
})}
|
|
255
|
+
</tbody>
|
|
256
|
+
</table>
|
|
257
|
+
</div>
|
|
258
|
+
</section>
|
|
259
|
+
<Footer {...footerProps} />
|
|
260
|
+
</>
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return [<Header key="header" data={data} setGlobalFilter={setGlobalFilter} globalFilter={globalFilter} />, <Table key="table" />]
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export default PreviewDataTable;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { useState, useContext, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const Tabs = ({ children, startingTab = 0, className, changeTab = null }) => {
|
|
4
|
+
const [active, setActive] = useState(startingTab);
|
|
5
|
+
|
|
6
|
+
let containerClassName = 'tabs';
|
|
7
|
+
|
|
8
|
+
if(className) {
|
|
9
|
+
containerClassName = `tabs ${className}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const setActiveTab = (disabled, index) => {
|
|
13
|
+
if(false === disabled) {
|
|
14
|
+
setActive(index)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if(startingTab > -1) {
|
|
20
|
+
setActive(startingTab)
|
|
21
|
+
}
|
|
22
|
+
}, [startingTab])
|
|
23
|
+
|
|
24
|
+
const tabs = children.map(({props}, i) => {
|
|
25
|
+
|
|
26
|
+
let classes = 'nav-item'
|
|
27
|
+
|
|
28
|
+
let disabled = props.disableRule || false
|
|
29
|
+
|
|
30
|
+
if(disabled) {
|
|
31
|
+
classes += ' disabled';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if(i === active) {
|
|
35
|
+
classes += ' active';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<li
|
|
40
|
+
onClick={() => setActiveTab(disabled, i)}
|
|
41
|
+
key={props.title}
|
|
42
|
+
className={classes}
|
|
43
|
+
>
|
|
44
|
+
{props.icon}
|
|
45
|
+
{props.title}
|
|
46
|
+
</li>
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<nav className={containerClassName}>
|
|
53
|
+
<ul className="nav nav-fill">
|
|
54
|
+
{tabs}
|
|
55
|
+
</ul>
|
|
56
|
+
</nav>
|
|
57
|
+
{children[active]}
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default Tabs;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export const ConfirmationModal
|
|
4
|
+
= (props) => {
|
|
5
|
+
return (
|
|
6
|
+
<>
|
|
7
|
+
<p className="message">{props.message}</p>
|
|
8
|
+
<div className="confirmation-buttons">
|
|
9
|
+
<div className="btn btn-inline" onClick={props.onCancel}>No</div>
|
|
10
|
+
<div className="btn btn-inline" onClick={props.onConfirm}>Yes</div>
|
|
11
|
+
</div>
|
|
12
|
+
</>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
// import FocusLock from "react-focus-lock";
|
|
3
|
+
import ReactDOM from "react-dom";
|
|
4
|
+
import CloseIcon from '../../assets/icons/close.svg';
|
|
5
|
+
|
|
6
|
+
export const Modal = ({
|
|
7
|
+
isShown,
|
|
8
|
+
hide,
|
|
9
|
+
modalContent,
|
|
10
|
+
headerText
|
|
11
|
+
}) => {
|
|
12
|
+
const onKeyDown = (event) => {
|
|
13
|
+
if (event.keyCode === 27 && isShown) {
|
|
14
|
+
hide();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
isShown
|
|
20
|
+
? (document.body.style.overflow = "hidden")
|
|
21
|
+
: (document.body.style.overflow = "unset");
|
|
22
|
+
document.addEventListener("keydown", onKeyDown, false);
|
|
23
|
+
return () => {
|
|
24
|
+
document.removeEventListener("keydown", onKeyDown, false);
|
|
25
|
+
};
|
|
26
|
+
}, [isShown]);
|
|
27
|
+
|
|
28
|
+
const modal = (
|
|
29
|
+
<>
|
|
30
|
+
<div className="modal-backdrop" onClick={hide} />
|
|
31
|
+
{/* <FocusLock> */}
|
|
32
|
+
<div className="modal-wrapper"
|
|
33
|
+
aria-modal
|
|
34
|
+
aria-labelledby={headerText}
|
|
35
|
+
tabIndex={-1}
|
|
36
|
+
role="dialog"
|
|
37
|
+
>
|
|
38
|
+
<div className="modal">
|
|
39
|
+
<div className="modal-header">
|
|
40
|
+
<strong>{headerText}</strong>
|
|
41
|
+
<CloseIcon className="modal-close" onClick={hide} />
|
|
42
|
+
</div>
|
|
43
|
+
<div className="modal-content">{modalContent}</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
{/* </FocusLock> */}
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return isShown ? ReactDOM.createPortal(modal, document.body) : null;
|
|
51
|
+
};
|
package/src/context.js
ADDED
package/src/index.html
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta
|
|
6
|
+
name="viewport"
|
|
7
|
+
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
|
8
|
+
/>
|
|
9
|
+
<style type="text/css">
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
}
|
|
13
|
+
.react-container {
|
|
14
|
+
min-height: 100vh;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div class="react-container react--editor"></div>
|
|
20
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import CdcEditor from './CdcEditor';
|
|
4
|
+
|
|
5
|
+
// Allow URL query to preselect a tab in standalone mode
|
|
6
|
+
const standaloneParams = new URLSearchParams(window.location.search);
|
|
7
|
+
|
|
8
|
+
let activeTab = Number.parseInt( standaloneParams.get('active') ) - 1 || null;
|
|
9
|
+
const domContainer = document.querySelector('.react-container')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
ReactDOM.render(
|
|
13
|
+
<React.StrictMode>
|
|
14
|
+
<CdcEditor startingTab={activeTab} containerEl={domContainer} />
|
|
15
|
+
</React.StrictMode>,
|
|
16
|
+
document.querySelector('.react-container')
|
|
17
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.data-table-header {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
margin-bottom: 1.5em;
|
|
6
|
+
h2 {
|
|
7
|
+
font-weight: 600;
|
|
8
|
+
font-size: 1.3em;
|
|
9
|
+
}
|
|
10
|
+
.filter {
|
|
11
|
+
align-self: flex-end;
|
|
12
|
+
font-size: 1em;
|
|
13
|
+
width: 30%;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@import "~@cdc/core/styles/variables";
|
|
2
|
+
|
|
3
|
+
$xxs: 350px;
|
|
4
|
+
$xs: 576px;
|
|
5
|
+
$sm: 768px;
|
|
6
|
+
$md: 992px;
|
|
7
|
+
$lg: 1200px;
|
|
8
|
+
|
|
9
|
+
$base-size: 16;
|
|
10
|
+
|
|
11
|
+
@function size($target, $context: $base-size) {
|
|
12
|
+
@return calc($target / $context) * 1em;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$gbl-padding: size(30);
|
|
16
|
+
$table-padding: size(10);
|
|
17
|
+
|
|
18
|
+
// colors
|
|
19
|
+
$white: #fff;
|
|
20
|
+
$darkest-gray: #2e2e2e;
|
|
21
|
+
$gray: #333;
|
|
22
|
+
$light-gray: #797979;
|
|
23
|
+
$lighter-gray: #ebebeb;
|
|
24
|
+
$lightest-gray: #f5f5f5;
|
|
25
|
+
|
|
26
|
+
$light-yellow: #fde0b5;
|
|
27
|
+
$dark-yellow: #f59a23;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
@import 'variables';
|
|
2
|
+
|
|
3
|
+
.cdc-editor .choose-vis {
|
|
4
|
+
padding: $gbl-padding;
|
|
5
|
+
.capitalize {
|
|
6
|
+
text-transform: capitalize;
|
|
7
|
+
}
|
|
8
|
+
ul + .heading-2 {
|
|
9
|
+
margin-top: 1em;
|
|
10
|
+
}
|
|
11
|
+
.grid {
|
|
12
|
+
margin-top: 1em;
|
|
13
|
+
list-style: none;
|
|
14
|
+
display: flex;
|
|
15
|
+
li {
|
|
16
|
+
margin-right: 1rem;
|
|
17
|
+
margin-bottom: 1rem;
|
|
18
|
+
width: 165px;
|
|
19
|
+
}
|
|
20
|
+
button {
|
|
21
|
+
background-color: #fff;
|
|
22
|
+
color: $baseColor;
|
|
23
|
+
border: solid 1px;
|
|
24
|
+
border-color: rgb(199,199,199);
|
|
25
|
+
padding: 1.3em $gbl-padding;
|
|
26
|
+
height: 100%;
|
|
27
|
+
align-items: center;
|
|
28
|
+
display: flex;
|
|
29
|
+
border: $lightGray 1px solid;
|
|
30
|
+
margin-right: 1em;
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
transition: .1s all;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
span {
|
|
35
|
+
text-transform: none;
|
|
36
|
+
font-size: 1em;
|
|
37
|
+
}
|
|
38
|
+
&:hover {
|
|
39
|
+
background: #F2F2F2;
|
|
40
|
+
border-color: #949494;
|
|
41
|
+
transition: .1s all;
|
|
42
|
+
}
|
|
43
|
+
&.active {
|
|
44
|
+
background: #fff;
|
|
45
|
+
border-color: #005eaa;
|
|
46
|
+
color: #005eaa;
|
|
47
|
+
position: relative;
|
|
48
|
+
path {
|
|
49
|
+
fill: #005eaa;
|
|
50
|
+
}
|
|
51
|
+
&:before {
|
|
52
|
+
content: " ";
|
|
53
|
+
width: 5px;
|
|
54
|
+
background: #005eaa;
|
|
55
|
+
left: 0;
|
|
56
|
+
top: 0;
|
|
57
|
+
bottom: 0;
|
|
58
|
+
position: absolute;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
svg {
|
|
62
|
+
display: block;
|
|
63
|
+
margin: 0 auto .5em;
|
|
64
|
+
box-sizing: border-box;
|
|
65
|
+
width: 100px;
|
|
66
|
+
height: 75px;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.cdc-editor .configure {
|
|
2
|
+
.editor-panel {
|
|
3
|
+
top: 3em;
|
|
4
|
+
}
|
|
5
|
+
.editor-toggle {
|
|
6
|
+
top: 3.5em;
|
|
7
|
+
}
|
|
8
|
+
.type-dashboard {
|
|
9
|
+
.editor-heading {
|
|
10
|
+
top: 3em;
|
|
11
|
+
}
|
|
12
|
+
.editor-panel, .visualizations-panel {
|
|
13
|
+
top: 6em !important;
|
|
14
|
+
}
|
|
15
|
+
.editor-toggle {
|
|
16
|
+
top: 6.5em !important;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|