@genspectrum/dashboard-components 0.1.4 → 0.2.0
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/custom-elements.json +1021 -804
- package/dist/dashboard-components.js +647 -218
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +336 -126
- package/dist/style.css +214 -36
- package/package.json +4 -4
- package/src/preact/aggregatedData/aggregate.stories.tsx +2 -0
- package/src/preact/aggregatedData/aggregate.tsx +33 -28
- package/src/preact/components/error-boundary.stories.tsx +62 -0
- package/src/preact/components/error-boundary.tsx +31 -0
- package/src/preact/components/error-display.stories.tsx +24 -3
- package/src/preact/components/error-display.tsx +14 -1
- package/src/preact/components/headline.stories.tsx +19 -1
- package/src/preact/components/headline.tsx +9 -1
- package/src/preact/components/info.stories.tsx +24 -3
- package/src/preact/components/info.tsx +49 -5
- package/src/preact/components/loading-display.stories.tsx +6 -6
- package/src/preact/components/loading-display.tsx +1 -1
- package/src/preact/components/no-data-display.tsx +5 -1
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +17 -0
- package/src/preact/dateRangeSelector/date-range-selector.tsx +43 -15
- package/src/preact/locationFilter/location-filter.stories.tsx +23 -6
- package/src/preact/locationFilter/location-filter.tsx +29 -18
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -0
- package/src/preact/mutationComparison/mutation-comparison.tsx +31 -27
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +17 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +26 -8
- package/src/preact/mutations/mutations.stories.tsx +3 -0
- package/src/preact/mutations/mutations.tsx +32 -26
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +57 -31
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -0
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +89 -32
- package/src/preact/textInput/text-input.tsx +26 -3
- package/src/web-components/app.stories.ts +1 -2
- package/src/web-components/app.ts +4 -2
- package/src/web-components/index.ts +1 -1
- package/src/web-components/input/{date-range-selector-component.stories.ts → gs-date-range-selector.stories.ts} +35 -3
- package/src/web-components/input/gs-date-range-selector.tsx +110 -0
- package/src/web-components/input/{location-filter-component.stories.ts → gs-location-filter.stories.ts} +29 -4
- package/src/web-components/input/{location-filter-component.tsx → gs-location-filter.tsx} +12 -1
- package/src/web-components/input/{mutation-filter-component.stories.ts → gs-mutation-filter.stories.ts} +30 -4
- package/src/web-components/input/gs-mutation-filter.tsx +114 -0
- package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts} +42 -3
- package/src/web-components/input/gs-text-input.tsx +73 -0
- package/src/web-components/input/index.ts +4 -4
- package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +26 -0
- package/src/web-components/{display/aggregate-component.stories.ts → visualization/gs-aggregate.stories.ts} +8 -6
- package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx} +16 -2
- package/src/web-components/{display/mutation-comparison-component.stories.ts → visualization/gs-mutation-comparison.stories.ts} +11 -9
- package/src/web-components/{display/mutation-comparison-component.tsx → visualization/gs-mutation-comparison.tsx} +8 -1
- package/src/web-components/{display/mutations-component.stories.ts → visualization/gs-mutations.stories.ts} +30 -11
- package/src/web-components/visualization/gs-mutations.tsx +94 -0
- package/src/web-components/{display/prevalence-over-time-component.stories.ts → visualization/gs-prevalence-over-time.stories.ts} +24 -1
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +148 -0
- package/src/web-components/{display/relative-growth-advantage-component.stories.ts → visualization/gs-relative-growth-advantage.stories.ts} +21 -1
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +100 -0
- package/src/web-components/visualization/index.ts +5 -0
- package/src/web-components/display/index.ts +0 -5
- package/src/web-components/display/mutations-component.tsx +0 -40
- package/src/web-components/display/prevalence-over-time-component.tsx +0 -58
- package/src/web-components/display/relative-growth-advantage-component.tsx +0 -49
- package/src/web-components/input/date-range-selector-component.tsx +0 -46
- package/src/web-components/input/mutation-filter-component.tsx +0 -35
- package/src/web-components/input/text-input-component.tsx +0 -39
package/dist/style.css
CHANGED
|
@@ -1008,6 +1008,35 @@ html {
|
|
|
1008
1008
|
max-width: 1536px;
|
|
1009
1009
|
}
|
|
1010
1010
|
}
|
|
1011
|
+
.alert {
|
|
1012
|
+
display: grid;
|
|
1013
|
+
width: 100%;
|
|
1014
|
+
grid-auto-flow: row;
|
|
1015
|
+
align-content: flex-start;
|
|
1016
|
+
align-items: center;
|
|
1017
|
+
justify-items: center;
|
|
1018
|
+
gap: 1rem;
|
|
1019
|
+
text-align: center;
|
|
1020
|
+
border-radius: var(--rounded-box, 1rem);
|
|
1021
|
+
border-width: 1px;
|
|
1022
|
+
--tw-border-opacity: 1;
|
|
1023
|
+
border-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));
|
|
1024
|
+
padding: 1rem;
|
|
1025
|
+
--tw-text-opacity: 1;
|
|
1026
|
+
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
|
1027
|
+
--alert-bg: var(--fallback-b2,oklch(var(--b2)/1));
|
|
1028
|
+
--alert-bg-mix: var(--fallback-b1,oklch(var(--b1)/1));
|
|
1029
|
+
background-color: var(--alert-bg);
|
|
1030
|
+
}
|
|
1031
|
+
@media (min-width: 640px) {
|
|
1032
|
+
|
|
1033
|
+
.alert {
|
|
1034
|
+
grid-auto-flow: column;
|
|
1035
|
+
grid-template-columns: auto minmax(auto,1fr);
|
|
1036
|
+
justify-items: start;
|
|
1037
|
+
text-align: start;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1011
1040
|
.avatar.placeholder > div {
|
|
1012
1041
|
display: flex;
|
|
1013
1042
|
align-items: center;
|
|
@@ -1065,7 +1094,6 @@ html {
|
|
|
1065
1094
|
transition-duration: 200ms;
|
|
1066
1095
|
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
1067
1096
|
border-width: var(--border-btn, 1px);
|
|
1068
|
-
animation: button-pop var(--animation-btn, 0.25s) ease-out;
|
|
1069
1097
|
transition-property: color, background-color, border-color, opacity, box-shadow, transform;
|
|
1070
1098
|
--tw-text-opacity: 1;
|
|
1071
1099
|
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
|
@@ -1517,28 +1545,13 @@ html {
|
|
|
1517
1545
|
.select[multiple] {
|
|
1518
1546
|
height: auto;
|
|
1519
1547
|
}
|
|
1520
|
-
.
|
|
1548
|
+
.steps {
|
|
1521
1549
|
display: inline-grid;
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
grid-
|
|
1527
|
-
grid-row-start: 1;
|
|
1528
|
-
transform: translateY(10%) scale(0.9);
|
|
1529
|
-
z-index: 1;
|
|
1530
|
-
width: 100%;
|
|
1531
|
-
opacity: 0.6;
|
|
1532
|
-
}
|
|
1533
|
-
.stack > *:nth-child(2) {
|
|
1534
|
-
transform: translateY(5%) scale(0.95);
|
|
1535
|
-
z-index: 2;
|
|
1536
|
-
opacity: 0.8;
|
|
1537
|
-
}
|
|
1538
|
-
.stack > *:nth-child(1) {
|
|
1539
|
-
transform: translateY(0) scale(1);
|
|
1540
|
-
z-index: 3;
|
|
1541
|
-
opacity: 1;
|
|
1550
|
+
grid-auto-flow: column;
|
|
1551
|
+
overflow: hidden;
|
|
1552
|
+
overflow-x: auto;
|
|
1553
|
+
counter-reset: step;
|
|
1554
|
+
grid-auto-columns: 1fr;
|
|
1542
1555
|
}
|
|
1543
1556
|
.steps .step {
|
|
1544
1557
|
display: grid;
|
|
@@ -1554,8 +1567,7 @@ html {
|
|
|
1554
1567
|
display: grid;
|
|
1555
1568
|
align-items: flex-end;
|
|
1556
1569
|
}
|
|
1557
|
-
.tabs-lifted:has(.tab-content[class^="rounded-"]) .tab:first-child:not(.tab-active),
|
|
1558
|
-
.tabs-lifted:has(.tab-content[class*=" rounded-"]) .tab:first-child:not(.tab-active) {
|
|
1570
|
+
.tabs-lifted:has(.tab-content[class^="rounded-"]) .tab:first-child:not(:is(.tab-active, [aria-selected="true"])), .tabs-lifted:has(.tab-content[class*=" rounded-"]) .tab:first-child:not(:is(.tab-active, [aria-selected="true"])) {
|
|
1559
1571
|
border-bottom-color: transparent;
|
|
1560
1572
|
}
|
|
1561
1573
|
.tab {
|
|
@@ -1600,7 +1612,7 @@ html {
|
|
|
1600
1612
|
grid-column-start: span 9999;
|
|
1601
1613
|
}
|
|
1602
1614
|
input.tab:checked + .tab-content,
|
|
1603
|
-
.tab-active + .tab-content {
|
|
1615
|
+
:is(.tab-active, [aria-selected="true"]) + .tab-content {
|
|
1604
1616
|
display: block;
|
|
1605
1617
|
}
|
|
1606
1618
|
.table {
|
|
@@ -1632,6 +1644,13 @@ input.tab:checked + .tab-content,
|
|
|
1632
1644
|
--tw-bg-opacity: 1;
|
|
1633
1645
|
background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
|
|
1634
1646
|
}
|
|
1647
|
+
.alert-error {
|
|
1648
|
+
border-color: var(--fallback-er,oklch(var(--er)/0.2));
|
|
1649
|
+
--tw-text-opacity: 1;
|
|
1650
|
+
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
|
1651
|
+
--alert-bg: var(--fallback-er,oklch(var(--er)/1));
|
|
1652
|
+
--alert-bg-mix: var(--fallback-b1,oklch(var(--b1)/1));
|
|
1653
|
+
}
|
|
1635
1654
|
.btm-nav > *.disabled,
|
|
1636
1655
|
.btm-nav > *[disabled] {
|
|
1637
1656
|
pointer-events: none;
|
|
@@ -1645,6 +1664,12 @@ input.tab:checked + .tab-content,
|
|
|
1645
1664
|
font-size: 1rem;
|
|
1646
1665
|
line-height: 1.5rem;
|
|
1647
1666
|
}
|
|
1667
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1668
|
+
|
|
1669
|
+
.btn {
|
|
1670
|
+
animation: button-pop var(--animation-btn, 0.25s) ease-out;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1648
1673
|
.btn:active:hover,
|
|
1649
1674
|
.btn:active:focus {
|
|
1650
1675
|
animation: button-pop 0s ease-out;
|
|
@@ -2174,6 +2199,30 @@ input.tab:checked + .tab-content,
|
|
|
2174
2199
|
background-position: calc(0% + 12px) calc(1px + 50%),
|
|
2175
2200
|
calc(0% + 16px) calc(1px + 50%);
|
|
2176
2201
|
}
|
|
2202
|
+
.skeleton {
|
|
2203
|
+
border-radius: var(--rounded-box, 1rem);
|
|
2204
|
+
--tw-bg-opacity: 1;
|
|
2205
|
+
background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));
|
|
2206
|
+
will-change: background-position;
|
|
2207
|
+
animation: skeleton 1.8s ease-in-out infinite;
|
|
2208
|
+
background-image: linear-gradient(
|
|
2209
|
+
105deg,
|
|
2210
|
+
transparent 0%,
|
|
2211
|
+
transparent 40%,
|
|
2212
|
+
var(--fallback-b1,oklch(var(--b1)/1)) 50%,
|
|
2213
|
+
transparent 60%,
|
|
2214
|
+
transparent 100%
|
|
2215
|
+
);
|
|
2216
|
+
background-size: 200% auto;
|
|
2217
|
+
background-repeat: no-repeat;
|
|
2218
|
+
background-position-x: -50%;
|
|
2219
|
+
}
|
|
2220
|
+
@media (prefers-reduced-motion) {
|
|
2221
|
+
|
|
2222
|
+
.skeleton {
|
|
2223
|
+
animation-duration: 15s;
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2177
2226
|
@keyframes skeleton {
|
|
2178
2227
|
|
|
2179
2228
|
from {
|
|
@@ -2222,12 +2271,79 @@ input.tab:checked + .tab-content,
|
|
|
2222
2271
|
.steps .step[data-content]:after {
|
|
2223
2272
|
content: attr(data-content);
|
|
2224
2273
|
}
|
|
2274
|
+
.steps .step-neutral + .step-neutral:before,
|
|
2275
|
+
.steps .step-neutral:after {
|
|
2276
|
+
--tw-bg-opacity: 1;
|
|
2277
|
+
background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
|
|
2278
|
+
--tw-text-opacity: 1;
|
|
2279
|
+
color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
|
|
2280
|
+
}
|
|
2281
|
+
.steps .step-primary + .step-primary:before,
|
|
2282
|
+
.steps .step-primary:after {
|
|
2283
|
+
--tw-bg-opacity: 1;
|
|
2284
|
+
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
|
|
2285
|
+
--tw-text-opacity: 1;
|
|
2286
|
+
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
|
|
2287
|
+
}
|
|
2288
|
+
.steps .step-secondary + .step-secondary:before,
|
|
2289
|
+
.steps .step-secondary:after {
|
|
2290
|
+
--tw-bg-opacity: 1;
|
|
2291
|
+
background-color: var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)));
|
|
2292
|
+
--tw-text-opacity: 1;
|
|
2293
|
+
color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)));
|
|
2294
|
+
}
|
|
2295
|
+
.steps .step-accent + .step-accent:before,
|
|
2296
|
+
.steps .step-accent:after {
|
|
2297
|
+
--tw-bg-opacity: 1;
|
|
2298
|
+
background-color: var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)));
|
|
2299
|
+
--tw-text-opacity: 1;
|
|
2300
|
+
color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)));
|
|
2301
|
+
}
|
|
2302
|
+
.steps .step-info + .step-info:before {
|
|
2303
|
+
--tw-bg-opacity: 1;
|
|
2304
|
+
background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)));
|
|
2305
|
+
}
|
|
2306
|
+
.steps .step-info:after {
|
|
2307
|
+
--tw-bg-opacity: 1;
|
|
2308
|
+
background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)));
|
|
2309
|
+
--tw-text-opacity: 1;
|
|
2310
|
+
color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));
|
|
2311
|
+
}
|
|
2312
|
+
.steps .step-success + .step-success:before {
|
|
2313
|
+
--tw-bg-opacity: 1;
|
|
2314
|
+
background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));
|
|
2315
|
+
}
|
|
2316
|
+
.steps .step-success:after {
|
|
2317
|
+
--tw-bg-opacity: 1;
|
|
2318
|
+
background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));
|
|
2319
|
+
--tw-text-opacity: 1;
|
|
2320
|
+
color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));
|
|
2321
|
+
}
|
|
2322
|
+
.steps .step-warning + .step-warning:before {
|
|
2323
|
+
--tw-bg-opacity: 1;
|
|
2324
|
+
background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));
|
|
2325
|
+
}
|
|
2326
|
+
.steps .step-warning:after {
|
|
2327
|
+
--tw-bg-opacity: 1;
|
|
2328
|
+
background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));
|
|
2329
|
+
--tw-text-opacity: 1;
|
|
2330
|
+
color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));
|
|
2331
|
+
}
|
|
2332
|
+
.steps .step-error + .step-error:before {
|
|
2333
|
+
--tw-bg-opacity: 1;
|
|
2334
|
+
background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));
|
|
2335
|
+
}
|
|
2336
|
+
.steps .step-error:after {
|
|
2337
|
+
--tw-bg-opacity: 1;
|
|
2338
|
+
background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));
|
|
2339
|
+
--tw-text-opacity: 1;
|
|
2340
|
+
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
|
2341
|
+
}
|
|
2225
2342
|
.tabs-lifted > .tab:focus-visible {
|
|
2226
2343
|
border-end-end-radius: 0;
|
|
2227
2344
|
border-end-start-radius: 0;
|
|
2228
2345
|
}
|
|
2229
|
-
.tab.tab-active:not(.tab-disabled):not([disabled]),
|
|
2230
|
-
.tab:is(input:checked) {
|
|
2346
|
+
.tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tab:is(input:checked) {
|
|
2231
2347
|
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
|
2232
2348
|
--tw-border-opacity: 1;
|
|
2233
2349
|
--tw-text-opacity: 1;
|
|
@@ -2262,8 +2378,7 @@ input.tab:checked + .tab-content,
|
|
|
2262
2378
|
padding-inline-end: var(--tab-padding, 1rem);
|
|
2263
2379
|
padding-top: var(--tab-border, 1px);
|
|
2264
2380
|
}
|
|
2265
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]),
|
|
2266
|
-
.tabs-lifted > .tab:is(input:checked) {
|
|
2381
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tabs-lifted > .tab:is(input:checked) {
|
|
2267
2382
|
background-color: var(--tab-bg);
|
|
2268
2383
|
border-width: var(--tab-border, 1px) var(--tab-border, 1px) 0 var(--tab-border, 1px);
|
|
2269
2384
|
border-inline-start-color: var(--tab-border-color);
|
|
@@ -2274,7 +2389,7 @@ input.tab:checked + .tab-content,
|
|
|
2274
2389
|
padding-bottom: var(--tab-border, 1px);
|
|
2275
2390
|
padding-top: 0;
|
|
2276
2391
|
}
|
|
2277
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked):before {
|
|
2392
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked):before {
|
|
2278
2393
|
z-index: 1;
|
|
2279
2394
|
content: "";
|
|
2280
2395
|
display: block;
|
|
@@ -2303,26 +2418,26 @@ input.tab:checked + .tab-content,
|
|
|
2303
2418
|
);
|
|
2304
2419
|
background-image: var(--radius-start), var(--radius-end);
|
|
2305
2420
|
}
|
|
2306
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before, .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2421
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2307
2422
|
background-image: var(--radius-end);
|
|
2308
2423
|
background-position: top right;
|
|
2309
2424
|
}
|
|
2310
|
-
[dir="rtl"] .tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2425
|
+
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2311
2426
|
background-image: var(--radius-start);
|
|
2312
2427
|
background-position: top left;
|
|
2313
2428
|
}
|
|
2314
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before, .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2429
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2315
2430
|
background-image: var(--radius-start);
|
|
2316
2431
|
background-position: top left;
|
|
2317
2432
|
}
|
|
2318
|
-
[dir="rtl"] .tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2433
|
+
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2319
2434
|
background-image: var(--radius-end);
|
|
2320
2435
|
background-position: top right;
|
|
2321
2436
|
}
|
|
2322
2437
|
.tabs-lifted
|
|
2323
|
-
> .tab-active:not(.tab-disabled):not([disabled])
|
|
2438
|
+
> :is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled])
|
|
2324
2439
|
+ .tabs-lifted
|
|
2325
|
-
.tab-active:not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked) + .tabs-lifted .tab:is(input:checked):before {
|
|
2440
|
+
:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked) + .tabs-lifted .tab:is(input:checked):before {
|
|
2326
2441
|
background-image: var(--radius-end);
|
|
2327
2442
|
background-position: top right;
|
|
2328
2443
|
}
|
|
@@ -2643,9 +2758,21 @@ input.tab:checked + .tab-content,
|
|
|
2643
2758
|
.static {
|
|
2644
2759
|
position: static;
|
|
2645
2760
|
}
|
|
2761
|
+
.absolute {
|
|
2762
|
+
position: absolute;
|
|
2763
|
+
}
|
|
2646
2764
|
.relative {
|
|
2647
2765
|
position: relative;
|
|
2648
2766
|
}
|
|
2767
|
+
.right-6 {
|
|
2768
|
+
right: 1.5rem;
|
|
2769
|
+
}
|
|
2770
|
+
.top-8 {
|
|
2771
|
+
top: 2rem;
|
|
2772
|
+
}
|
|
2773
|
+
.z-50 {
|
|
2774
|
+
z-index: 50;
|
|
2775
|
+
}
|
|
2649
2776
|
.z-\[1\] {
|
|
2650
2777
|
z-index: 1;
|
|
2651
2778
|
}
|
|
@@ -2682,6 +2809,9 @@ input.tab:checked + .tab-content,
|
|
|
2682
2809
|
.mt-2 {
|
|
2683
2810
|
margin-top: 0.5rem;
|
|
2684
2811
|
}
|
|
2812
|
+
.mt-4 {
|
|
2813
|
+
margin-top: 1rem;
|
|
2814
|
+
}
|
|
2685
2815
|
.inline {
|
|
2686
2816
|
display: inline;
|
|
2687
2817
|
}
|
|
@@ -2718,6 +2848,10 @@ input.tab:checked + .tab-content,
|
|
|
2718
2848
|
.min-w-0 {
|
|
2719
2849
|
min-width: 0px;
|
|
2720
2850
|
}
|
|
2851
|
+
.min-w-max {
|
|
2852
|
+
min-width: -moz-max-content;
|
|
2853
|
+
min-width: max-content;
|
|
2854
|
+
}
|
|
2721
2855
|
.max-w-screen-lg {
|
|
2722
2856
|
max-width: 1024px;
|
|
2723
2857
|
}
|
|
@@ -2742,6 +2876,9 @@ input.tab:checked + .tab-content,
|
|
|
2742
2876
|
.items-center {
|
|
2743
2877
|
align-items: center;
|
|
2744
2878
|
}
|
|
2879
|
+
.justify-end {
|
|
2880
|
+
justify-content: flex-end;
|
|
2881
|
+
}
|
|
2745
2882
|
.justify-center {
|
|
2746
2883
|
justify-content: center;
|
|
2747
2884
|
}
|
|
@@ -2757,6 +2894,9 @@ input.tab:checked + .tab-content,
|
|
|
2757
2894
|
.overflow-auto {
|
|
2758
2895
|
overflow: auto;
|
|
2759
2896
|
}
|
|
2897
|
+
.overflow-scroll {
|
|
2898
|
+
overflow: scroll;
|
|
2899
|
+
}
|
|
2760
2900
|
.whitespace-nowrap {
|
|
2761
2901
|
white-space: nowrap;
|
|
2762
2902
|
}
|
|
@@ -2775,6 +2915,9 @@ input.tab:checked + .tab-content,
|
|
|
2775
2915
|
.rounded-lg {
|
|
2776
2916
|
border-radius: 0.5rem;
|
|
2777
2917
|
}
|
|
2918
|
+
.rounded-md {
|
|
2919
|
+
border-radius: 0.375rem;
|
|
2920
|
+
}
|
|
2778
2921
|
.rounded-none {
|
|
2779
2922
|
border-radius: 0px;
|
|
2780
2923
|
}
|
|
@@ -2797,6 +2940,10 @@ input.tab:checked + .tab-content,
|
|
|
2797
2940
|
.border-b-2 {
|
|
2798
2941
|
border-bottom-width: 2px;
|
|
2799
2942
|
}
|
|
2943
|
+
.border-black {
|
|
2944
|
+
--tw-border-opacity: 1;
|
|
2945
|
+
border-color: rgb(0 0 0 / var(--tw-border-opacity));
|
|
2946
|
+
}
|
|
2800
2947
|
.border-error {
|
|
2801
2948
|
--tw-border-opacity: 1;
|
|
2802
2949
|
border-color: var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));
|
|
@@ -2856,6 +3003,13 @@ input.tab:checked + .tab-content,
|
|
|
2856
3003
|
padding-top: 0.5rem;
|
|
2857
3004
|
padding-bottom: 0.5rem;
|
|
2858
3005
|
}
|
|
3006
|
+
.text-justify {
|
|
3007
|
+
text-align: justify;
|
|
3008
|
+
}
|
|
3009
|
+
.text-base {
|
|
3010
|
+
font-size: 1rem;
|
|
3011
|
+
line-height: 1.5rem;
|
|
3012
|
+
}
|
|
2859
3013
|
.text-lg {
|
|
2860
3014
|
font-size: 1.125rem;
|
|
2861
3015
|
line-height: 1.75rem;
|
|
@@ -2881,15 +3035,35 @@ input.tab:checked + .tab-content,
|
|
|
2881
3035
|
.leading-5 {
|
|
2882
3036
|
line-height: 1.25rem;
|
|
2883
3037
|
}
|
|
3038
|
+
.text-blue-600 {
|
|
3039
|
+
--tw-text-opacity: 1;
|
|
3040
|
+
color: rgb(37 99 235 / var(--tw-text-opacity));
|
|
3041
|
+
}
|
|
2884
3042
|
.text-gray-600 {
|
|
2885
3043
|
--tw-text-opacity: 1;
|
|
2886
3044
|
color: rgb(75 85 99 / var(--tw-text-opacity));
|
|
2887
3045
|
}
|
|
3046
|
+
.text-red-700 {
|
|
3047
|
+
--tw-text-opacity: 1;
|
|
3048
|
+
color: rgb(185 28 28 / var(--tw-text-opacity));
|
|
3049
|
+
}
|
|
3050
|
+
.underline {
|
|
3051
|
+
text-decoration-line: underline;
|
|
3052
|
+
}
|
|
2888
3053
|
.shadow {
|
|
2889
3054
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
2890
3055
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
2891
3056
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
2892
3057
|
}
|
|
3058
|
+
.shadow-lg {
|
|
3059
|
+
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
3060
|
+
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
3061
|
+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
3062
|
+
}
|
|
3063
|
+
.blur {
|
|
3064
|
+
--tw-blur: blur(8px);
|
|
3065
|
+
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
3066
|
+
}
|
|
2893
3067
|
.filter {
|
|
2894
3068
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
2895
3069
|
}
|
|
@@ -2905,6 +3079,10 @@ input.tab:checked + .tab-content,
|
|
|
2905
3079
|
--tw-bg-opacity: 1;
|
|
2906
3080
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
|
2907
3081
|
}
|
|
3082
|
+
.hover\:text-blue-800:hover {
|
|
3083
|
+
--tw-text-opacity: 1;
|
|
3084
|
+
color: rgb(30 64 175 / var(--tw-text-opacity));
|
|
3085
|
+
}
|
|
2908
3086
|
.hover\:text-gray-700:hover {
|
|
2909
3087
|
--tw-text-opacity: 1;
|
|
2910
3088
|
color: rgb(55 65 81 / var(--tw-text-opacity));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"lint:lit-analyzer": "lit-analyzer",
|
|
36
36
|
"generate-manifest": "npx custom-elements-manifest analyze --litelement --globs src/web-components/**",
|
|
37
37
|
"generate-manifest:watch": "npm run generate-manifest -- --watch",
|
|
38
|
-
"format": "prettier \"**/*.{
|
|
38
|
+
"format": "prettier \"**/*.{ts,tsx,json,md,mdx,mjs,cjs}\" --write",
|
|
39
39
|
"check-format": "prettier --check \"**/*.{ts,tsx,json,md,mdx,mjs,cjs}\"",
|
|
40
40
|
"check-types": "tsc --noEmit",
|
|
41
41
|
"check-dependencies": "depcheck",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"zod": "^3.23.0"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@custom-elements-manifest/analyzer": "^0.
|
|
73
|
+
"@custom-elements-manifest/analyzer": "^0.10.2",
|
|
74
74
|
"@playwright/test": "^1.43.1",
|
|
75
75
|
"@storybook/addon-actions": "^8.0.9",
|
|
76
76
|
"@storybook/addon-essentials": "^8.0.9",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@storybook/preact": "^8.0.9",
|
|
81
81
|
"@storybook/preact-vite": "^8.0.9",
|
|
82
82
|
"@storybook/test": "^8.0.0",
|
|
83
|
-
"@storybook/test-runner": "^0.
|
|
83
|
+
"@storybook/test-runner": "^0.18.0",
|
|
84
84
|
"@storybook/types": "^8.0.9",
|
|
85
85
|
"@storybook/web-components": "^8.0.9",
|
|
86
86
|
"@storybook/web-components-vite": "^8.0.9",
|
|
@@ -11,6 +11,7 @@ const meta: Meta<AggregateProps> = {
|
|
|
11
11
|
argTypes: {
|
|
12
12
|
fields: [{ control: 'object' }],
|
|
13
13
|
size: [{ control: 'object' }],
|
|
14
|
+
headline: { control: 'text' },
|
|
14
15
|
},
|
|
15
16
|
parameters: {
|
|
16
17
|
fetchMock: {
|
|
@@ -49,5 +50,6 @@ export const Default: StoryObj<AggregateProps> = {
|
|
|
49
50
|
country: 'USA',
|
|
50
51
|
},
|
|
51
52
|
size: { width: '100%', height: '70vh' },
|
|
53
|
+
headline: 'Aggregate',
|
|
52
54
|
},
|
|
53
55
|
};
|
|
@@ -6,6 +6,7 @@ import { type AggregateData, queryAggregateData } from '../../query/queryAggrega
|
|
|
6
6
|
import { type LapisFilter } from '../../types';
|
|
7
7
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
8
8
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
9
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
9
10
|
import { ErrorDisplay } from '../components/error-display';
|
|
10
11
|
import Headline from '../components/headline';
|
|
11
12
|
import Info from '../components/info';
|
|
@@ -17,53 +18,57 @@ import { useQuery } from '../useQuery';
|
|
|
17
18
|
|
|
18
19
|
export type View = 'table';
|
|
19
20
|
|
|
20
|
-
export
|
|
21
|
+
export type AggregateProps = {
|
|
22
|
+
size?: Size;
|
|
23
|
+
headline?: string;
|
|
24
|
+
} & AggregateInnerProps;
|
|
25
|
+
|
|
26
|
+
export interface AggregateInnerProps {
|
|
21
27
|
filter: LapisFilter;
|
|
22
28
|
fields: string[];
|
|
23
29
|
views: View[];
|
|
24
|
-
size?: Size;
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
32
|
+
export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
33
|
+
views,
|
|
34
|
+
size,
|
|
35
|
+
headline = 'Mutations',
|
|
36
|
+
filter,
|
|
37
|
+
fields,
|
|
38
|
+
}) => {
|
|
39
|
+
const defaultSize = { height: '600px', width: '100%' };
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
|
|
43
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
44
|
+
<Headline heading={headline}>
|
|
45
|
+
<AggregateInner fields={fields} filter={filter} views={views} />
|
|
46
|
+
</Headline>
|
|
47
|
+
</ResizeContainer>
|
|
48
|
+
</ErrorBoundary>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const AggregateInner: FunctionComponent<AggregateInnerProps> = ({ fields, views, filter }) => {
|
|
28
53
|
const lapis = useContext(LapisUrlContext);
|
|
29
54
|
|
|
30
55
|
const { data, error, isLoading } = useQuery(async () => {
|
|
31
56
|
return queryAggregateData(filter, fields, lapis);
|
|
32
57
|
}, [filter, fields, lapis]);
|
|
33
58
|
|
|
34
|
-
const headline = 'Aggregate';
|
|
35
|
-
|
|
36
59
|
if (isLoading) {
|
|
37
|
-
return
|
|
38
|
-
<Headline heading={headline}>
|
|
39
|
-
<LoadingDisplay />
|
|
40
|
-
</Headline>
|
|
41
|
-
);
|
|
60
|
+
return <LoadingDisplay />;
|
|
42
61
|
}
|
|
43
62
|
|
|
44
63
|
if (error !== null) {
|
|
45
|
-
return
|
|
46
|
-
<Headline heading={headline}>
|
|
47
|
-
<ErrorDisplay error={error} />
|
|
48
|
-
</Headline>
|
|
49
|
-
);
|
|
64
|
+
return <ErrorDisplay error={error} />;
|
|
50
65
|
}
|
|
51
66
|
|
|
52
67
|
if (data === null) {
|
|
53
|
-
return
|
|
54
|
-
<Headline heading={headline}>
|
|
55
|
-
<NoDataDisplay />
|
|
56
|
-
</Headline>
|
|
57
|
-
);
|
|
68
|
+
return <NoDataDisplay />;
|
|
58
69
|
}
|
|
59
70
|
|
|
60
|
-
return
|
|
61
|
-
<ResizeContainer size={size} defaultSize={{ height: '700px', width: '100%' }}>
|
|
62
|
-
<Headline heading={headline}>
|
|
63
|
-
<AggregatedDataTabs data={data} views={views} fields={fields} />
|
|
64
|
-
</Headline>
|
|
65
|
-
</ResizeContainer>
|
|
66
|
-
);
|
|
71
|
+
return <AggregatedDataTabs data={data} views={views} fields={fields} />;
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
type AggregatedDataTabsProps = {
|
|
@@ -96,7 +101,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({ data }) => {
|
|
|
96
101
|
return (
|
|
97
102
|
<div class='flex flex-row'>
|
|
98
103
|
<CsvDownloadButton className='mx-1 btn btn-xs' getData={() => data} filename='aggregate.csv' />
|
|
99
|
-
<Info
|
|
104
|
+
<Info>Info for aggregate</Info>
|
|
100
105
|
</div>
|
|
101
106
|
);
|
|
102
107
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, waitFor, within } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import { ErrorBoundary } from './error-boundary';
|
|
5
|
+
|
|
6
|
+
const meta: Meta = {
|
|
7
|
+
title: 'Component/Error boundary',
|
|
8
|
+
component: ErrorBoundary,
|
|
9
|
+
parameters: { fetchMock: {} },
|
|
10
|
+
argTypes: {
|
|
11
|
+
size: { control: 'object' },
|
|
12
|
+
defaultSize: { control: 'object' },
|
|
13
|
+
headline: { control: 'text' },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
export const ErrorBoundaryWithoutErrorStory: StoryObj = {
|
|
20
|
+
render: (args) => (
|
|
21
|
+
<ErrorBoundary size={args.size} defaultSize={args.defaultSize} headline={args.headline}>
|
|
22
|
+
<div>Some content</div>
|
|
23
|
+
</ErrorBoundary>
|
|
24
|
+
),
|
|
25
|
+
args: {
|
|
26
|
+
size: { height: '600px', width: '100%' },
|
|
27
|
+
defaultSize: { height: '600px', width: '100%' },
|
|
28
|
+
headline: 'Some headline',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
play: async ({ canvasElement }) => {
|
|
32
|
+
const canvas = within(canvasElement);
|
|
33
|
+
const content = canvas.getByText('Some content', { exact: false });
|
|
34
|
+
await waitFor(() => expect(content).toBeInTheDocument());
|
|
35
|
+
await waitFor(() => expect(canvas.queryByText('Some headline')).not.toBeInTheDocument());
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const ErrorBoundaryWithErrorStory: StoryObj = {
|
|
40
|
+
render: (args) => (
|
|
41
|
+
<ErrorBoundary size={args.size} defaultSize={args.defaultSize} headline={args.headline}>
|
|
42
|
+
<ContentThatThrowsError />
|
|
43
|
+
</ErrorBoundary>
|
|
44
|
+
),
|
|
45
|
+
args: {
|
|
46
|
+
size: { height: '600px', width: '100%' },
|
|
47
|
+
defaultSize: { height: '600px', width: '100%' },
|
|
48
|
+
headline: 'Some headline',
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
play: async ({ canvasElement }) => {
|
|
52
|
+
const canvas = within(canvasElement);
|
|
53
|
+
const content = canvas.queryByText('Some content.', { exact: false });
|
|
54
|
+
await waitFor(() => expect(content).not.toBeInTheDocument());
|
|
55
|
+
await waitFor(() => expect(canvas.getByText('Some headline')).toBeInTheDocument());
|
|
56
|
+
await waitFor(() => expect(canvas.getByText('Error')).toBeInTheDocument());
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const ContentThatThrowsError = () => {
|
|
61
|
+
throw new Error('Some error');
|
|
62
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { FunctionComponent } from 'preact';
|
|
2
|
+
import { useErrorBoundary } from 'preact/hooks';
|
|
3
|
+
|
|
4
|
+
import { ErrorDisplay } from './error-display';
|
|
5
|
+
import { ResizeContainer, type Size } from './resize-container';
|
|
6
|
+
import Headline from '../components/headline';
|
|
7
|
+
|
|
8
|
+
export const ErrorBoundary: FunctionComponent<{ size?: Size; defaultSize: Size; headline?: string }> = ({
|
|
9
|
+
size,
|
|
10
|
+
defaultSize,
|
|
11
|
+
headline,
|
|
12
|
+
children,
|
|
13
|
+
}) => {
|
|
14
|
+
const [internalError] = useErrorBoundary();
|
|
15
|
+
|
|
16
|
+
if (internalError) {
|
|
17
|
+
console.error(internalError);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (internalError) {
|
|
21
|
+
return (
|
|
22
|
+
<ResizeContainer defaultSize={defaultSize} size={size}>
|
|
23
|
+
<Headline heading={headline}>
|
|
24
|
+
<ErrorDisplay error={internalError} />
|
|
25
|
+
</Headline>
|
|
26
|
+
</ResizeContainer>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return <>{children}</>;
|
|
31
|
+
};
|