@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.
Files changed (87) hide show
  1. package/dist/App.d.ts +4 -2
  2. package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
  3. package/dist/components/button/base.d.ts +1 -0
  4. package/dist/components/button/defaultMini.d.ts +4 -0
  5. package/dist/components/button/primaryMini.d.ts +4 -0
  6. package/dist/components/dropdownContext/index.d.ts +13 -0
  7. package/dist/components/dropdownSelect/index.d.ts +17 -0
  8. package/dist/components/modal.d.ts +1 -0
  9. package/dist/components/toolbar/toolbar-item.d.ts +1 -0
  10. package/dist/dataSource/dataSelection/config.d.ts +2 -0
  11. package/dist/dataSource/index.d.ts +1 -1
  12. package/dist/fields/datasetFields/dimFields.d.ts +2 -2
  13. package/dist/fields/datasetFields/meaFields.d.ts +2 -2
  14. package/dist/fields/encodeFields/singleEncodeDropDown.d.ts +17 -0
  15. package/dist/fields/encodeFields/singleEncodeEditor.d.ts +11 -0
  16. package/dist/fields/obComponents/obPill.d.ts +3 -3
  17. package/dist/graphic-walker.es.js +20874 -19172
  18. package/dist/graphic-walker.es.js.map +1 -1
  19. package/dist/graphic-walker.umd.js +245 -170
  20. package/dist/graphic-walker.umd.js.map +1 -1
  21. package/dist/insightBoard/index.d.ts +1 -1
  22. package/dist/interfaces.d.ts +1 -0
  23. package/dist/renderer/index.d.ts +3 -1
  24. package/dist/store/visualSpecStore.d.ts +1 -0
  25. package/dist/utils/index.d.ts +2 -0
  26. package/dist/utils/media.d.ts +2 -0
  27. package/dist/vis/react-vega.d.ts +2 -0
  28. package/dist/vis/theme.d.ts +130 -0
  29. package/package.json +2 -1
  30. package/src/App.tsx +8 -5
  31. package/src/components/button/base.ts +1 -0
  32. package/src/components/button/default.tsx +6 -2
  33. package/src/components/button/defaultMini.tsx +17 -0
  34. package/src/components/button/primary.tsx +6 -2
  35. package/src/components/button/primaryMini.tsx +21 -0
  36. package/src/components/callout.tsx +4 -1
  37. package/src/components/clickMenu.tsx +4 -2
  38. package/src/components/container.tsx +9 -0
  39. package/src/components/dataTable/index.tsx +42 -52
  40. package/src/components/dataTable/pagination.tsx +4 -4
  41. package/src/components/dataTypeIcon.tsx +1 -1
  42. package/src/components/dropdownContext/index.tsx +64 -0
  43. package/src/components/dropdownSelect/index.tsx +92 -0
  44. package/src/components/modal.tsx +26 -14
  45. package/src/components/tabs/defaultTab.tsx +4 -4
  46. package/src/components/tabs/editableTab.tsx +5 -5
  47. package/src/components/toolbar/components.tsx +18 -1
  48. package/src/components/toolbar/index.tsx +5 -0
  49. package/src/components/toolbar/toolbar-button.tsx +6 -1
  50. package/src/components/toolbar/toolbar-item.tsx +4 -0
  51. package/src/components/toolbar/toolbar-select-button.tsx +21 -4
  52. package/src/components/toolbar/toolbar-toggle-button.tsx +6 -1
  53. package/src/components/tooltip.tsx +4 -1
  54. package/src/dataSource/dataSelection/config.ts +28 -0
  55. package/src/dataSource/dataSelection/csvData.tsx +77 -32
  56. package/src/dataSource/dataSelection/gwFile.tsx +0 -8
  57. package/src/dataSource/dataSelection/index.tsx +1 -2
  58. package/src/dataSource/dataSelection/publicData.tsx +2 -3
  59. package/src/dataSource/index.tsx +81 -61
  60. package/src/fields/aestheticFields.tsx +3 -1
  61. package/src/fields/components.tsx +21 -2
  62. package/src/fields/datasetFields/dimFields.tsx +43 -35
  63. package/src/fields/datasetFields/index.tsx +2 -2
  64. package/src/fields/datasetFields/meaFields.tsx +73 -47
  65. package/src/fields/encodeFields/singleEncodeDropDown.tsx +92 -0
  66. package/src/fields/encodeFields/singleEncodeEditor.tsx +78 -0
  67. package/src/fields/filterField/filterEditDialog.tsx +2 -1
  68. package/src/fields/filterField/filterPill.tsx +1 -1
  69. package/src/fields/filterField/slider.tsx +1 -1
  70. package/src/fields/filterField/tabs.tsx +11 -21
  71. package/src/fields/obComponents/obPill.tsx +65 -35
  72. package/src/index.css +13 -0
  73. package/src/insightBoard/index.tsx +24 -23
  74. package/src/insightBoard/radioGroupButtons.tsx +7 -0
  75. package/src/interfaces.ts +1 -0
  76. package/src/lib/inferMeta.ts +1 -1
  77. package/src/locales/en-US.json +7 -4
  78. package/src/locales/zh-CN.json +5 -2
  79. package/src/main.tsx +1 -1
  80. package/src/renderer/index.tsx +2 -1
  81. package/src/store/visualSpecStore.ts +16 -0
  82. package/src/utils/index.ts +19 -0
  83. package/src/utils/media.ts +26 -0
  84. package/src/utils/normalization.ts +2 -1
  85. package/src/vis/react-vega.tsx +20 -4
  86. package/src/vis/theme.ts +126 -0
  87. package/src/visualSettings/index.tsx +24 -8
