@genspectrum/dashboard-components 0.11.2 → 0.11.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/style.css CHANGED
@@ -2684,9 +2684,6 @@ input.tab:checked + .tab-content,
2684
2684
  border-end-end-radius: inherit;
2685
2685
  border-start-end-radius: inherit;
2686
2686
  }
2687
- .modal-middle {
2688
- place-items: center;
2689
- }
2690
2687
  .modal-bottom {
2691
2688
  place-items: end;
2692
2689
  }
@@ -3131,9 +3128,6 @@ input.tab:checked + .tab-content,
3131
3128
  .min-w-\[7\.5rem\] {
3132
3129
  min-width: 7.5rem;
3133
3130
  }
3134
- .max-w-3xl {
3135
- max-width: 48rem;
3136
- }
3137
3131
  .max-w-screen-lg {
3138
3132
  max-width: 1024px;
3139
3133
  }
@@ -3307,10 +3301,6 @@ input.tab:checked + .tab-content,
3307
3301
  padding-top: 0.5rem;
3308
3302
  padding-bottom: 0.5rem;
3309
3303
  }
3310
- .py-4 {
3311
- padding-top: 1rem;
3312
- padding-bottom: 1rem;
3313
- }
3314
3304
  .pl-2 {
3315
3305
  padding-left: 0.5rem;
3316
3306
  }
