diff --git a/client/components.json b/client/components.json new file mode 100644 index 0000000000..032a4c4799 --- /dev/null +++ b/client/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/styles/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/client/package.json b/client/package.json index 216213c40e..d2bdf4dd72 100644 --- a/client/package.json +++ b/client/package.json @@ -34,6 +34,7 @@ "@json2csv/plainjs": "^6.1.3", "@loaders.gl/core": "3.3.1", "@luma.gl/constants": "8.5.18", + "@radix-ui/react-collapsible": "1.0.3", "@reduxjs/toolkit": "1.8.2", "@tailwindcss/forms": "0.4.0", "@tailwindcss/typography": "0.5.0", @@ -43,7 +44,9 @@ "autoprefixer": "10.2.5", "axios": "1.3.4", "chroma-js": "2.1.2", + "class-variance-authority": "0.7.0", "classnames": "2.3.1", + "clsx": "^2.1.0", "d3-array": "3.0.2", "d3-format": "3.0.1", "d3-scale": "4.0.2", @@ -70,7 +73,9 @@ "recharts": "2.9.0", "rooks": "7.14.1", "sharp": "0.32.6", + "tailwind-merge": "2.2.1", "tailwindcss": "3.3.1", + "tailwindcss-animate": "1.0.7", "uuid": "8.3.2", "yup": "0.32.11" }, diff --git a/client/src/components/ui/collapsible.tsx b/client/src/components/ui/collapsible.tsx new file mode 100644 index 0000000000..9605c4e41a --- /dev/null +++ b/client/src/components/ui/collapsible.tsx @@ -0,0 +1,9 @@ +import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; + +const Collapsible = CollapsiblePrimitive.Root; + +const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; + +const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; + +export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx new file mode 100644 index 0000000000..d1ba374297 --- /dev/null +++ b/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx @@ -0,0 +1,5 @@ +const DeforestationFreeSuppliersBreakdown = () => { + return
DeforestationFreeSuppliersBreakdown
; +}; + +export default DeforestationFreeSuppliersBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx new file mode 100644 index 0000000000..4a5546533f --- /dev/null +++ b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx @@ -0,0 +1,5 @@ +const SuppliersWithDeforestationAlertsBreakdown = () => { + return
SuppliersWithDeforestationAlertsBreakdown
; +}; + +export default SuppliersWithDeforestationAlertsBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx new file mode 100644 index 0000000000..dbd62935f8 --- /dev/null +++ b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx @@ -0,0 +1,5 @@ +const SuppliersWithNoLocationDataBreakdown = () => { + return
SuppliersWithNoLocationData
; +}; + +export default SuppliersWithNoLocationDataBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/index.tsx b/client/src/containers/analysis-eudr/category-list/index.tsx new file mode 100644 index 0000000000..d96078e0df --- /dev/null +++ b/client/src/containers/analysis-eudr/category-list/index.tsx @@ -0,0 +1,101 @@ +import { useState } from 'react'; + +import DeforestationFreeSuppliersBreakdown from './breakdown/deforestation-free-suppliers'; +import SuppliersWithDeforestationAlertsBreakdown from './breakdown/suppliers-with-deforestation-alerts'; +import SuppliersWithNoLocationDataBreakdown from './breakdown/suppliers-with-no-location-data'; + +import { Button } from '@/components/button'; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; +import { formatPercentage } from '@/utils/number-format'; + +const CATEGORIES = [ + { + name: 'Deforestation-free suppliers', + slug: 'deforestation-free-suppliers', + color: 'bg-[#4AB7F3]', + // todo move this value field to the component + value: 0.3, + }, + { + name: 'Suppliers with deforestation alerts', + slug: 'suppliers-with-deforestation-alerts', + color: 'bg-[#FFC038]', + // todo move this value field to the component + value: 0.6, + }, + { + name: 'Suppliers with no location data', + slug: 'suppliers-with-no-location-data', + color: 'bg-[#8460FF]', + // todo move this value field to the component + value: 0.1, + }, +] as const; + +type CategoryState = Record<(typeof CATEGORIES)[number]['slug'], boolean>; + +export const CategoryList = (): JSX.Element => { + const [categories, toggleCategory] = useState( + CATEGORIES.reduce( + (acc, category) => ({ + ...acc, + [category.slug]: false, + }), + {} as CategoryState, + ), + ); + const categoriesWithValues = CATEGORIES.map((category) => ({ + ...category, + // todo: calculate value field here + })); + + return ( + <> + {categoriesWithValues.map((category) => ( + { + toggleCategory((prev) => ({ + ...prev, + [category.slug]: !prev[category.slug], + })); + }} + > +
+
{category.name}
+
+
+ {formatPercentage(category.value)} of suppliers +
+
+
+
+
+ + + +
+ + {category.slug === 'deforestation-free-suppliers' && ( + + )} + {category.slug === 'suppliers-with-deforestation-alerts' && ( + + )} + {category.slug === 'suppliers-with-no-location-data' && ( + + )} + + + ))} + + ); +}; + +export default CategoryList; diff --git a/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx b/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx index b5cfc0a7bb..756c5c828e 100644 --- a/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx +++ b/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx @@ -10,7 +10,7 @@ import { Label, } from 'recharts'; -import { Button } from '@/components/button'; +import CategoryList from '@/containers/analysis-eudr/category-list'; const data = [ { @@ -121,7 +121,7 @@ const SuppliersStackedBar = () => { type="category" width={200} /> - + @@ -129,54 +129,73 @@ const SuppliersStackedBar = () => {
-
-
Deforestation-free suppliers
-
-
- 31% of suppliers + + {/* + +
+
Deforestation-free suppliers
+
+
+ 31% of suppliers +
+
+
+
+
+ +
-
-
+ + +
test
+
+ + + +
+
Suppliers with deforestation alerts
+
+
+ 36% of suppliers +
+
+
+
+
+
-
-
- -
-
-
-
Suppliers with deforestation alerts
-
-
- 36% of suppliers + + +
test
+
+ + + +
+
Suppliers with no location data
+
+
+ 33% of suppliers +
+
+
+
+
+
+ +
-
-
-
-
-
- -
-
-
-
Suppliers with no location data
-
-
- 33% of suppliers -
-
-
-
-
-
- -
-
+ + +
test
+
+ */}
); diff --git a/client/src/lib/utils.ts b/client/src/lib/utils.ts new file mode 100644 index 0000000000..9ad0df4269 --- /dev/null +++ b/client/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/client/src/styles/globals.css b/client/src/styles/globals.css index 1ce4c66ed8..39e3f37c1f 100644 --- a/client/src/styles/globals.css +++ b/client/src/styles/globals.css @@ -2,15 +2,76 @@ @tailwind components; @tailwind utilities; -@-webkit-keyframes autofill { - 0%, - 100% { - color: #666; - @apply bg-transparent; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; } -} -@layer base { + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } + + * { + @apply border-border; + } + /* body { + @apply bg-background text-foreground; + } */ + input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-search-cancel-button, input[type='search']::-webkit-search-results-button, @@ -56,9 +117,15 @@ } } -@layer utilities { +@-webkit-keyframes autofill { + 0%, + 100% { + color: #666; + @apply bg-transparent; + } } + .rc-tree .rc-tree-checkbox { @apply hidden; } diff --git a/client/src/utils/number-format.ts b/client/src/utils/number-format.ts index 3e35866e80..b14809c04c 100644 --- a/client/src/utils/number-format.ts +++ b/client/src/utils/number-format.ts @@ -19,3 +19,7 @@ export function formatNumber(number: number): string { export const PRECISE_NUMBER_FORMAT = format(',.3~r'); export const BIG_NUMBER_FORMAT = format('s'); + +export const formatPercentage = (value: number, options: Intl.NumberFormatOptions = {}) => { + return Intl.NumberFormat(undefined, { style: 'percent', ...options }).format(value); +}; diff --git a/client/tailwind.config.ts b/client/tailwind.config.ts new file mode 100644 index 0000000000..de906dfb55 --- /dev/null +++ b/client/tailwind.config.ts @@ -0,0 +1,150 @@ +import type { Config } from 'tailwindcss'; + +const forms = require('@tailwindcss/forms'); +const typography = require('@tailwindcss/typography'); +const colors = require('tailwindcss/colors'); + +const config = { + darkMode: ['class'], + content: ['./src/**/*.{ts,tsx}'], + prefix: '', + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + extend: { + fontFamily: { + sans: ['Public Sans', 'sans-serif'], + }, + fontSize: { + '2xs': '0.625rem', // 10px + xs: ['0.75rem', '1rem'], // 12px + sm: ['0.875rem', '1.25rem'], // 14px + base: ['1rem', '1.5rem'], // 16px + lg: ['1.125rem', '1.75rem'], // 18px + '2xl': ['1.5rem', '2rem'], // 20px + '3xl': ['1.875rem', '2.25rem'], // 24px + '4xl': ['2.25rem', '2.5rem'], // 28px + }, + height: { + 'screen-minus-header': "calc(100vh - theme('spacing.16'))", + }, + spacing: { + 125: '30.875rem', + 250: '48.75rem', + }, + backgroundImage: { + auth: 'linear-gradient(240.36deg, #2E34B0 0%, #0C1063 68.13%)', + }, + boxShadow: { + menu: '0 4px 4px 0px rgba(0, 0, 0, 0.25)', + 'button-hovered': + '0px 0px 0px 6px rgba(0, 0, 0, 0.26), 0px 4px 4px 0px rgba(0, 0, 0, 0.25)', + 'button-focused': '0px 0px 0px 4px rgba(63, 89, 224, 0.20), 0px 0px 0px 1px #FFF', + }, + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + gray: { + 900: '#15181F', + 600: '#40424B', + 500: '#60626A', + 400: '#8F9195', + 300: '#AEB1B5', + 200: '#D1D5DB', + 100: '#F3F4F6', + 50: '#F9FAFB', + }, + navy: { + 50: '#F0F2FD', // light navy + 200: '#C7CDEA', // light mid navy + 400: '#3F59E0', // navy + 600: '#2E34B0', // mid navy + 900: '#152269', // dark navy + }, + orange: { + 500: '#FFA000', // orange + 300: '#F0B957', // light mid orange + 100: '#F9DFB1', // light orange + 50: '#FFF1D9', // lightest orange + }, + blue: { + 400: '#4AB7F3', // blue + 200: '#C7F0FF', // soft blue + }, + green: { + 800: '#006D2C', + 400: '#078A3C', + 200: '#CDE8D8', + 50: '#E6F9EE', + }, + red: { + 800: '#BA1809', // dark red + 400: '#E93323', // red + 50: '#FEF2F2', // light red + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, + }, + plugins: [ + require('tailwindcss-animate'), + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + ], +} satisfies Config; + +export default config; diff --git a/client/tailwind.config.js b/client/tailwind.config_old.js similarity index 100% rename from client/tailwind.config.js rename to client/tailwind.config_old.js diff --git a/client/yarn.lock b/client/yarn.lock index 4650448ed6..b8c55dc06a 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -209,6 +209,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.23.7": + version: 7.24.0 + resolution: "@babel/runtime@npm:7.24.0" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 7a6a5d40fbdd68491ec183ba2e631c07415119960083b4fd76564cce3751e9acd2f12ab89575e38496fa389fa06d458732776e69ee1858e366cc3fbdb049f847 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.20.0": version: 7.20.1 resolution: "@babel/runtime@npm:7.20.1" @@ -1565,6 +1574,191 @@ __metadata: languageName: node linkType: hard +"@radix-ui/primitive@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/primitive@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + checksum: 2b93e161d3fdabe9a64919def7fa3ceaecf2848341e9211520c401181c9eaebb8451c630b066fad2256e5c639c95edc41de0ba59c40eff37e799918d019822d1 + languageName: node + linkType: hard + +"@radix-ui/react-collapsible@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-collapsible@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-presence": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 26976e4a72a3e0f4b2c62af2898b3e205c3652af46a3b41cda9a43567fe8381d9ef6afb0b29e3214c450b847f4f2099a533cffc5045844ecab290e9fa6114ca9 + languageName: node + linkType: hard + +"@radix-ui/react-compose-refs@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-compose-refs@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 2b9a613b6db5bff8865588b6bf4065f73021b3d16c0a90b2d4c23deceeb63612f1f15de188227ebdc5f88222cab031be617a9dd025874c0487b303be3e5cc2a8 + languageName: node + linkType: hard + +"@radix-ui/react-context@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-context@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 60e9b81d364f40c91a6213ec953f7c64fcd9d75721205a494a5815b3e5ae0719193429b62ee6c7002cd6aaf70f8c0e2f08bdbaba9ffcc233044d32b56d2127d1 + languageName: node + linkType: hard + +"@radix-ui/react-id@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-id@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-layout-effect": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 446a453d799cc790dd2a1583ff8328da88271bff64530b5a17c102fa7fb35eece3cf8985359d416f65e330cd81aa7b8fe984ea125fc4f4eaf4b3801d698e49fe + languageName: node + linkType: hard + +"@radix-ui/react-presence@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-presence@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: ed2ff9faf9e4257a4065034d3771459e5a91c2d840b2fcec94661761704dbcb65bcdd927d28177a2a129b3dab5664eb90a9b88309afe0257a9f8ba99338c0d95 + languageName: node + linkType: hard + +"@radix-ui/react-primitive@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-primitive@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-slot": 1.0.2 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 9402bc22923c8e5c479051974a721c301535c36521c0237b83e5fa213d013174e77f3ad7905e6d60ef07e14f88ec7f4ea69891dc7a2b39047f8d3640e8f8d713 + languageName: node + linkType: hard + +"@radix-ui/react-slot@npm:1.0.2": + version: 1.0.2 + resolution: "@radix-ui/react-slot@npm:1.0.2" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-compose-refs": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: edf5edf435ff594bea7e198bf16d46caf81b6fb559493acad4fa8c308218896136acb16f9b7238c788fd13e94a904f2fd0b6d834e530e4cae94522cdb8f77ce9 + languageName: node + linkType: hard + +"@radix-ui/react-use-callback-ref@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-callback-ref@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: b9fd39911c3644bbda14a84e4fca080682bef84212b8d8931fcaa2d2814465de242c4cfd8d7afb3020646bead9c5e539d478cea0a7031bee8a8a3bb164f3bc4c + languageName: node + linkType: hard + +"@radix-ui/react-use-controllable-state@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-controllable-state@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-use-callback-ref": 1.0.1 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: dee2be1937d293c3a492cb6d279fc11495a8f19dc595cdbfe24b434e917302f9ac91db24e8cc5af9a065f3f209c3423115b5442e65a5be9fd1e9091338972be9 + languageName: node + linkType: hard + +"@radix-ui/react-use-layout-effect@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/react-use-layout-effect@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: bed9c7e8de243a5ec3b93bb6a5860950b0dba359b6680c84d57c7a655e123dec9b5891c5dfe81ab970652e7779fe2ad102a23177c7896dde95f7340817d47ae5 + languageName: node + linkType: hard + "@reduxjs/toolkit@npm:1.8.2": version: 1.8.2 resolution: "@reduxjs/toolkit@npm:1.8.2" @@ -3229,6 +3423,15 @@ __metadata: languageName: node linkType: hard +"class-variance-authority@npm:0.7.0": + version: 0.7.0 + resolution: "class-variance-authority@npm:0.7.0" + dependencies: + clsx: 2.0.0 + checksum: e7fd1fab433ef06f52a1b7b241b70b4a185864deef199d3b0a2c3412f1cc179517288264c383f3b971a00d76811625fc8f7ffe709e6170219e88cd7368f08a20 + languageName: node + linkType: hard + "classnames@npm:2.3.1, classnames@npm:2.x, classnames@npm:^2.2.1, classnames@npm:^2.2.6": version: 2.3.1 resolution: "classnames@npm:2.3.1" @@ -3300,6 +3503,20 @@ __metadata: languageName: node linkType: hard +"clsx@npm:2.0.0": + version: 2.0.0 + resolution: "clsx@npm:2.0.0" + checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e + languageName: node + linkType: hard + +"clsx@npm:^2.1.0": + version: 2.1.0 + resolution: "clsx@npm:2.1.0" + checksum: 43fefc29b6b49c9476fbce4f8b1cc75c27b67747738e598e6651dd40d63692135dc60b18fa1c5b78a2a9ba8ae6fd2055a068924b94e20b42039bd53b78b98e1d + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -6644,6 +6861,7 @@ __metadata: "@json2csv/plainjs": ^6.1.3 "@loaders.gl/core": 3.3.1 "@luma.gl/constants": 8.5.18 + "@radix-ui/react-collapsible": 1.0.3 "@reduxjs/toolkit": 1.8.2 "@tailwindcss/forms": 0.4.0 "@tailwindcss/typography": 0.5.0 @@ -6663,7 +6881,9 @@ __metadata: autoprefixer: 10.2.5 axios: 1.3.4 chroma-js: 2.1.2 + class-variance-authority: 0.7.0 classnames: 2.3.1 + clsx: ^2.1.0 cypress: 13.2.0 d3-array: 3.0.2 d3-format: 3.0.1 @@ -6703,7 +6923,9 @@ __metadata: rooks: 7.14.1 sharp: 0.32.6 start-server-and-test: 1.14.0 + tailwind-merge: 2.2.1 tailwindcss: 3.3.1 + tailwindcss-animate: 1.0.7 typescript: 5.2.2 update-browserslist-db: ^1.0.13 uuid: 8.3.2 @@ -9862,6 +10084,24 @@ __metadata: languageName: node linkType: hard +"tailwind-merge@npm:2.2.1": + version: 2.2.1 + resolution: "tailwind-merge@npm:2.2.1" + dependencies: + "@babel/runtime": ^7.23.7 + checksum: fd149409b1c18f3bc57aa30ae3a0e0c7f2913636666bd920c1aceeb8798b36766be55dfec8581e63860b83c7e405700ef530952a59c828ccff0c2a401fa67f05 + languageName: node + linkType: hard + +"tailwindcss-animate@npm:1.0.7": + version: 1.0.7 + resolution: "tailwindcss-animate@npm:1.0.7" + peerDependencies: + tailwindcss: "*" + checksum: c1760983eb3fec0c8421e95082bf308e6845df43e2f90862386366e82545c801b26b4d189c4cd23d6915252b76d18005c8e5f591f8b119944c7fb8650d0f8bce + languageName: node + linkType: hard + "tailwindcss@npm:3.3.1": version: 3.3.1 resolution: "tailwindcss@npm:3.3.1"