@@ -1,3 +1,3 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  declare const _default: React.FunctionComponent<{}>;
3
3
  export default _default;
@@ -104,6 +104,7 @@ export interface DraggableFieldState {
104
104
  shape: IViewField[];
105
105
  theta: IViewField[];
106
106
  radius: IViewField[];
107
+ details: IViewField[];
107
108
  filters: IFilterField[];
108
109
  }
109
110
  export interface IDraggableStateKey {
@@ -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<React.RefAttributes<IReactVegaHandler>, "key"> & React.RefAttributes<IReactVegaHandler>>>;
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;
@@ -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[];
@@ -0,0 +1,2 @@
1
+ export declare function currentMediaTheme(): "dark" | "light";
2
+ export declare function useCurrentMediaTheme(): "dark" | "light";
@@ -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.13",
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: React.FC<IGWProps> = (props) => {
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 observer(App);
192
+ export default App;
@@ -4,4 +4,5 @@ export interface ButtonBaseProps {
4
4
  onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
5
5
  text: string;
6
6
  disabled?: boolean;
7
+ className?: string;
7
8
  }
@@ -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="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"
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="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 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"
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-teal-400";
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-indigo-100 text-indigo-800";
51
+ return "bg-sky-100 text-sky-800";
60
52
  case "ordinal":
61
- return "bg-purple-100 text-purple-800";
53
+ return "bg-indigo-100 text-indigo-800";
62
54
  case "quantitative":
63
- return "bg-green-100 text-green-800";
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 divide-gray-30">
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
- <select
120
- className={
121
- "px-2 py font-normal mt-2 rounded-full text-xs text-white " +
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: e.target.value as IMutField["analyticType"],
115
+ analyticType: value as IMutField["analyticType"],
129
116
  });
130
117
  }}
131
118
  >
132
- {analyticTypeList.map((type) => (
133
- <option key={type.value} value={type.value}>
134
- {type.label}
135
- </option>
136
- ))}
137
- </select>
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
- <select
141
- className={
142
- "inline-block px-2.5 py-0.5 text-xs font-medium mt-1 rounded-full text-xs text-white " +
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: e.target.value as IMutField["semanticType"],
135
+ semanticType: value as IMutField["semanticType"],
150
136
  });
151
137
  }}
152
138
  >
153
- {semanticTypeList.map((type) => (
154
- <option key={type.value} value={type.value}>
155
- {type.label}
156
- </option>
157
- ))}
158
- </select>
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-200 bg-white">
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-700">
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-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
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-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
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-green-500";
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":