package/dist/util.d.ts CHANGED
@@ -787,7 +787,10 @@ declare global {
787
787
 
788
788
  declare global {
789
789
  interface HTMLElementTagNameMap {
790
- 'gs-mutation-comparison-component': MutationComparisonComponent;
790
+ 'gs-location-filter': LocationFilterComponent;
791
+ }
792
+ interface HTMLElementEventMap {
793
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
791
794
  }
792
795
  }
793
796
 
@@ -795,7 +798,7 @@ declare global {
795
798
  declare global {
796
799
  namespace JSX {
797
800
  interface IntrinsicElements {
798
- 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
801
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
799
802
  }
800
803
  }
801
804
  }
@@ -803,7 +806,11 @@ declare global {
803
806
 
804
807
  declare global {
805
808
  interface HTMLElementTagNameMap {
806
- 'gs-mutations-component': MutationsComponent;
809
+ 'gs-date-range-selector': DateRangeSelectorComponent;
810
+ }
811
+ interface HTMLElementEventMap {
812
+ 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
813
+ 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
807
814
  }
808
815
  }
809
816
 
@@ -811,7 +818,7 @@ declare global {
811
818
  declare global {
812
819
  namespace JSX {
813
820
  interface IntrinsicElements {
814
- 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
821
+ 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
815
822
  }
816
823
  }
817
824
  }
@@ -819,7 +826,10 @@ declare global {
819
826
 
820
827
  declare global {
821
828
  interface HTMLElementTagNameMap {
822
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
829
+ 'gs-text-input': TextInputComponent;
830
+ }
831
+ interface HTMLElementEventMap {
832
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
823
833
  }
824
834
  }
825
835
 
@@ -827,7 +837,7 @@ declare global {
827
837
  declare global {
828
838
  namespace JSX {
829
839
  interface IntrinsicElements {
830
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
840
+ 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
831
841
  }
832
842
  }
833
843
  }
@@ -835,7 +845,10 @@ declare global {
835
845
 
836
846
  declare global {
837
847
  interface HTMLElementTagNameMap {
838
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
848
+ 'gs-mutation-filter': MutationFilterComponent;
849
+ }
850
+ interface HTMLElementEventMap {
851
+ 'gs-mutation-filter-changed': CustomEvent<MutationsFilter>;
839
852
  }
840
853
  }
841
854
 
@@ -843,7 +856,7 @@ declare global {
843
856
  declare global {
844
857
  namespace JSX {
845
858
  interface IntrinsicElements {
846
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
859
+ 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
847
860
  }
848
861
  }
849
862
  }
@@ -851,7 +864,10 @@ declare global {
851
864
 
852
865
  declare global {
853
866
  interface HTMLElementTagNameMap {
854
- 'gs-aggregate': AggregateComponent;
867
+ 'gs-lineage-filter': LineageFilterComponent;
868
+ }
869
+ interface HTMLElementEventMap {
870
+ 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
855
871
  }
856
872
  }
857
873
 
@@ -859,7 +875,7 @@ declare global {
859
875
  declare global {
860
876
  namespace JSX {
861
877
  interface IntrinsicElements {
862
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
878
+ 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
863
879
  }
864
880
  }
865
881
  }
@@ -867,7 +883,7 @@ declare global {
867
883
 
868
884
  declare global {
869
885
  interface HTMLElementTagNameMap {
870
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
886
+ 'gs-mutation-comparison-component': MutationComparisonComponent;
871
887
  }
872
888
  }
873
889
 
@@ -875,7 +891,7 @@ declare global {
875
891
  declare global {
876
892
  namespace JSX {
877
893
  interface IntrinsicElements {
878
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
894
+ 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
879
895
  }
880
896
  }
881
897
  }
@@ -883,7 +899,7 @@ declare global {
883
899
 
884
900
  declare global {
885
901
  interface HTMLElementTagNameMap {
886
- 'gs-mutations-over-time': MutationsOverTimeComponent;
902
+ 'gs-mutations-component': MutationsComponent;
887
903
  }
888
904
  }
889
905
 
@@ -891,7 +907,7 @@ declare global {
891
907
  declare global {
892
908
  namespace JSX {
893
909
  interface IntrinsicElements {
894
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
910
+ 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
895
911
  }
896
912
  }
897
913
  }
@@ -899,7 +915,7 @@ declare global {
899
915
 
900
916
  declare global {
901
917
  interface HTMLElementTagNameMap {
902
- 'gs-sequences-by-location': SequencesByLocationComponent;
918
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
903
919
  }
904
920
  }
905
921
 
@@ -907,7 +923,7 @@ declare global {
907
923
  declare global {
908
924
  namespace JSX {
909
925
  interface IntrinsicElements {
910
- 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
926
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
911
927
  }
912
928
  }
913
929
  }
@@ -915,7 +931,7 @@ declare global {
915
931
 
916
932
  declare global {
917
933
  interface HTMLElementTagNameMap {
918
- 'gs-statistics': StatisticsComponent;
934
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
919
935
  }
920
936
  }
921
937
 
@@ -923,7 +939,7 @@ declare global {
923
939
  declare global {
924
940
  namespace JSX {
925
941
  interface IntrinsicElements {
926
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
942
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
927
943
  }
928
944
  }
929
945
  }
@@ -931,11 +947,7 @@ declare global {
931
947
 
932
948
  declare global {
933
949
  interface HTMLElementTagNameMap {
934
- 'gs-date-range-selector': DateRangeSelectorComponent;
935
- }
936
- interface HTMLElementEventMap {
937
- 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
938
- 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
950
+ 'gs-aggregate': AggregateComponent;
939
951
  }
940
952
  }
941
953
 
@@ -943,7 +955,7 @@ declare global {
943
955
  declare global {
944
956
  namespace JSX {
945
957
  interface IntrinsicElements {
946
- 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
958
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
947
959
  }
948
960
  }
949
961
  }
@@ -951,10 +963,7 @@ declare global {
951
963
 
952
964
  declare global {
953
965
  interface HTMLElementTagNameMap {
954
- 'gs-location-filter': LocationFilterComponent;
955
- }
956
- interface HTMLElementEventMap {
957
- 'gs-location-changed': CustomEvent<Record<string, string>>;
966
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
958
967
  }
959
968
  }
960
969
 
@@ -962,7 +971,7 @@ declare global {
962
971
  declare global {
963
972
  namespace JSX {
964
973
  interface IntrinsicElements {
965
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
974
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
966
975
  }
967
976
  }
968
977
  }
@@ -970,10 +979,7 @@ declare global {
970
979
 
971
980
  declare global {
972
981
  interface HTMLElementTagNameMap {
973
- 'gs-text-input': TextInputComponent;
974
- }
975
- interface HTMLElementEventMap {
976
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
982
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
977
983
  }
978
984
  }
979
985
 
@@ -981,7 +987,7 @@ declare global {
981
987
  declare global {
982
988
  namespace JSX {
983
989
  interface IntrinsicElements {
984
- 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
990
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
985
991
  }
986
992
  }
987
993
  }
@@ -989,10 +995,7 @@ declare global {
989
995
 
990
996
  declare global {
991
997
  interface HTMLElementTagNameMap {
992
- 'gs-mutation-filter': MutationFilterComponent;
993
- }
994
- interface HTMLElementEventMap {
995
- 'gs-mutation-filter-changed': CustomEvent<MutationsFilter>;
998
+ 'gs-sequences-by-location': SequencesByLocationComponent;
996
999
  }
997
1000
  }
998
1001
 
@@ -1000,7 +1003,7 @@ declare global {
1000
1003
  declare global {
1001
1004
  namespace JSX {
1002
1005
  interface IntrinsicElements {
1003
- 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1006
+ 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1004
1007
  }
1005
1008
  }
1006
1009
  }
@@ -1008,10 +1011,7 @@ declare global {
1008
1011
 
1009
1012
  declare global {
1010
1013
  interface HTMLElementTagNameMap {
1011
- 'gs-lineage-filter': LineageFilterComponent;
1012
- }
1013
- interface HTMLElementEventMap {
1014
- 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
1014
+ 'gs-statistics': StatisticsComponent;
1015
1015
  }
1016
1016
  }
1017
1017
 
@@ -1019,7 +1019,7 @@ declare global {
1019
1019
  declare global {
1020
1020
  namespace JSX {
1021
1021
  interface IntrinsicElements {
1022
- 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1022
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1023
1023
  }
1024
1024
  }
1025
1025
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -2,6 +2,8 @@ import { type FunctionComponent } from 'preact';
2
2
  import { useEffect, useRef } from 'preact/hooks';
3
3
  import { type ZodError } from 'zod';
4
4
 
5
+ import { InfoHeadline1, InfoParagraph } from './info';
6
+ import { Modal, useModalRef } from './modal';
5
7
  import { LapisError, UnknownLapisError } from '../../lapisApi/lapisApi';
6
8
 
7
9
  export const GS_ERROR_EVENT_TYPE = 'gs-error';
@@ -46,7 +48,7 @@ export const ErrorDisplay: FunctionComponent<ErrorDisplayProps> = ({ error, rese
46
48
  console.error(error);
47
49
 
48
50
  const containerRef = useRef<HTMLInputElement>(null);
49
- const ref = useRef<HTMLDialogElement>(null);
51
+ const modalRef = useModalRef();
50
52
 
51
53
  useEffect(() => {
52
54
  containerRef.current?.dispatchEvent(new ErrorEvent(error));
@@ -66,23 +68,16 @@ export const ErrorDisplay: FunctionComponent<ErrorDisplayProps> = ({ error, rese
66
68
  {details !== undefined && (
67
69
  <>
68
70
  {' '}
69
- <button className='underline hover:text-gray-400' onClick={() => ref.current?.showModal()}>
71
+ <button
72
+ className='underline hover:text-gray-400'
73
+ onClick={() => modalRef.current?.showModal()}
74
+ >
70
75
  Show details.
71
76
  </button>
72
- <dialog ref={ref} class='modal'>
73
- <div class='modal-box'>
74
- <form method='dialog'>
75
- <button className='btn btn-sm btn-circle btn-ghost absolute right-2 top-2'>
76
-
77
- </button>
78
- </form>
79
- <h1 class='text-lg'>{details.headline}</h1>
80
- <div class='py-4'>{details.message}</div>
81
- </div>
82
- <form method='dialog' class='modal-backdrop'>
83
- <button>close</button>
84
- </form>
85
- </dialog>
77
+ <Modal modalRef={modalRef}>
78
+ <InfoHeadline1>{details.headline}</InfoHeadline1>
79
+ <InfoParagraph>{details.message}</InfoParagraph>
80
+ </Modal>
86
81
  </>
87
82
  )}
88
83
  </div>
@@ -1,11 +1,12 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { useRef } from 'preact/hooks';
2
+
3
+ import { Modal, useModalRef } from './modal';
3
4
 
4
5
  const Info: FunctionComponent = ({ children }) => {
5
- const dialogRef = useRef<HTMLDialogElement>(null);
6
+ const modalRef = useModalRef();
6
7
 
7
8
  const toggleHelp = () => {
8
- dialogRef.current?.showModal();
9
+ modalRef.current?.showModal();
9
10
  };
10
11
 
11
12
  return (
@@ -13,22 +14,7 @@ const Info: FunctionComponent = ({ children }) => {
13
14
  <button type='button' className='btn btn-xs' onClick={toggleHelp}>
14
15
  ?
15
16
  </button>
16
- <dialog ref={dialogRef} className={'modal modal-bottom sm:modal-middle'}>
17
- <div className='modal-box sm:max-w-5xl'>
18
- <form method='dialog'>
19
- <button className='btn btn-sm btn-circle btn-ghost absolute right-2 top-2'>✕</button>
20
- </form>
21
- <div className={'flex flex-col'}>{children}</div>
22
- <div className='modal-action'>
23
- <form method='dialog'>
24
- <button className={'float-right underline text-sm hover:text-blue-700 mr-2'}>Close</button>
25
- </form>
26
- </div>
27
- </div>
28
- <form method='dialog' className='modal-backdrop'>
29
- <button>Helper to close when clicked outside</button>
30
- </form>
31
- </dialog>
17
+ <Modal modalRef={modalRef}>{children}</Modal>
32
18
  </div>
33
19
  );
34
20
  };
@@ -0,0 +1,44 @@
1
+ import { type Meta, type StoryObj } from '@storybook/preact';
2
+ import { expect, waitFor, within } from '@storybook/test';
3
+ import { type FunctionComponent } from 'preact';
4
+
5
+ import { Modal, type ModalProps, useModalRef } from './modal';
6
+
7
+ const meta: Meta<ModalProps> = {
8
+ title: 'Component/Modal',
9
+ component: Modal,
10
+ parameters: { fetchMock: {} },
11
+ };
12
+
13
+ export default meta;
14
+
15
+ const WrapperWithButtonThatOpensTheModal: FunctionComponent = () => {
16
+ const modalRef = useModalRef();
17
+
18
+ return (
19
+ <div>
20
+ <button className='btn' onClick={() => modalRef.current?.showModal()}>
21
+ Open modal
22
+ </button>
23
+ <Modal modalRef={modalRef}>
24
+ <h1>Modal content</h1>
25
+ </Modal>
26
+ </div>
27
+ );
28
+ };
29
+
30
+ export const ModalStory: StoryObj<ModalProps> = {
31
+ render: () => {
32
+ return <WrapperWithButtonThatOpensTheModal />;
33
+ },
34
+ play: async ({ canvasElement, step }) => {
35
+ const canvas = within(canvasElement);
36
+
37
+ await step('Open the modal', async () => {
38
+ const button = canvas.getByText('Open modal');
39
+ button.click();
40
+
41
+ await waitFor(() => expect(canvas.getByText('Modal content')).toBeVisible());
42
+ });
43
+ },
44
+ };
@@ -0,0 +1,31 @@
1
+ import { type FunctionComponent, type Ref } from 'preact';
2
+ import { useRef } from 'preact/hooks';
3
+
4
+ export type ModalProps = {
5
+ modalRef: Ref<HTMLDialogElement>;
6
+ };
7
+
8
+ export function useModalRef() {
9
+ return useRef<HTMLDialogElement>(null);
10
+ }
11
+
12
+ export const Modal: FunctionComponent<ModalProps> = ({ children, modalRef }) => {
13
+ return (
14
+ <dialog ref={modalRef} className={'modal modal-bottom sm:modal-middle'}>
15
+ <div className='modal-box sm:max-w-5xl'>
16
+ <form method='dialog'>
17
+ <button className='btn btn-sm btn-circle btn-ghost absolute right-2 top-2'>✕</button>
18
+ </form>
19
+ <div className={'flex flex-col'}>{children}</div>
20
+ <div className='modal-action'>
21
+ <form method='dialog'>
22
+ <button className={'float-right underline text-sm hover:text-blue-700 mr-2'}>Close</button>
23
+ </form>
24
+ </div>
25
+ </div>
26
+ <form method='dialog' className='modal-backdrop'>
27
+ <button>Helper to close when clicked outside</button>
28
+ </form>
29
+ </dialog>
30
+ );
31
+ };
@@ -7,6 +7,7 @@ import { type GeoJsonFeatureProperties, type MapSource, useGeoJsonMap } from './
7
7
  import { type AggregateData } from '../../query/queryAggregateData';
8
8
  import { InfoHeadline1, InfoParagraph } from '../components/info';
9
9
  import { LoadingDisplay } from '../components/loading-display';
10
+ import { Modal, useModalRef } from '../components/modal';
10
11
  import { formatProportion } from '../shared/table/formatProportion';
11
12
 
12
13
  type FeatureData = { proportion: number; count: number };
@@ -90,7 +91,7 @@ export const SequencesByLocationMapInner: FunctionComponent<SequencesByLocationM
90
91
  style: (feature: Feature<GeometryObject, EnhancedGeoJsonFeatureProperties> | undefined) => ({
91
92
  fillColor: getColor(feature?.properties.data?.proportion),
92
93
  fillOpacity: 1,
93
- color: 'grey',
94
+ color: '#666666',
94
95
  weight: 1,
95
96
  }),
96
97
  })
@@ -135,48 +136,38 @@ const DataMatchInformation: FunctionComponent<DataMatchInformationProps> = ({
135
136
  nullCount,
136
137
  hasTableView,
137
138
  }) => {
138
- const dialogRef = useRef<HTMLDialogElement>(null);
139
+ const modalRef = useModalRef();
139
140
 
140
141
  const proportion = formatProportion(countOfMatchedLocationData / totalCount);
141
142
 
142
143
  return (
143
144
  <>
144
145
  <button
145
- onClick={() => dialogRef.current?.showModal()}
146
+ onClick={() => modalRef.current?.showModal()}
146
147
  className='text-sm absolute bottom-0 px-1 z-[1001] bg-white rounded border cursor-pointer tooltip'
147
148
  data-tip='Click for detailed information'
148
149
  >
149
150
  This map shows {proportion} of the data.
150
151
  </button>
151
- <dialog ref={dialogRef} className={'modal modal-middle'}>
152
- <div className='modal-box max-w-3xl'>
153
- <InfoHeadline1>Sequences By Location - Map View</InfoHeadline1>
154
- <InfoParagraph>
155
- The current filter has matched {totalCount.toLocaleString('en-us')} sequences. From these
156
- sequences, we were able to match {countOfMatchedLocationData.toLocaleString('en-us')} (
157
- {proportion}) on locations on the map.
158
- </InfoParagraph>
159
- <InfoParagraph>
160
- {unmatchedLocations.length > 0 && (
161
- <>
162
- The following locations from the data could not be matched on the map:{' '}
163
- {unmatchedLocations.map((it) => `"${it}"`).join(', ')}.{' '}
164
- </>
165
- )}
166
- {nullCount > 0 &&
167
- `${nullCount.toLocaleString('en-us')} matching sequences have no location information. `}
168
- {hasTableView && 'You can check the table view for more detailed information.'}
169
- </InfoParagraph>
170
- <div className='modal-action'>
171
- <form method='dialog'>
172
- <button className={'float-right underline text-sm hover:text-blue-700 mr-2'}>Close</button>
173
- </form>
174
- </div>
175
- </div>
176
- <form method='dialog' className='modal-backdrop'>
177
- <button>Helper to close when clicked outside</button>
178
- </form>
179
- </dialog>
152
+ <Modal modalRef={modalRef}>
153
+ <InfoHeadline1>Sequences By Location - Map View</InfoHeadline1>
154
+ <InfoParagraph>
155
+ The current filter has matched {totalCount.toLocaleString('en-us')} sequences. From these sequences,
156
+ we were able to match {countOfMatchedLocationData.toLocaleString('en-us')} ({proportion}) on
157
+ locations on the map.
158
+ </InfoParagraph>
159
+ <InfoParagraph>
160
+ {unmatchedLocations.length > 0 && (
161
+ <>
162
+ The following locations from the data could not be matched on the map:{' '}
163
+ {unmatchedLocations.map((it) => `"${it}"`).join(', ')}.{' '}
164
+ </>
165
+ )}
166
+ {nullCount > 0 &&
167
+ `${nullCount.toLocaleString('en-us')} matching sequences have no location information. `}
168
+ {hasTableView && 'You can check the table view for more detailed information.'}
169
+ </InfoParagraph>
170
+ </Modal>
180
171
  </>
181
172
  );
182
173
  };
@@ -232,7 +223,7 @@ function matchLocationDataAndGeoJsonFeatures(
232
223
 
233
224
  function getColor(value: number | undefined): string {
234
225
  if (value === undefined) {
235
- return '#888888';
226
+ return '#DDDDDD';
236
227
  }
237
228
 
238
229
  const thresholds = [