Skip to content

Commit

Permalink
feat: add legend components (#24)
Browse files Browse the repository at this point in the history
* feat: add legend component

* feat: add tooltip

* fix: title shouldn't be optional

* feat: add legend container and add tooltip to accordion

* fix: rename interface

* fix: rename

* fix: rename props

* fix: introduce LegendsOperation file

---------

Co-authored-by: marinovl7 <[email protected]>
  • Loading branch information
bohdangarchu and marinovl7 authored Nov 12, 2024
1 parent 2dd8cb3 commit 290f3dc
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 9 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
"react-dom": "18.3.1",
"react-leaflet": "^4.2.1",
"react-pdf": "^9.1.1",
"tailwind-variants": "0.1.20"
"tailwind-variants": "0.1.20",
"uuid": "^11.0.3"
},
"devDependencies": {
"@commitlint/cli": "^19.5.0",
Expand Down
10 changes: 9 additions & 1 deletion src/components/Accordions/Accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Accordion, AccordionItem } from '@nextui-org/accordion';

import { AccordionsProps } from '@/domain/props/AccordionProps';

import { Tooltip } from '../Tooltip/Tooltip';

export default function CustomAccordion({ items }: AccordionsProps) {
return (
<div className="w-full flex justify-start items-start max-w-[600px] overflow-visible overflow-x-auto p-2 rounded-lg">
Expand All @@ -16,7 +18,13 @@ export default function CustomAccordion({ items }: AccordionsProps) {
title={
<div className="flex justify-between items-center w-full">
<span>{item.title}</span>
{item.iconSrc && <img src={item.iconSrc} alt="info icon" className="w-[37px] h-[37px] p-[5.5px]" />}
{item.tooltipInfo ? (
<Tooltip text={item.tooltipInfo}>
{item.iconSrc && <img src={item.iconSrc} alt="info icon" className="w-[37px] h-[37px] p-[5.5px]" />}
</Tooltip>
) : (
item.iconSrc && <img src={item.iconSrc} alt="info icon" className="w-[37px] h-[37px] p-[5.5px]" />
)}
</div>
}
>
Expand Down
26 changes: 26 additions & 0 deletions src/components/Legend/GradientLegend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import GradientLegendProps from '@/domain/props/GradientLegendProps';

export default function GradientLegend({
startColor,
middleColor,
endColor,
startLabel,
endLabel,
}: GradientLegendProps) {
return (
<div className="relative flex flex-col items-center w-96 px-4 py-3">
<div
className="flex items-center w-full h-2 rounded-full"
style={{
background: middleColor
? `linear-gradient(90deg, hsl(var(--nextui-${startColor})) 0%, hsl(var(--nextui-${middleColor})) 50%, hsl(var(--nextui-${endColor})) 100%)`
: `linear-gradient(90deg, hsl(var(--nextui-${startColor})) 0%, hsl(var(--nextui-${endColor})) 100%)`,
}}
/>
<div className="flex justify-between w-full mt-2 text-xs font-medium">
<span>{startLabel}</span>
<span>{endLabel}</span>
</div>
</div>
);
}
25 changes: 25 additions & 0 deletions src/components/Legend/LegendContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import LegendContainerProps from '@/domain/props/LegendContainerProps';
import { LegendOperations } from '@/operations/legends/LegendOperations.ts';

import CustomAccordion from '../Accordions/Accordion';
import GradientLegend from './GradientLegend';
import PointLegend from './PointLegend';

export default function LegendContainer({ items }: LegendContainerProps) {
return (
<div className="w-[450px]">
<CustomAccordion
items={items.map((item) => ({
title: item.title,
iconSrc: '/Images/InfoIcon.svg',
tooltipInfo: item.tooltipInfo,
content: LegendOperations.isGradientLegendContainerItem(item) ? (
<GradientLegend {...item} />
) : (
<PointLegend {...item} />
),
}))}
/>
</div>
);
}
18 changes: 18 additions & 0 deletions src/components/Legend/PointLegend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { v4 as uuid } from 'uuid';

import { PointLegendProps } from '@/domain/props/PointLegendProps';

export default function PointLegend({ records }: PointLegendProps) {
return (
<div className="relative flex flex-col w-96 px-4 py-3">
<div className="flex flex-wrap gap-x-3 gap-y-2">
{records.map((record) => (
<div key={uuid()} className="flex items-center space-x-2">
<span className="w-3 h-3 rounded-full" style={{ backgroundColor: `hsl(var(--nextui-${record.color}))` }} />
<span className="text-sm">{record.label}</span>
</div>
))}
</div>
</div>
);
}
1 change: 1 addition & 0 deletions src/domain/entities/accordions/Accordions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface AccordionItemProps {
title: string;
iconSrc?: string;
tooltipInfo?: string;
content: React.ReactNode | string;
}
9 changes: 9 additions & 0 deletions src/domain/props/GradientLegendContainerItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface GradientLegendContainerItem {
startColor: string;
middleColor?: string;
endColor: string;
title: string;
startLabel: string;
endLabel: string;
tooltipInfo?: string;
}
7 changes: 7 additions & 0 deletions src/domain/props/GradientLegendProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default interface GradientLegendProps {
startColor: string;
middleColor?: string;
endColor: string;
startLabel: string;
endLabel: string;
}
6 changes: 6 additions & 0 deletions src/domain/props/LegendContainerProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { GradientLegendContainerItem } from './GradientLegendContainerItem';
import PointLegendContainerItem from './PointLegendContainerItem';

export default interface LegendContainerProps {
items: (PointLegendContainerItem | GradientLegendContainerItem)[];
}
7 changes: 7 additions & 0 deletions src/domain/props/PointLegendContainerItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import PointLegendRecord from './PointLegendRecord';

export default interface PointLegendContainerItem {
title: string;
records: PointLegendRecord[];
tooltipInfo?: string;
}
5 changes: 5 additions & 0 deletions src/domain/props/PointLegendProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import PointLegendRecord from './PointLegendRecord';

export interface PointLegendProps {
records: PointLegendRecord[];
}
4 changes: 4 additions & 0 deletions src/domain/props/PointLegendRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface PointLegendRecord {
label: string;
color: string;
}
20 changes: 20 additions & 0 deletions src/operations/legends/LegendOperations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { GradientLegendContainerItem } from '@/domain/props/GradientLegendContainerItem.ts';

export class LegendOperations {
static isGradientLegendContainerItem(value: unknown): value is GradientLegendContainerItem {
if (typeof value !== 'object' || value === null) {
return false;
}

const item = value as GradientLegendContainerItem;
return (
typeof item.startColor === 'string' &&
(typeof item.middleColor === 'string' || item.middleColor === undefined) &&
typeof item.endColor === 'string' &&
typeof item.title === 'string' &&
typeof item.startLabel === 'string' &&
typeof item.endLabel === 'string' &&
(typeof item.tooltipInfo === 'string' || item.tooltipInfo === undefined)
);
}
}
14 changes: 7 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@
"@react-types/menu" "3.9.9"
"@react-types/shared" "3.23.1"

"@nextui-org/[email protected]":
"@nextui-org/[email protected]", "@nextui-org/modal@^2.0.41":
version "2.0.41"
resolved "https://registry.yarnpkg.com/@nextui-org/modal/-/modal-2.0.41.tgz#3fba82661413236e9b41f3b4d6c50c3205d6292c"
integrity sha512-Sirn319xAf7E4cZqvQ0o0Vd3Xqy0FRSuhOTwp8dALMGTMY61c2nIyurgVCNP6hh8dMvMT7zQEPP9/LE0boFCEQ==
Expand Down Expand Up @@ -2818,7 +2818,7 @@
dependencies:
"@types/geojson" "*"

"@types/geojson@*", "@types/geojson@^7946.0.14", "@types/geojson@^7946.0.14":
"@types/geojson@*", "@types/geojson@^7946.0.14":
version "7946.0.14"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613"
integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==
Expand Down Expand Up @@ -4311,11 +4311,6 @@ geojson@^0.5.0:
resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0"
integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==

geojson@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0"
integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==

get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
Expand Down Expand Up @@ -6566,6 +6561,11 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==

uuid@^11.0.3:
version "11.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.0.3.tgz#248451cac9d1a4a4128033e765d137e2b2c49a3d"
integrity sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==

vt-pbf@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac"
Expand Down

0 comments on commit 290f3dc

Please sign in to comment.