@kanaries/graphic-walker 0.2.13 → 0.2.14
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/App.d.ts +4 -2
- package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
- package/dist/components/button/base.d.ts +1 -0
- package/dist/components/button/defaultMini.d.ts +4 -0
- package/dist/components/button/primaryMini.d.ts +4 -0
- package/dist/components/dropdownContext/index.d.ts +13 -0
- package/dist/components/dropdownSelect/index.d.ts +17 -0
- package/dist/components/modal.d.ts +1 -0
- package/dist/components/toolbar/toolbar-item.d.ts +1 -0
- package/dist/dataSource/dataSelection/config.d.ts +2 -0
- package/dist/dataSource/index.d.ts +1 -1
- package/dist/fields/datasetFields/dimFields.d.ts +2 -2
- package/dist/fields/datasetFields/meaFields.d.ts +2 -2
- package/dist/fields/encodeFields/singleEncodeDropDown.d.ts +17 -0
- package/dist/fields/encodeFields/singleEncodeEditor.d.ts +11 -0
- package/dist/fields/obComponents/obPill.d.ts +3 -3
- package/dist/graphic-walker.es.js +20874 -19172
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +245 -170
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/insightBoard/index.d.ts +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/renderer/index.d.ts +3 -1
- package/dist/store/visualSpecStore.d.ts +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/media.d.ts +2 -0
- package/dist/vis/react-vega.d.ts +2 -0
- package/dist/vis/theme.d.ts +130 -0
- package/package.json +2 -1
- package/src/App.tsx +8 -5
- package/src/components/button/base.ts +1 -0
- package/src/components/button/default.tsx +6 -2
- package/src/components/button/defaultMini.tsx +17 -0
- package/src/components/button/primary.tsx +6 -2
- package/src/components/button/primaryMini.tsx +21 -0
- package/src/components/callout.tsx +4 -1
- package/src/components/clickMenu.tsx +4 -2
- package/src/components/container.tsx +9 -0
- package/src/components/dataTable/index.tsx +42 -52
- package/src/components/dataTable/pagination.tsx +4 -4
- package/src/components/dataTypeIcon.tsx +1 -1
- package/src/components/dropdownContext/index.tsx +64 -0
- package/src/components/dropdownSelect/index.tsx +92 -0
- package/src/components/modal.tsx +26 -14
- package/src/components/tabs/defaultTab.tsx +4 -4
- package/src/components/tabs/editableTab.tsx +5 -5
- package/src/components/toolbar/components.tsx +18 -1
- package/src/components/toolbar/index.tsx +5 -0
- package/src/components/toolbar/toolbar-button.tsx +6 -1
- package/src/components/toolbar/toolbar-item.tsx +4 -0
- package/src/components/toolbar/toolbar-select-button.tsx +21 -4
- package/src/components/toolbar/toolbar-toggle-button.tsx +6 -1
- package/src/components/tooltip.tsx +4 -1
- package/src/dataSource/dataSelection/config.ts +28 -0
- package/src/dataSource/dataSelection/csvData.tsx +77 -32
- package/src/dataSource/dataSelection/gwFile.tsx +0 -8
- package/src/dataSource/dataSelection/index.tsx +1 -2
- package/src/dataSource/dataSelection/publicData.tsx +2 -3
- package/src/dataSource/index.tsx +81 -61
- package/src/fields/aestheticFields.tsx +3 -1
- package/src/fields/components.tsx +21 -2
- package/src/fields/datasetFields/dimFields.tsx +43 -35
- package/src/fields/datasetFields/index.tsx +2 -2
- package/src/fields/datasetFields/meaFields.tsx +73 -47
- package/src/fields/encodeFields/singleEncodeDropDown.tsx +92 -0
- package/src/fields/encodeFields/singleEncodeEditor.tsx +78 -0
- package/src/fields/filterField/filterEditDialog.tsx +2 -1
- package/src/fields/filterField/filterPill.tsx +1 -1
- package/src/fields/filterField/slider.tsx +1 -1
- package/src/fields/filterField/tabs.tsx +11 -21
- package/src/fields/obComponents/obPill.tsx +65 -35
- package/src/index.css +13 -0
- package/src/insightBoard/index.tsx +24 -23
- package/src/insightBoard/radioGroupButtons.tsx +7 -0
- package/src/interfaces.ts +1 -0
- package/src/lib/inferMeta.ts +1 -1
- package/src/locales/en-US.json +7 -4
- package/src/locales/zh-CN.json +5 -2
- package/src/main.tsx +1 -1
- package/src/renderer/index.tsx +2 -1
- package/src/store/visualSpecStore.ts +16 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/media.ts +26 -0
- package/src/utils/normalization.ts +2 -1
- package/src/vis/react-vega.tsx +20 -4
- package/src/vis/theme.ts +126 -0
- package/src/visualSettings/index.tsx +24 -8
package/dist/interfaces.d.ts
CHANGED
package/dist/renderer/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IReactVegaHandler } from '../vis/react-vega';
|
|
3
|
-
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<
|
|
3
|
+
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<{
|
|
4
|
+
themeKey?: "vega" | "g2" | undefined;
|
|
5
|
+
} & React.RefAttributes<IReactVegaHandler>, "key" | "themeKey"> & React.RefAttributes<IReactVegaHandler>>>;
|
|
4
6
|
export default _default;
|
|
@@ -93,6 +93,7 @@ export declare class VizSpecStore {
|
|
|
93
93
|
reorderField(stateKey: keyof DraggableFieldState, sourceIndex: number, destinationIndex: number): void;
|
|
94
94
|
moveField(sourceKey: keyof DraggableFieldState, sourceIndex: number, destinationKey: keyof DraggableFieldState, destinationIndex: number): void;
|
|
95
95
|
removeField(sourceKey: keyof DraggableFieldState, sourceIndex: number): void;
|
|
96
|
+
replaceField(sourceKey: keyof DraggableFieldState, sourceIndex: number, fid: string): void;
|
|
96
97
|
private appendFilter;
|
|
97
98
|
writeFilter(index: number, rule: IFilterRule | null): void;
|
|
98
99
|
setFilterEditing(index: number): void;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -20,3 +20,5 @@ export declare function extendCountField(dataSource: IRow[], fields: IMutField[]
|
|
|
20
20
|
dataSource: IRow[];
|
|
21
21
|
fields: IMutField[];
|
|
22
22
|
};
|
|
23
|
+
export declare function getRange(nums: number[]): [number, number];
|
|
24
|
+
export declare function makeNumbersBeautiful(nums: number[]): number[];
|
package/dist/vis/react-vega.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ interface ReactVegaProps {
|
|
|
27
27
|
onGeomClick?: (values: any, e: any) => void;
|
|
28
28
|
selectEncoding: SingleViewProps['selectEncoding'];
|
|
29
29
|
brushEncoding: SingleViewProps['brushEncoding'];
|
|
30
|
+
/** @default "vega" */
|
|
31
|
+
themeKey?: 'vega' | 'g2';
|
|
30
32
|
}
|
|
31
33
|
interface SingleViewProps {
|
|
32
34
|
x: IViewField;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export declare const VegaTheme: {
|
|
2
|
+
readonly light: {
|
|
3
|
+
readonly background: "transparent";
|
|
4
|
+
};
|
|
5
|
+
readonly dark: {
|
|
6
|
+
readonly background: "transparent";
|
|
7
|
+
readonly axis: {
|
|
8
|
+
readonly gridColor: "#666";
|
|
9
|
+
readonly domainColor: "#d1d5db";
|
|
10
|
+
readonly tickColor: "#d1d5db";
|
|
11
|
+
readonly labelColor: "#d1d5db";
|
|
12
|
+
};
|
|
13
|
+
readonly legend: {
|
|
14
|
+
readonly labelColor: "#d1d5db";
|
|
15
|
+
readonly titleColor: "#d1d5db";
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare const AntVTheme: {
|
|
20
|
+
readonly light: {
|
|
21
|
+
readonly area: {
|
|
22
|
+
readonly fill: "#5B8FF9";
|
|
23
|
+
};
|
|
24
|
+
readonly bar: {
|
|
25
|
+
readonly fill: "#5B8FF9";
|
|
26
|
+
};
|
|
27
|
+
readonly circle: {
|
|
28
|
+
readonly fill: "#5B8FF9";
|
|
29
|
+
};
|
|
30
|
+
readonly line: {
|
|
31
|
+
readonly stroke: "#5B8FF9";
|
|
32
|
+
};
|
|
33
|
+
readonly point: {
|
|
34
|
+
readonly stroke: "#5B8FF9";
|
|
35
|
+
};
|
|
36
|
+
readonly rect: {
|
|
37
|
+
readonly fill: "#5B8FF9";
|
|
38
|
+
};
|
|
39
|
+
readonly tick: {
|
|
40
|
+
readonly stroke: "#5B8FF9";
|
|
41
|
+
};
|
|
42
|
+
readonly boxplot: {
|
|
43
|
+
readonly fill: "#5B8FF9";
|
|
44
|
+
};
|
|
45
|
+
readonly errorbar: {
|
|
46
|
+
readonly stroke: "#5B8FF9";
|
|
47
|
+
};
|
|
48
|
+
readonly errorband: {
|
|
49
|
+
readonly fill: "#5B8FF9";
|
|
50
|
+
};
|
|
51
|
+
readonly arc: {
|
|
52
|
+
readonly fill: "#5B8FF9";
|
|
53
|
+
};
|
|
54
|
+
readonly background: "transparent";
|
|
55
|
+
readonly range: {
|
|
56
|
+
readonly category: readonly ["#5B8FF9", "#61DDAA", "#65789B", "#F6BD16", "#7262FD", "#78D3F8", "#9661BC", "#F6903D", "#008685", "#F08BB4"];
|
|
57
|
+
readonly diverging: readonly ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"];
|
|
58
|
+
readonly heatmap: readonly ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"];
|
|
59
|
+
readonly ramp: readonly ["#EBCCFF", "#CCB0FF", "#AE95FF", "#907BFF", "#7262FD", "#5349E0", "#2F32C3", "#001BA7", "#00068C"];
|
|
60
|
+
};
|
|
61
|
+
readonly scale: {
|
|
62
|
+
readonly continuous: {
|
|
63
|
+
readonly range: readonly ["#f7fbff", "#08306b"];
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
readonly dark: {
|
|
68
|
+
readonly area: {
|
|
69
|
+
readonly fill: "#5B8FF9";
|
|
70
|
+
};
|
|
71
|
+
readonly bar: {
|
|
72
|
+
readonly fill: "#5B8FF9";
|
|
73
|
+
};
|
|
74
|
+
readonly circle: {
|
|
75
|
+
readonly fill: "#5B8FF9";
|
|
76
|
+
};
|
|
77
|
+
readonly line: {
|
|
78
|
+
readonly stroke: "#5B8FF9";
|
|
79
|
+
};
|
|
80
|
+
readonly point: {
|
|
81
|
+
readonly stroke: "#5B8FF9";
|
|
82
|
+
};
|
|
83
|
+
readonly rect: {
|
|
84
|
+
readonly fill: "#5B8FF9";
|
|
85
|
+
};
|
|
86
|
+
readonly tick: {
|
|
87
|
+
readonly stroke: "#5B8FF9";
|
|
88
|
+
};
|
|
89
|
+
readonly boxplot: {
|
|
90
|
+
readonly fill: "#5B8FF9";
|
|
91
|
+
};
|
|
92
|
+
readonly errorbar: {
|
|
93
|
+
readonly stroke: "#5B8FF9";
|
|
94
|
+
};
|
|
95
|
+
readonly errorband: {
|
|
96
|
+
readonly fill: "#5B8FF9";
|
|
97
|
+
};
|
|
98
|
+
readonly arc: {
|
|
99
|
+
readonly fill: "#5B8FF9";
|
|
100
|
+
};
|
|
101
|
+
readonly background: "transparent";
|
|
102
|
+
readonly axis: {
|
|
103
|
+
readonly gridColor: "#666";
|
|
104
|
+
readonly domainColor: "#d1d5db";
|
|
105
|
+
readonly tickColor: "#d1d5db";
|
|
106
|
+
readonly labelColor: "#d1d5db";
|
|
107
|
+
};
|
|
108
|
+
readonly legend: {
|
|
109
|
+
readonly labelColor: "#d1d5db";
|
|
110
|
+
readonly titleColor: "#d1d5db";
|
|
111
|
+
};
|
|
112
|
+
readonly range: {
|
|
113
|
+
readonly category: readonly ["#5B8FF9", "#61DDAA", "#65789B", "#F6BD16", "#7262FD", "#78D3F8", "#9661BC", "#F6903D", "#008685", "#F08BB4"];
|
|
114
|
+
readonly diverging: readonly ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"];
|
|
115
|
+
readonly heatmap: readonly ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"];
|
|
116
|
+
readonly ramp: readonly ["#EBCCFF", "#CCB0FF", "#AE95FF", "#907BFF", "#7262FD", "#5349E0", "#2F32C3", "#001BA7", "#00068C"];
|
|
117
|
+
};
|
|
118
|
+
readonly scale: {
|
|
119
|
+
readonly continuous: {
|
|
120
|
+
readonly range: readonly ["#f7fbff", "#08306b"];
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
export declare const builtInThemes: {
|
|
126
|
+
[themeKey: string]: {
|
|
127
|
+
light: any;
|
|
128
|
+
dark: any;
|
|
129
|
+
};
|
|
130
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanaries/graphic-walker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev:front_end": "vite --host",
|
|
6
6
|
"dev": "npm run dev:front_end",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@headlessui/react": "^1.7.12",
|
|
35
36
|
"@heroicons/react": "^2.0.8",
|
|
36
37
|
"@kanaries/react-beautiful-dnd": "0.0.1",
|
|
37
38
|
"@kanaries/web-data-loader": "0.1.5",
|
package/src/App.tsx
CHANGED
|
@@ -36,9 +36,11 @@ export interface IGWProps {
|
|
|
36
36
|
* auto parse field key into a safe string. default is true
|
|
37
37
|
*/
|
|
38
38
|
fieldKeyGuard?: boolean;
|
|
39
|
+
/** @default "vega" */
|
|
40
|
+
themeKey?: 'vega' | 'g2';
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
const App
|
|
43
|
+
const App = observer<IGWProps>(function App (props) {
|
|
42
44
|
const {
|
|
43
45
|
dataSource = [],
|
|
44
46
|
rawFields = [],
|
|
@@ -47,6 +49,7 @@ const App: React.FC<IGWProps> = (props) => {
|
|
|
47
49
|
i18nResources,
|
|
48
50
|
hideDataSourceConfig,
|
|
49
51
|
fieldKeyGuard = true,
|
|
52
|
+
themeKey = 'vega',
|
|
50
53
|
} = props;
|
|
51
54
|
const { commonStore, vizStore } = useGlobalStore();
|
|
52
55
|
const [insightReady, setInsightReady] = useState<boolean>(true);
|
|
@@ -117,7 +120,7 @@ const App: React.FC<IGWProps> = (props) => {
|
|
|
117
120
|
const rendererRef = useRef<IReactVegaHandler>(null);
|
|
118
121
|
|
|
119
122
|
return (
|
|
120
|
-
<div className="App">
|
|
123
|
+
<div className="App font-sans dark:bg-zinc-900 dark:text-white m-0 p-0">
|
|
121
124
|
{/* <div className="grow-0">
|
|
122
125
|
<PageNav />
|
|
123
126
|
</div> */}
|
|
@@ -153,7 +156,7 @@ const App: React.FC<IGWProps> = (props) => {
|
|
|
153
156
|
vizEmbededMenu.show && commonStore.closeEmbededMenu();
|
|
154
157
|
}}
|
|
155
158
|
>
|
|
156
|
-
{datasets.length > 0 && <ReactiveRenderer ref={rendererRef} />}
|
|
159
|
+
{datasets.length > 0 && <ReactiveRenderer ref={rendererRef} themeKey={themeKey} />}
|
|
157
160
|
<InsightBoard />
|
|
158
161
|
{vizEmbededMenu.show && (
|
|
159
162
|
<ClickMenu x={vizEmbededMenu.position[0]} y={vizEmbededMenu.position[1]}>
|
|
@@ -184,6 +187,6 @@ const App: React.FC<IGWProps> = (props) => {
|
|
|
184
187
|
</div>
|
|
185
188
|
</div>
|
|
186
189
|
);
|
|
187
|
-
};
|
|
190
|
+
});
|
|
188
191
|
|
|
189
|
-
export default
|
|
192
|
+
export default App;
|
|
@@ -2,10 +2,14 @@ import React from "react";
|
|
|
2
2
|
import { ButtonBaseProps } from "./base";
|
|
3
3
|
|
|
4
4
|
const DefaultButton: React.FC<ButtonBaseProps> = (props) => {
|
|
5
|
-
const { text, onClick, disabled } = props;
|
|
5
|
+
const { text, onClick, disabled, className } = props;
|
|
6
|
+
let btnClassName = "inline-flex items-center rounded border border-gray-300 bg-white dark:bg-zinc-900 px-2.5 py-1.5 text-xs font-medium text-gray-700 dark:text-gray-200 shadow-sm hover:bg-gray-50 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50"
|
|
7
|
+
if (className) {
|
|
8
|
+
btnClassName = btnClassName + " " + className;
|
|
9
|
+
}
|
|
6
10
|
return (
|
|
7
11
|
<button
|
|
8
|
-
className=
|
|
12
|
+
className={btnClassName}
|
|
9
13
|
onClick={onClick}
|
|
10
14
|
disabled={disabled}
|
|
11
15
|
>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ButtonBaseProps } from "./base";
|
|
3
|
+
|
|
4
|
+
const DefaultMiniButton: React.FC<ButtonBaseProps> = (props) => {
|
|
5
|
+
const { text, onClick, disabled } = props;
|
|
6
|
+
return (
|
|
7
|
+
<button
|
|
8
|
+
className="inline-block min-w-96 text-xs ml-2 pt-1 pb-1 pl-6 pr-6 border border-gray-500 rounded-sm hover:bg-gray-800 hover:border-gray-800 hover:text-white disabled:bg-gray-400 disabled:border-gray-400 disabled:text-white disabled:cursor-not-allowed disabled:text-white"
|
|
9
|
+
onClick={onClick}
|
|
10
|
+
disabled={disabled}
|
|
11
|
+
>
|
|
12
|
+
{text}
|
|
13
|
+
</button>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default DefaultMiniButton;
|
|
@@ -2,10 +2,14 @@ import React from "react";
|
|
|
2
2
|
import { ButtonBaseProps } from "./base";
|
|
3
3
|
|
|
4
4
|
const PrimaryButton: React.FC<ButtonBaseProps> = (props) => {
|
|
5
|
-
const { text, onClick, disabled } = props;
|
|
5
|
+
const { text, onClick, disabled, className } = props;
|
|
6
|
+
let btnClassName = "inline-flex items-center rounded border border-transparent bg-indigo-600 px-2.5 py-1.5 text-xs font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
7
|
+
if (className) {
|
|
8
|
+
btnClassName = btnClassName + " " + className;
|
|
9
|
+
}
|
|
6
10
|
return (
|
|
7
11
|
<button
|
|
8
|
-
className=
|
|
12
|
+
className={btnClassName}
|
|
9
13
|
onClick={onClick}
|
|
10
14
|
disabled={disabled}
|
|
11
15
|
>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ButtonBaseProps } from "./base";
|
|
3
|
+
|
|
4
|
+
const PrimaryMiniButton: React.FC<ButtonBaseProps> = (props) => {
|
|
5
|
+
const { text, onClick, disabled, className } = props;
|
|
6
|
+
let btnClassName = "inline-block min-w-96 text-xs ml-2 pt-1 pb-1 pl-6 pr-6 border border-gray-800 bg-gray-800 text-white rounded-sm hover:bg-white dark:bg-zinc-900 border-gray-800 hover:text-gray-800 cursor-pointer disabled:bg-gray-400 disabled:border-gray-400 disabled:text-white disabled:cursor-not-allowed disabled:text-white"
|
|
7
|
+
if (className) {
|
|
8
|
+
btnClassName = btnClassName + " " + className;
|
|
9
|
+
}
|
|
10
|
+
return (
|
|
11
|
+
<button
|
|
12
|
+
className={btnClassName}
|
|
13
|
+
onClick={onClick}
|
|
14
|
+
disabled={disabled}
|
|
15
|
+
>
|
|
16
|
+
{text}
|
|
17
|
+
</button>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default PrimaryMiniButton;
|
|
@@ -27,6 +27,9 @@ const Bubble = styled.div`
|
|
|
27
27
|
transform: translate(-50%, -50%) rotate(45deg);
|
|
28
28
|
background-color: #fff;
|
|
29
29
|
border-radius: 1px;
|
|
30
|
+
@media (prefers-color-scheme: dark) {
|
|
31
|
+
background-color: #000;
|
|
32
|
+
}
|
|
30
33
|
}
|
|
31
34
|
`;
|
|
32
35
|
|
|
@@ -49,7 +52,7 @@ const Callout = memo<CalloutProps>(function Callout({ target, children }) {
|
|
|
49
52
|
root &&
|
|
50
53
|
pos &&
|
|
51
54
|
createPortal(
|
|
52
|
-
<Bubble role="dialog" className="fixed bg-white z-50" style={{ left: pos[0], top: pos[1] + 4 }}>
|
|
55
|
+
<Bubble role="dialog" className="fixed bg-white dark:bg-zinc-900 z-50" style={{ left: pos[0], top: pos[1] + 4 }}>
|
|
53
56
|
{children}
|
|
54
57
|
</Bubble>,
|
|
55
58
|
root
|
|
@@ -8,9 +8,11 @@ const MenuContainer = styled.div`
|
|
|
8
8
|
position: absolute;
|
|
9
9
|
z-index: 99;
|
|
10
10
|
cursor: pointer;
|
|
11
|
-
/* box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.09); */
|
|
12
|
-
/* border-radius: 2px; */
|
|
13
11
|
padding: 4px;
|
|
12
|
+
@media (prefers-color-scheme: dark) {
|
|
13
|
+
background-color: #000;
|
|
14
|
+
border: 1px solid #4b5563;
|
|
15
|
+
}
|
|
14
16
|
`;
|
|
15
17
|
interface ClickMenuProps {
|
|
16
18
|
x: number;
|
|
@@ -5,6 +5,11 @@ export const Container = styled.div`
|
|
|
5
5
|
padding: 1em;
|
|
6
6
|
margin: 1em;
|
|
7
7
|
background-color: #fff;
|
|
8
|
+
// dark theme
|
|
9
|
+
@media (prefers-color-scheme: dark) {
|
|
10
|
+
background-color: #000;
|
|
11
|
+
border: 1px solid #4b5563;
|
|
12
|
+
}
|
|
8
13
|
`;
|
|
9
14
|
|
|
10
15
|
export const NestContainer = styled.div`
|
|
@@ -13,4 +18,8 @@ export const NestContainer = styled.div`
|
|
|
13
18
|
font-size: 12px;
|
|
14
19
|
margin: 0.2em;
|
|
15
20
|
background-color: #fff;
|
|
21
|
+
@media (prefers-color-scheme: dark) {
|
|
22
|
+
background-color: #000;
|
|
23
|
+
border: 1px solid #4b5563;
|
|
24
|
+
}
|
|
16
25
|
`;
|
|
@@ -3,6 +3,8 @@ import styled from "styled-components";
|
|
|
3
3
|
import { IMutField, IRow } from "../../interfaces";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import Pagination from "./pagination";
|
|
6
|
+
import { ChevronUpDownIcon } from "@heroicons/react/24/outline";
|
|
7
|
+
import DropdownContext from "../dropdownContext";
|
|
6
8
|
|
|
7
9
|
interface DataTableProps {
|
|
8
10
|
size?: number;
|
|
@@ -18,16 +20,6 @@ const Container = styled.div`
|
|
|
18
20
|
box-sizing: content-box;
|
|
19
21
|
border-collapse: collapse;
|
|
20
22
|
font-size: 12px;
|
|
21
|
-
thead {
|
|
22
|
-
th {
|
|
23
|
-
}
|
|
24
|
-
th.number {
|
|
25
|
-
border-top: 3px solid #5cdbd3;
|
|
26
|
-
}
|
|
27
|
-
th.text {
|
|
28
|
-
border-top: 3px solid #69c0ff;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
23
|
tbody {
|
|
32
24
|
td {
|
|
33
25
|
}
|
|
@@ -50,17 +42,17 @@ function getHeaderType(field: IMutField): "number" | "text" {
|
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
function getHeaderClassNames(field: IMutField) {
|
|
53
|
-
return field.analyticType === "dimension" ? "border-t-4 border-blue-400" : "border-t-4 border-
|
|
45
|
+
return field.analyticType === "dimension" ? "border-t-4 border-blue-400" : "border-t-4 border-purple-400";
|
|
54
46
|
}
|
|
55
47
|
|
|
56
48
|
function getSemanticColors(field: IMutField): string {
|
|
57
49
|
switch (field.semanticType) {
|
|
58
50
|
case "nominal":
|
|
59
|
-
return "bg-
|
|
51
|
+
return "bg-sky-100 text-sky-800";
|
|
60
52
|
case "ordinal":
|
|
61
|
-
return "bg-
|
|
53
|
+
return "bg-indigo-100 text-indigo-800";
|
|
62
54
|
case "quantitative":
|
|
63
|
-
return "bg-
|
|
55
|
+
return "bg-purple-100 text-purple-800";
|
|
64
56
|
case "temporal":
|
|
65
57
|
return "bg-yellow-100 text-yellow-800";
|
|
66
58
|
default:
|
|
@@ -91,7 +83,7 @@ const DataTable: React.FC<DataTableProps> = (props) => {
|
|
|
91
83
|
const to = Math.min((pageIndex + 1) * size, data.length - 1);
|
|
92
84
|
|
|
93
85
|
return (
|
|
94
|
-
<Container className="rounded border-gray-200 border">
|
|
86
|
+
<Container className="rounded border-gray-200 dark:border-gray-700 border">
|
|
95
87
|
<Pagination
|
|
96
88
|
total={data.length}
|
|
97
89
|
from={from + 1}
|
|
@@ -103,74 +95,72 @@ const DataTable: React.FC<DataTableProps> = (props) => {
|
|
|
103
95
|
setPageIndex(Math.max(0, pageIndex - 1));
|
|
104
96
|
}}
|
|
105
97
|
/>
|
|
106
|
-
<table className="min-w-full divide-y
|
|
107
|
-
<thead className="bg-gray-50">
|
|
108
|
-
<tr className="divide-x divide-gray-200">
|
|
98
|
+
<table className="min-w-full divide-y">
|
|
99
|
+
<thead className="bg-gray-50 dark:bg-gray-900">
|
|
100
|
+
<tr className="divide-x divide-gray-200 dark:divide-gray-600">
|
|
109
101
|
{metas.map((field, fIndex) => (
|
|
110
102
|
<th key={field.fid} className={""}>
|
|
111
103
|
<div
|
|
112
104
|
className={
|
|
113
105
|
getHeaderClassNames(field) +
|
|
114
|
-
" whitespace-nowrap py-3.5 px-6 text-left text-xs font-semibold text-gray-900 sm:pl-6"
|
|
106
|
+
" whitespace-nowrap py-3.5 px-6 text-left text-xs font-semibold text-gray-900 dark:text-gray-50 sm:pl-6"
|
|
115
107
|
}
|
|
116
108
|
>
|
|
117
109
|
<b>{field.name || field.fid}</b>
|
|
118
110
|
<div>
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
(field.analyticType === "dimension" ? "bg-blue-500" : "bg-teal-500")
|
|
123
|
-
}
|
|
124
|
-
// className="border-b border-gray-200 bg-gray-50 pl-0 mt-2 font-light"
|
|
125
|
-
value={field.analyticType}
|
|
126
|
-
onChange={(e) => {
|
|
111
|
+
<DropdownContext
|
|
112
|
+
options={analyticTypeList}
|
|
113
|
+
onSelect={(value) => {
|
|
127
114
|
onMetaChange(field.fid, fIndex, {
|
|
128
|
-
analyticType:
|
|
115
|
+
analyticType: value as IMutField["analyticType"],
|
|
129
116
|
});
|
|
130
117
|
}}
|
|
131
118
|
>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
119
|
+
<span
|
|
120
|
+
className={
|
|
121
|
+
"cursor-pointer inline-flex px-2.5 py-0.5 text-xs font-medium mt-1 rounded-full text-xs text-white " +
|
|
122
|
+
(field.analyticType === "dimension" ? "bg-blue-500" : "bg-purple-500")
|
|
123
|
+
}
|
|
124
|
+
>
|
|
125
|
+
{field.analyticType}
|
|
126
|
+
<ChevronUpDownIcon className="ml-2 w-3" />
|
|
127
|
+
</span>
|
|
128
|
+
</DropdownContext>
|
|
138
129
|
</div>
|
|
139
130
|
<div>
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
getSemanticColors(field)
|
|
144
|
-
}
|
|
145
|
-
// className="border-b border-gray-200 bg-gray-50 pl-0 mt-2 font-light"
|
|
146
|
-
value={field.semanticType}
|
|
147
|
-
onChange={(e) => {
|
|
131
|
+
<DropdownContext
|
|
132
|
+
options={semanticTypeList}
|
|
133
|
+
onSelect={(value) => {
|
|
148
134
|
onMetaChange(field.fid, fIndex, {
|
|
149
|
-
semanticType:
|
|
135
|
+
semanticType: value as IMutField["semanticType"],
|
|
150
136
|
});
|
|
151
137
|
}}
|
|
152
138
|
>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
139
|
+
<span
|
|
140
|
+
className={
|
|
141
|
+
"cursor-pointer inline-flex px-2.5 py-0.5 text-xs font-medium mt-1 rounded-full text-xs " +
|
|
142
|
+
getSemanticColors(field)
|
|
143
|
+
}
|
|
144
|
+
>
|
|
145
|
+
{field.semanticType}
|
|
146
|
+
<ChevronUpDownIcon className="ml-2 w-3" />
|
|
147
|
+
</span>
|
|
148
|
+
</DropdownContext>
|
|
159
149
|
</div>
|
|
160
150
|
</div>
|
|
161
151
|
</th>
|
|
162
152
|
))}
|
|
163
153
|
</tr>
|
|
164
154
|
</thead>
|
|
165
|
-
<tbody className="divide-y divide-gray-
|
|
155
|
+
<tbody className="divide-y divide-gray-100 dark:divide-gray-600 bg-white dark:bg-zinc-900">
|
|
166
156
|
{data.slice(from, to).map((row, index) => (
|
|
167
|
-
<tr className={"divide-x divide-gray-200 " + (index % 2 ? "bg-gray-50" : "")} key={index}>
|
|
157
|
+
<tr className={"divide-x divide-gray-200 dark:divide-gray-600 " + (index % 2 ? "bg-gray-50 dark:bg-gray-800" : "")} key={index}>
|
|
168
158
|
{metas.map((field) => (
|
|
169
159
|
<td
|
|
170
160
|
key={field.fid + index}
|
|
171
161
|
className={
|
|
172
162
|
getHeaderType(field) +
|
|
173
|
-
" whitespace-nowrap py-2 pl-4 pr-3 text-xs text-gray-500 sm:pl-6"
|
|
163
|
+
" whitespace-nowrap py-2 pl-4 pr-3 text-xs text-gray-500 dark:text-gray-300 sm:pl-6"
|
|
174
164
|
}
|
|
175
165
|
>
|
|
176
166
|
{row[field.fid]}
|
|
@@ -12,11 +12,11 @@ export default function Pagination(props: PaginationProps) {
|
|
|
12
12
|
const { t } = useTranslation();
|
|
13
13
|
return (
|
|
14
14
|
<nav
|
|
15
|
-
className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6"
|
|
15
|
+
className="flex items-center justify-between border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-zinc-900 px-4 py-3 sm:px-6"
|
|
16
16
|
aria-label="Pagination"
|
|
17
17
|
>
|
|
18
18
|
<div className="hidden sm:block">
|
|
19
|
-
<p className="text-sm text-gray-
|
|
19
|
+
<p className="text-sm text-gray-800 dark:text-gray-100">
|
|
20
20
|
Showing <span className="font-medium">{from}</span> to <span className="font-medium">{to}</span> of{" "}
|
|
21
21
|
<span className="font-medium">{total}</span> results
|
|
22
22
|
</p>
|
|
@@ -26,7 +26,7 @@ export default function Pagination(props: PaginationProps) {
|
|
|
26
26
|
onClick={() => {
|
|
27
27
|
onPrev();
|
|
28
28
|
}}
|
|
29
|
-
className="relative inline-flex items-center rounded-md border border-gray-300 bg-white px-
|
|
29
|
+
className="relative inline-flex items-center rounded-md border border-gray-300 bg-white dark:bg-zinc-900 px-2.5 py-1.5 text-xs font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
30
30
|
>
|
|
31
31
|
{t('actions.prev')}
|
|
32
32
|
</button>
|
|
@@ -34,7 +34,7 @@ export default function Pagination(props: PaginationProps) {
|
|
|
34
34
|
onClick={() => {
|
|
35
35
|
onNext()
|
|
36
36
|
}}
|
|
37
|
-
className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-
|
|
37
|
+
className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white dark:bg-zinc-900 px-2.5 py-1.5 text-xs font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
38
38
|
>
|
|
39
39
|
{t('actions.next')}
|
|
40
40
|
</button>
|
|
@@ -6,7 +6,7 @@ const DataTypeIcon: React.FC<{ dataType: IMutField["semanticType"]; analyticType
|
|
|
6
6
|
props
|
|
7
7
|
) => {
|
|
8
8
|
const { dataType, analyticType } = props;
|
|
9
|
-
const color = analyticType === "dimension" ? "text-blue-500" : "text-
|
|
9
|
+
const color = analyticType === "dimension" ? "text-blue-500" : "text-purple-500";
|
|
10
10
|
const iconClassName = `w-3 inline-block mr-0.5 ${color}`;
|
|
11
11
|
switch (dataType) {
|
|
12
12
|
case "quantitative":
|