@kanaries/graphic-walker 0.2.13 → 0.2.15

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 (99) hide show
  1. package/dist/App.d.ts +6 -3
  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/callout.d.ts +2 -0
  7. package/dist/components/dropdownContext/index.d.ts +13 -0
  8. package/dist/components/dropdownSelect/index.d.ts +17 -0
  9. package/dist/components/modal.d.ts +1 -0
  10. package/dist/components/toolbar/components.d.ts +4 -1
  11. package/dist/components/toolbar/index.d.ts +2 -0
  12. package/dist/components/toolbar/toolbar-item.d.ts +4 -0
  13. package/dist/components/tooltip.d.ts +2 -0
  14. package/dist/dataSource/dataSelection/config.d.ts +2 -0
  15. package/dist/dataSource/index.d.ts +1 -1
  16. package/dist/fields/components.d.ts +0 -1
  17. package/dist/fields/datasetFields/dimFields.d.ts +2 -2
  18. package/dist/fields/datasetFields/meaFields.d.ts +2 -2
  19. package/dist/fields/encodeFields/singleEncodeDropDown.d.ts +17 -0
  20. package/dist/fields/encodeFields/singleEncodeEditor.d.ts +11 -0
  21. package/dist/fields/filterField/filterEditDialog.d.ts +1 -1
  22. package/dist/fields/obComponents/obPill.d.ts +3 -3
  23. package/dist/graphic-walker.es.js +21205 -19397
  24. package/dist/graphic-walker.es.js.map +1 -1
  25. package/dist/graphic-walker.umd.js +181 -236
  26. package/dist/graphic-walker.umd.js.map +1 -1
  27. package/dist/insightBoard/index.d.ts +1 -1
  28. package/dist/interfaces.d.ts +3 -0
  29. package/dist/renderer/index.d.ts +7 -3
  30. package/dist/store/visualSpecStore.d.ts +1 -0
  31. package/dist/utils/index.d.ts +2 -0
  32. package/dist/utils/media.d.ts +3 -0
  33. package/dist/vis/react-vega.d.ts +5 -1
  34. package/dist/vis/theme.d.ts +146 -0
  35. package/dist/visualSettings/index.d.ts +2 -1
  36. package/package.json +2 -1
  37. package/src/App.tsx +24 -16
  38. package/src/components/button/base.ts +1 -0
  39. package/src/components/button/default.tsx +6 -2
  40. package/src/components/button/defaultMini.tsx +17 -0
  41. package/src/components/button/primary.tsx +6 -2
  42. package/src/components/button/primaryMini.tsx +21 -0
  43. package/src/components/callout.tsx +9 -4
  44. package/src/components/clickMenu.tsx +1 -5
  45. package/src/components/dataTable/index.tsx +42 -52
  46. package/src/components/dataTable/pagination.tsx +4 -4
  47. package/src/components/dataTypeIcon.tsx +1 -1
  48. package/src/components/dropdownContext/index.tsx +64 -0
  49. package/src/components/dropdownSelect/index.tsx +92 -0
  50. package/src/components/modal.tsx +20 -22
  51. package/src/components/sizeSetting.tsx +2 -2
  52. package/src/components/tabs/defaultTab.tsx +4 -4
  53. package/src/components/tabs/editableTab.tsx +5 -5
  54. package/src/components/toolbar/components.tsx +10 -8
  55. package/src/components/toolbar/index.tsx +16 -4
  56. package/src/components/toolbar/toolbar-button.tsx +8 -2
  57. package/src/components/toolbar/toolbar-item.tsx +18 -9
  58. package/src/components/toolbar/toolbar-select-button.tsx +21 -8
  59. package/src/components/toolbar/toolbar-toggle-button.tsx +8 -2
  60. package/src/components/tooltip.tsx +10 -3
  61. package/src/dataSource/dataSelection/config.ts +28 -0
  62. package/src/dataSource/dataSelection/csvData.tsx +77 -32
  63. package/src/dataSource/dataSelection/gwFile.tsx +0 -8
  64. package/src/dataSource/dataSelection/index.tsx +1 -2
  65. package/src/dataSource/dataSelection/publicData.tsx +2 -3
  66. package/src/dataSource/index.tsx +80 -61
  67. package/src/fields/aestheticFields.tsx +3 -1
  68. package/src/fields/components.tsx +20 -38
  69. package/src/fields/datasetFields/dimFields.tsx +43 -35
  70. package/src/fields/datasetFields/index.tsx +3 -4
  71. package/src/fields/datasetFields/meaFields.tsx +73 -47
  72. package/src/fields/encodeFields/singleEncodeDropDown.tsx +92 -0
  73. package/src/fields/encodeFields/singleEncodeEditor.tsx +78 -0
  74. package/src/fields/filterField/filterEditDialog.tsx +63 -98
  75. package/src/fields/filterField/filterPill.tsx +1 -1
  76. package/src/fields/filterField/slider.tsx +2 -2
  77. package/src/fields/filterField/tabs.tsx +11 -21
  78. package/src/fields/obComponents/obPill.tsx +65 -35
  79. package/src/index.css +13 -0
  80. package/src/insightBoard/index.tsx +24 -23
  81. package/src/insightBoard/mainBoard.tsx +9 -2
  82. package/src/insightBoard/radioGroupButtons.tsx +7 -0
  83. package/src/interfaces.ts +5 -1
  84. package/src/lib/inferMeta.ts +1 -1
  85. package/src/locales/en-US.json +11 -5
  86. package/src/locales/i18n.ts +7 -0
  87. package/src/locales/ja-JP.json +195 -0
  88. package/src/locales/zh-CN.json +9 -3
  89. package/src/main.tsx +1 -1
  90. package/src/renderer/index.tsx +96 -70
  91. package/src/store/visualSpecStore.ts +16 -0
  92. package/src/utils/index.ts +19 -0
  93. package/src/utils/media.ts +31 -0
  94. package/src/utils/normalization.ts +2 -1
  95. package/src/vis/react-vega.tsx +36 -5
  96. package/src/vis/theme.ts +124 -0
  97. package/src/visualSettings/index.tsx +29 -33
  98. package/dist/components/container.d.ts +0 -2
  99. package/src/components/container.tsx +0 -16
@@ -8,17 +8,23 @@ export interface ToolbarButtonItem extends IToolbarItem {
8
8
  }
9
9
 
10
10
  const ToolbarButton = memo<IToolbarProps<ToolbarButtonItem>>(function ToolbarButton(props) {
11
- const { item, styles } = props;
11
+ const { item, styles, darkModePreference } = props;
12
12
  const { icon: Icon, label, disabled, onClick } = item;
13
13
  const handlers = useHandlers(() => onClick?.(), disabled ?? false);
14
14
 
15
+ const mergedIconStyles = {
16
+ ...styles?.icon,
17
+ ...item.styles?.icon,
18
+ };
19
+
15
20
  return (
16
21
  <>
17
22
  <ToolbarItemContainer
18
23
  props={props}
19
24
  handlers={onClick ? handlers : null}
25
+ darkModePreference={darkModePreference}
20
26
  >
21
- <Icon style={styles?.icon} />
27
+ <Icon style={mergedIconStyles} />
22
28
  </ToolbarItemContainer>
23
29
  </>
24
30
  );
@@ -8,6 +8,7 @@ import { ToolbarContainer, ToolbarItemContainerElement, ToolbarSplitter, useHand
8
8
  import Toolbar, { ToolbarProps } from ".";
9
9
  import Tooltip from "../tooltip";
10
10
  import Callout from "../callout";
11
+ import { useCurrentMediaTheme } from "../../utils/media";
11
12
 
12
13
 
13
14
  const ToolbarSplit = styled.div<{ open: boolean }>`
@@ -34,7 +35,7 @@ const ToolbarSplit = styled.div<{ open: boolean }>`
34
35
  const FormContainer = styled(ToolbarContainer)`
35
36
  width: max-content;
36
37
  height: max-content;
37
- background-color: #fff;
38
+ background-color: ${({ dark }) => dark ? '#000' : '#fff'};
38
39
  `;
39
40
 
40
41
  export interface IToolbarItem {
@@ -48,6 +49,7 @@ export interface IToolbarItem {
48
49
  disabled?: boolean;
49
50
  menu?: ToolbarProps;
50
51
  form?: JSX.Element;
52
+ styles?: Partial<Pick<NonNullable<ToolbarProps['styles']>, 'item' | 'icon' | 'splitIcon'>>;
51
53
  }
52
54
 
53
55
  export const ToolbarItemSplitter = '-';
@@ -61,6 +63,7 @@ export type ToolbarItemProps = (
61
63
 
62
64
  export interface IToolbarProps<P extends Exclude<ToolbarItemProps, typeof ToolbarItemSplitter> = Exclude<ToolbarItemProps, typeof ToolbarItemSplitter>> {
63
65
  item: P;
66
+ darkModePreference: NonNullable<ToolbarProps['darkModePreference']>;
64
67
  styles?: ToolbarProps['styles'];
65
68
  openedKey: string | null;
66
69
  setOpenedKey: (key: string | null) => void;
@@ -70,6 +73,7 @@ export interface IToolbarProps<P extends Exclude<ToolbarItemProps, typeof Toolba
70
73
  let idFlag = 0;
71
74
 
72
75
  export const ToolbarItemContainer = memo<{
76
+ darkModePreference: NonNullable<ToolbarProps['darkModePreference']>;
73
77
  props: IToolbarProps;
74
78
  handlers: ReturnType<typeof useHandlers> | null;
75
79
  children: unknown;
@@ -80,6 +84,7 @@ export const ToolbarItemContainer = memo<{
80
84
  styles, openedKey, setOpenedKey, renderSlot,
81
85
  },
82
86
  handlers,
87
+ darkModePreference,
83
88
  children,
84
89
  ...props
85
90
  }
@@ -126,15 +131,18 @@ export const ToolbarItemContainer = memo<{
126
131
 
127
132
  useEffect(() => {
128
133
  if (opened && menu) {
129
- renderSlot(<Toolbar {...menu} />);
134
+ renderSlot(<Toolbar {...menu} darkModePreference={darkModePreference} />);
130
135
  return () => renderSlot(null);
131
136
  }
132
137
  }, [opened, menu, renderSlot]);
133
138
 
139
+ const dark = useCurrentMediaTheme(darkModePreference) === 'dark';
140
+
134
141
  return (
135
142
  <>
136
- <Tooltip content={label}>
143
+ <Tooltip content={label} darkModePreference={darkModePreference}>
137
144
  <ToolbarItemContainerElement
145
+ dark={dark}
138
146
  role="button" tabIndex={disabled ? undefined : 0} aria-label={label} aria-disabled={disabled ?? false}
139
147
  split={Boolean(form || menu)}
140
148
  style={styles?.item}
@@ -186,8 +194,8 @@ export const ToolbarItemContainer = memo<{
186
194
  </ToolbarItemContainerElement>
187
195
  </Tooltip>
188
196
  {opened && form && (
189
- <Callout target={`#${id}`}>
190
- <FormContainer onMouseDown={e => e.stopPropagation()}>
197
+ <Callout target={`#${id}`} darkModePreference={darkModePreference}>
198
+ <FormContainer dark={dark} onMouseDown={e => e.stopPropagation()}>
191
199
  {form}
192
200
  </FormContainer>
193
201
  </Callout>
@@ -198,20 +206,21 @@ export const ToolbarItemContainer = memo<{
198
206
 
199
207
  const ToolbarItem = memo<{
200
208
  item: ToolbarItemProps;
209
+ darkModePreference: NonNullable<ToolbarProps['darkModePreference']>;
201
210
  styles?: ToolbarProps['styles'];
202
211
  openedKey: string | null;
203
212
  setOpenedKey: (key: string | null) => void;
204
213
  renderSlot: (node: ReactNode) => void;
205
- }>(function ToolbarItem ({ item, styles, openedKey, setOpenedKey, renderSlot }) {
214
+ }>(function ToolbarItem ({ item, styles, openedKey, setOpenedKey, renderSlot, darkModePreference }) {
206
215
  if (item === ToolbarItemSplitter) {
207
216
  return <ToolbarSplitter />;
208
217
  }
209
218
  if ('checked' in item) {
210
- return <ToolbarToggleButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} />;
219
+ return <ToolbarToggleButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} darkModePreference={darkModePreference} />;
211
220
  } else if ('options' in item) {
212
- return <ToolbarSelectButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} />;
221
+ return <ToolbarSelectButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} darkModePreference={darkModePreference} />;
213
222
  }
214
- return <ToolbarButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} />;
223
+ return <ToolbarButton item={item} styles={styles} openedKey={openedKey} setOpenedKey={setOpenedKey} renderSlot={renderSlot} darkModePreference={darkModePreference} />;
215
224
  });
216
225
 
217
226
 
@@ -4,6 +4,7 @@ import produce from "immer";
4
4
  import { IToolbarItem, IToolbarProps, ToolbarItemContainer } from "./toolbar-item";
5
5
  import { ToolbarContainer, useHandlers, ToolbarItemContainerElement } from "./components";
6
6
  import Callout from "../callout";
7
+ import { useCurrentMediaTheme } from "../../utils/media";
7
8
 
8
9
 
9
10
  const OptionGroup = styled(ToolbarContainer)`
@@ -16,7 +17,12 @@ const OptionGroup = styled(ToolbarContainer)`
16
17
  --color: #777;
17
18
  --color-hover: #555;
18
19
  --blue: #282958;
19
- background-color: var(--background-color);
20
+ --dark-mode-background-color: #1f1f1f;
21
+ --dark-mode-background-color-hover: #2f2f2f;
22
+ --dark-mode-color: #aaa;
23
+ --dark-mode-color-hover: #ccc;
24
+ --dark-mode-blue: #282958;
25
+ background-color: ${({ dark }) => dark ? 'var(--dark-mode-background-color)' : 'var(--background-color)'};
20
26
  `;
21
27
 
22
28
  const Option = styled(ToolbarItemContainerElement)`
@@ -71,7 +77,7 @@ export interface ToolbarSelectButtonItem<T extends string = string> extends IToo
71
77
  }
72
78
 
73
79
  const ToolbarSelectButton = memo<IToolbarProps<ToolbarSelectButtonItem>>(function ToolbarSelectButton(props) {
74
- const { item, styles, openedKey, setOpenedKey } = props;
80
+ const { darkModePreference, item, styles, openedKey, setOpenedKey } = props;
75
81
  const { key, icon: Icon, disabled, options, value, onSelect } = item;
76
82
  const id = `${key}::button`;
77
83
 
@@ -115,9 +121,17 @@ const ToolbarSelectButton = memo<IToolbarProps<ToolbarSelectButtonItem>>(functio
115
121
  const currentOption = options.find(opt => opt.key === value);
116
122
  const CurrentIcon = currentOption?.icon;
117
123
 
124
+ const mergedIconStyles = {
125
+ ...styles?.icon,
126
+ ...item.styles?.icon,
127
+ };
128
+
129
+ const dark = useCurrentMediaTheme(darkModePreference) === 'dark';
130
+
118
131
  return (
119
132
  <>
120
133
  <ToolbarItemContainer
134
+ darkModePreference={darkModePreference}
121
135
  props={produce(props, draft => {
122
136
  if (currentOption) {
123
137
  draft.item.label = `${draft.item.label}: ${currentOption.label}`;
@@ -126,28 +140,26 @@ const ToolbarSelectButton = memo<IToolbarProps<ToolbarSelectButtonItem>>(functio
126
140
  handlers={handlers}
127
141
  aria-haspopup="listbox"
128
142
  >
129
- <Icon style={styles?.icon} />
143
+ <Icon style={mergedIconStyles} />
130
144
  {CurrentIcon && (
131
145
  <CurrentIcon
132
146
  style={{
133
- ...styles?.icon,
134
147
  position: 'absolute',
135
148
  left: 'calc(var(--height) - var(--icon-size) * 1.2)',
136
149
  bottom: 'calc((var(--height) - var(--icon-size)) * 0.1)',
137
150
  width: 'calc(var(--icon-size) * 0.6)',
138
151
  height: 'calc(var(--icon-size) * 0.6)',
139
152
  margin: 'calc((var(--height) - var(--icon-size)) * 0.2)',
140
- filter: 'drop-shadow(0 0 0.5px var(--background-color)) '.repeat(4),
141
153
  pointerEvents: 'none',
142
- color: '#1d1e38',
154
+ ...mergedIconStyles,
143
155
  }}
144
156
  />
145
157
  )}
146
158
  <TriggerFlag aria-hidden id={id} />
147
159
  </ToolbarItemContainer>
148
160
  {opened && (
149
- <Callout target={`#${id}`}>
150
- <OptionGroup role="listbox" aria-activedescendant={`${id}::${value}`} aria-describedby={id} aria-disabled={disabled} onMouseDown={e => e.stopPropagation()}>
161
+ <Callout target={`#${id}`} darkModePreference={darkModePreference}>
162
+ <OptionGroup dark={dark} role="listbox" aria-activedescendant={`${id}::${value}`} aria-describedby={id} aria-disabled={disabled} onMouseDown={e => e.stopPropagation()}>
151
163
  {options.map((option, idx, arr) => {
152
164
  const selected = option.key === value;
153
165
  const OptionIcon = option.icon;
@@ -156,6 +168,7 @@ const ToolbarSelectButton = memo<IToolbarProps<ToolbarSelectButtonItem>>(functio
156
168
  const next = arr[(idx + 1) % arr.length];
157
169
  return (
158
170
  <Option
171
+ dark={dark}
159
172
  key={option.key}
160
173
  id={optionId}
161
174
  role="option"
@@ -46,10 +46,15 @@ export interface ToolbarToggleButtonItem extends IToolbarItem {
46
46
  }
47
47
 
48
48
  const ToolbarToggleButton = memo<IToolbarProps<ToolbarToggleButtonItem>>(function ToolbarToggleButton(props) {
49
- const { item, styles } = props;
49
+ const { item, styles, darkModePreference } = props;
50
50
  const { icon: Icon, label, disabled, checked, onChange } = item;
51
51
  const handlers = useHandlers(() => onChange(!checked), disabled ?? false);
52
52
 
53
+ const mergedIconStyles = {
54
+ ...styles?.icon,
55
+ ...item.styles?.icon,
56
+ };
57
+
53
58
  return (
54
59
  <>
55
60
  <ToolbarItemContainer
@@ -57,9 +62,10 @@ const ToolbarToggleButton = memo<IToolbarProps<ToolbarToggleButtonItem>>(functio
57
62
  handlers={handlers}
58
63
  role="checkbox"
59
64
  aria-checked={checked}
65
+ darkModePreference={darkModePreference}
60
66
  >
61
67
  <ToggleContainer checked={checked}>
62
- <Icon style={styles?.icon} />
68
+ <Icon style={mergedIconStyles} />
63
69
  </ToggleContainer>
64
70
  </ToolbarItemContainer>
65
71
  </>
@@ -1,7 +1,9 @@
1
1
  import React, { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { createPortal } from "react-dom";
3
3
  import styled from "styled-components";
4
+ import type { IDarkMode } from "../interfaces";
4
5
  import { ShadowDomContext } from "..";
6
+ import { useCurrentMediaTheme } from "../utils/media";
5
7
 
6
8
  export interface TooltipProps {
7
9
  children: JSX.Element;
@@ -12,12 +14,13 @@ export interface TooltipProps {
12
14
  hideDelay?: number;
13
15
  /** @default 3_000 */
14
16
  autoHide?: number;
17
+ darkModePreference: IDarkMode;
15
18
  }
16
19
 
17
20
  const attrName = "data-tooltip-host-id";
18
21
  let flag = 0;
19
22
 
20
- const Bubble = styled.div`
23
+ const Bubble = styled.div<{ dark: boolean }>`
21
24
  border-radius: 1px;
22
25
  transform: translate(-50%, -100%);
23
26
  filter: drop-shadow(0 1.6px 1.2px rgba(0, 0, 0, 0.15)) drop-shadow(0 -1px 1px rgba(0, 0, 0, 0.12));
@@ -31,7 +34,7 @@ const Bubble = styled.div`
31
34
  width: 8px;
32
35
  height: 8px;
33
36
  transform: translate(-50%, 50%) rotate(45deg);
34
- background-color: #fff;
37
+ background-color: ${({ dark }) => dark ? '#000' : '#fff'};
35
38
  border-radius: 1px;
36
39
  }
37
40
  `;
@@ -42,6 +45,7 @@ const Tooltip = memo<TooltipProps>(function Tooltip({
42
45
  autoHide = 3_000,
43
46
  showDelay = 250,
44
47
  hideDelay = 250,
48
+ darkModePreference = 'media',
45
49
  }) {
46
50
  const hostId = useMemo(() => flag++, []);
47
51
  const [pos, setPos] = useState<[number, number]>([0, 0]);
@@ -118,6 +122,8 @@ const Tooltip = memo<TooltipProps>(function Tooltip({
118
122
  }
119
123
  }, [root, hostId]);
120
124
 
125
+ const darkMode = useCurrentMediaTheme(darkModePreference);
126
+
121
127
  return (
122
128
  <>
123
129
  {element}
@@ -125,7 +131,8 @@ const Tooltip = memo<TooltipProps>(function Tooltip({
125
131
  root &&
126
132
  createPortal(
127
133
  <Bubble
128
- className="fixed text-xs p-1 px-3 text-gray-500 bg-white z-50"
134
+ className={`${darkMode === 'dark' ? 'dark bg-zinc-900' : 'bg-white'} fixed text-xs p-1 px-3 text-gray-500 z-50`}
135
+ dark={darkMode === 'dark'}
129
136
  onMouseOver={() => setHover(true)}
130
137
  onMouseOut={() => setHover(false)}
131
138
  style={{ left: pos[0], top: pos[1] - 4 }}
@@ -0,0 +1,28 @@
1
+ import { IDropdownSelectOption } from "../../components/dropdownSelect";
2
+
3
+ export const charsetOptions: IDropdownSelectOption[] = [
4
+ {
5
+ label: 'UTF-8',
6
+ value: 'utf-8',
7
+ },
8
+ {
9
+ label: 'GB2312',
10
+ value: 'gb2312',
11
+ },
12
+ {
13
+ label: 'US-ASCII',
14
+ value: 'us-ascii',
15
+ },
16
+ {
17
+ label: 'Big5',
18
+ value: 'big5',
19
+ },
20
+ {
21
+ label: 'Big5-HKSCS',
22
+ value: 'Big5-HKSCS',
23
+ },
24
+ {
25
+ label: 'GB18030',
26
+ value: 'GB18030',
27
+ },
28
+ ]
@@ -1,4 +1,4 @@
1
- import React, { useRef, useCallback } from "react";
1
+ import React, { useRef, useCallback, useState } from "react";
2
2
  import { FileReader } from "@kanaries/web-data-loader";
3
3
  import { IRow } from "../../interfaces";
4
4
  import Table from "../table";
@@ -8,25 +8,51 @@ import { observer } from "mobx-react-lite";
8
8
  import { useTranslation } from "react-i18next";
9
9
  import DefaultButton from "../../components/button/default";
10
10
  import PrimaryButton from "../../components/button/primary";
11
+ import DropdownSelect from "../../components/dropdownSelect";
12
+ import { charsetOptions } from "./config";
11
13
 
12
14
  const Container = styled.div`
13
15
  overflow-x: auto;
16
+ min-height: 300px;
14
17
  `;
15
18
 
16
19
  interface ICSVData {}
17
20
  const CSVData: React.FC<ICSVData> = (props) => {
18
21
  const fileRef = useRef<HTMLInputElement>(null);
19
22
  const { commonStore } = useGlobalStore();
20
- const { tmpDSName, tmpDataSource } = commonStore;
23
+ const { tmpDSName, tmpDataSource, tmpDSRawFields } = commonStore;
24
+ const [encoding, setEncoding] = useState<string>("utf-8");
21
25
 
22
26
  const onSubmitData = useCallback(() => {
23
27
  commonStore.commitTempDS();
24
28
  }, []);
25
29
 
26
30
  const { t } = useTranslation("translation", { keyPrefix: "DataSource.dialog.file" });
31
+ const fileLoaded = tmpDataSource.length > 0 && tmpDSRawFields.length > 0;
27
32
 
28
33
  return (
29
34
  <Container>
35
+ {!fileLoaded && (
36
+ <div className="text-center">
37
+ <svg
38
+ className="mx-auto h-12 w-12 text-gray-400"
39
+ fill="none"
40
+ viewBox="0 0 24 24"
41
+ stroke="currentColor"
42
+ aria-hidden="true"
43
+ >
44
+ <path
45
+ vectorEffect="non-scaling-stroke"
46
+ strokeLinecap="round"
47
+ strokeLinejoin="round"
48
+ strokeWidth={2}
49
+ d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"
50
+ />
51
+ </svg>
52
+ <h3 className="mt-2 text-sm font-semibold text-gray-900">{t('choose_file')}</h3>
53
+ <p className="mt-1 text-sm text-gray-500">{t('get_start_desc')}</p>
54
+ </div>
55
+ )}
30
56
  <input
31
57
  style={{ display: "none" }}
32
58
  type="file"
@@ -39,42 +65,61 @@ const CSVData: React.FC<ICSVData> = (props) => {
39
65
  file,
40
66
  config: { type: "reservoirSampling", size: Infinity },
41
67
  onLoading: () => {},
68
+ encoding,
42
69
  }).then((data) => {
43
70
  commonStore.updateTempDS(data as IRow[]);
44
71
  });
45
72
  }
46
73
  }}
47
74
  />
48
- <div className="mt-1 mb-1">
49
- <DefaultButton
50
- onClick={() => {
51
- if (fileRef.current) {
52
- fileRef.current.click();
53
- }
54
- }}
55
- text={t("open")}
56
- />
57
- <PrimaryButton
58
- text={t("submit")}
59
- disabled={tmpDataSource.length === 0}
60
- onClick={() => {
61
- onSubmitData();
62
- }}
63
- />
64
- </div>
65
- <div className="my-2">
66
- <label className="block text-xs text-gray-800 mb-1 font-bold">{t("dataset_name")}</label>
67
- <input
68
- type="text"
69
- placeholder={t("dataset_name")}
70
- value={tmpDSName}
71
- onChange={(e) => {
72
- commonStore.updateTempName(e.target.value);
73
- }}
74
- className="text-xs p-2 rounded border border-gray-200 outline-none focus:outline-none focus:border-blue-500 placeholder:italic placeholder:text-slate-400"
75
- />
76
- </div>
77
- <Table />
75
+ {!fileLoaded && (
76
+ <div className="my-1 flex justify-center">
77
+ <DefaultButton
78
+ className="mr-2"
79
+ onClick={() => {
80
+ if (fileRef.current) {
81
+ fileRef.current.click();
82
+ }
83
+ }}
84
+ text={t("open")}
85
+ />
86
+ <div className="inline-block relative">
87
+ <DropdownSelect
88
+ buttonClassName="w-36"
89
+ options={charsetOptions}
90
+ selectedKey={encoding}
91
+ onSelect={(k) => {
92
+ setEncoding(k);
93
+ }}
94
+ />
95
+ </div>
96
+ </div>
97
+ )}
98
+ {fileLoaded && (
99
+ <div className="mb-2 mt-6">
100
+ <label className="block text-xs text-gray-800 dark:text-gray-200 mb-1 font-bold">
101
+ {t("dataset_name")}
102
+ </label>
103
+ <input
104
+ type="text"
105
+ placeholder={t("dataset_name")}
106
+ value={tmpDSName}
107
+ onChange={(e) => {
108
+ commonStore.updateTempName(e.target.value);
109
+ }}
110
+ className="text-xs mr-2 p-2 rounded border border-gray-200 dark:border-gray-700 outline-none focus:outline-none focus:border-blue-500 placeholder:italic placeholder:text-slate-400 dark:bg-stone-900"
111
+ />
112
+ <PrimaryButton
113
+ className="mr-2"
114
+ text={t("submit")}
115
+ disabled={tmpDataSource.length === 0}
116
+ onClick={() => {
117
+ onSubmitData();
118
+ }}
119
+ />
120
+ </div>
121
+ )}
122
+ {fileLoaded && <Table />}
78
123
  </Container>
79
124
  );
80
125
  };
@@ -1,15 +1,7 @@
1
1
  import React, { useRef, useCallback } from "react";
2
- import { FileReader } from "@kanaries/web-data-loader";
3
- import { IRow } from "../../interfaces";
4
- import Table from "../table";
5
- import styled from "styled-components";
6
2
  import { useGlobalStore } from "../../store";
7
3
  import { observer } from "mobx-react-lite";
8
- import { useTranslation } from "react-i18next";
9
4
 
10
- const Container = styled.div`
11
- overflow-x: auto;
12
- `;
13
5
 
14
6
  interface GWFileProps {
15
7
  fileRef: React.RefObject<HTMLInputElement>;
@@ -3,7 +3,7 @@ import { useState } from "react";
3
3
  import CSVData from "./csvData";
4
4
  import PublicData from "./publicData";
5
5
  import { useTranslation } from "react-i18next";
6
- import PureTabs from "../../components/tabs/editableTab";
6
+ import PureTabs from "../../components/tabs/defaultTab";
7
7
 
8
8
  const DataSelection: React.FC = (props) => {
9
9
  const [sourceType, setSourceType] = useState<"file" | "public">("file");
@@ -26,7 +26,6 @@ const DataSelection: React.FC = (props) => {
26
26
  setSourceType(sk as "public" | "file");
27
27
  }}
28
28
  />
29
- <hr className="mt-1 mb-1" />
30
29
  {sourceType === "file" && <CSVData />}
31
30
  {sourceType === "public" && <PublicData />}
32
31
  </div>
@@ -36,20 +36,19 @@ const PublicData: React.FC<IPublicDataProps> = props => {
36
36
  })
37
37
  })
38
38
  }}
39
- className="border rounded border-gray-300 p-2 m-2 cursor-pointer hover:bg-gray-50"
39
+ className="border rounded border-gray-300 dark:border-gray-600 p-2 m-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 dark:text-gray-200"
40
40
  >
41
41
  <div>{data.title}</div>
42
42
  {/* <p>{data.title}</p> */}
43
43
  </div>)
44
44
  }
45
45
  </div>
46
- <hr className="m-1" />
47
46
  <PrimaryButton
47
+ className='my-1'
48
48
  disabled={tmpDataSource.length === 0}
49
49
  onClick={() => { commonStore.commitTempDS() }}
50
50
  text={t('submit')}
51
51
  />
52
- <hr className="m-1" />
53
52
  <Table />
54
53
  </div>
55
54
  }