@omnsight/osint-entity-components 0.1.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.
Files changed (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +76 -0
  3. package/package.json +82 -0
  4. package/src/App.tsx +245 -0
  5. package/src/assets/icons/generated/basil-document-solid.tsx +8 -0
  6. package/src/assets/icons/generated/boxicons-announcement.tsx +8 -0
  7. package/src/assets/icons/generated/boxicons-book.tsx +8 -0
  8. package/src/assets/icons/generated/codicon-organization.tsx +8 -0
  9. package/src/assets/icons/generated/emojione-monotone-ship.tsx +8 -0
  10. package/src/assets/icons/generated/fa-solid-ship.tsx +8 -0
  11. package/src/assets/icons/generated/flowbite-truck-solid.tsx +8 -0
  12. package/src/assets/icons/generated/fluent-emoji-high-contrast-broken-chain.tsx +8 -0
  13. package/src/assets/icons/generated/fluent-emoji-high-contrast-military-helmet.tsx +8 -0
  14. package/src/assets/icons/generated/game-icons-bombing-run.tsx +8 -0
  15. package/src/assets/icons/generated/game-icons-missile-launcher.tsx +8 -0
  16. package/src/assets/icons/generated/game-icons-pistol-gun.tsx +8 -0
  17. package/src/assets/icons/generated/gg-website.tsx +8 -0
  18. package/src/assets/icons/generated/hugeicons-trade-up.tsx +8 -0
  19. package/src/assets/icons/generated/ic-sharp-oil-barrel.tsx +8 -0
  20. package/src/assets/icons/generated/ion-train-sharp.tsx +8 -0
  21. package/src/assets/icons/generated/mdi-account-school.tsx +8 -0
  22. package/src/assets/icons/generated/mdi-account-tie-hat.tsx +8 -0
  23. package/src/assets/icons/generated/mdi-account-tie.tsx +19 -0
  24. package/src/assets/icons/generated/mdi-airplane.tsx +8 -0
  25. package/src/assets/icons/generated/mdi-factory.tsx +19 -0
  26. package/src/assets/icons/generated/mdi-forum.tsx +8 -0
  27. package/src/assets/icons/generated/mdi-handcuffs.tsx +8 -0
  28. package/src/assets/icons/generated/mdi-tank.tsx +19 -0
  29. package/src/assets/icons/generated/mingcute-government-line.tsx +25 -0
  30. package/src/assets/icons/generated/mingcute-phone-call-fill.tsx +8 -0
  31. package/src/assets/icons/generated/pixel-technology.tsx +8 -0
  32. package/src/assets/icons/generated/ri-exchange-box-fill.tsx +8 -0
  33. package/src/assets/icons/generated/ri-seedling-line.tsx +8 -0
  34. package/src/assets/icons/generated/ri-spy-fill.tsx +8 -0
  35. package/src/assets/icons/generated/streamline-cyber-newspaper-2.tsx +8 -0
  36. package/src/assets/icons/generated/streamline-flex-deepfake-technology-1-solid.tsx +8 -0
  37. package/src/assets/icons/generated/uit-social-media-logo.tsx +8 -0
  38. package/src/avatars/EmptyAvatar.tsx +12 -0
  39. package/src/avatars/EventAvatar.tsx +40 -0
  40. package/src/avatars/OrganizationAvatar.tsx +43 -0
  41. package/src/avatars/PersonAvatar.tsx +41 -0
  42. package/src/avatars/SourceAvatar.tsx +67 -0
  43. package/src/avatars/WebsiteAvatar.tsx +40 -0
  44. package/src/avatars/index.ts +12 -0
  45. package/src/avatars/layouts/AvatarDropdown.tsx +48 -0
  46. package/src/avatars/layouts/AvatarRowList.tsx +23 -0
  47. package/src/avatars/layouts/AvatarSpan.tsx +11 -0
  48. package/src/avatars/layouts/EntityStyles.css +10 -0
  49. package/src/avatars/layouts/RelationTooltip.tsx +75 -0
  50. package/src/cards/EventCard.tsx +46 -0
  51. package/src/cards/OrganizationCard.tsx +38 -0
  52. package/src/cards/PersonCard.tsx +46 -0
  53. package/src/cards/SourceCard.tsx +63 -0
  54. package/src/cards/WebsiteCard.tsx +63 -0
  55. package/src/cards/index.ts +5 -0
  56. package/src/env.d.ts +2 -0
  57. package/src/i18n.ts +22 -0
  58. package/src/icons/Event/Icon.tsx +32 -0
  59. package/src/icons/Event/Select.tsx +61 -0
  60. package/src/icons/Event/icons.ts +118 -0
  61. package/src/icons/Organization/Icon.tsx +41 -0
  62. package/src/icons/Organization/Select.tsx +61 -0
  63. package/src/icons/Organization/icons.ts +53 -0
  64. package/src/icons/Person/Icon.tsx +34 -0
  65. package/src/icons/Person/Select.tsx +55 -0
  66. package/src/icons/Person/icons.ts +27 -0
  67. package/src/icons/Source/Icon.tsx +35 -0
  68. package/src/icons/Source/Select.tsx +61 -0
  69. package/src/icons/Source/icons.ts +40 -0
  70. package/src/icons/Website/Icon.tsx +39 -0
  71. package/src/icons/Website/Select.tsx +61 -0
  72. package/src/icons/Website/icons.ts +35 -0
  73. package/src/icons/index.ts +10 -0
  74. package/src/index.tsx +3 -0
  75. package/src/locales/en.json +75 -0
  76. package/src/locales/zh.json +76 -0
  77. package/src/main.tsx +22 -0
@@ -0,0 +1,48 @@
1
+ import React, { useState } from 'react';
2
+ import { ActionIcon, Stack, Popover } from '@mantine/core';
3
+
4
+ interface Props {
5
+ children: React.ReactNode[];
6
+ avatarOnOpen: React.ReactNode;
7
+ avatarOnClose: React.ReactNode;
8
+ }
9
+
10
+ export const AvatarDropdown: React.FC<Props> = ({ children, avatarOnOpen, avatarOnClose }) => {
11
+ const [opened, setOpened] = useState(false);
12
+
13
+ return (
14
+ <Popover
15
+ opened={opened}
16
+ onChange={setOpened}
17
+ position="bottom"
18
+ withArrow
19
+ shadow="md"
20
+ width={60}
21
+ withinPortal
22
+ >
23
+ <Popover.Target>
24
+ <ActionIcon
25
+ variant="light"
26
+ color="blue"
27
+ size="lg"
28
+ radius="xl"
29
+ onClick={() => setOpened((o) => !o)}
30
+ >
31
+ {opened ? avatarOnOpen : avatarOnClose}
32
+ </ActionIcon>
33
+ </Popover.Target>
34
+ <Popover.Dropdown
35
+ style={{
36
+ padding: 5,
37
+ backgroundColor: 'transparent',
38
+ border: 'none',
39
+ boxShadow: 'none',
40
+ }}
41
+ >
42
+ <Stack gap={8} style={{ backgroundColor: 'transparent', padding: 5 }}>
43
+ {children}
44
+ </Stack>
45
+ </Popover.Dropdown>
46
+ </Popover>
47
+ );
48
+ };
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { Avatar, Text } from '@mantine/core';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ interface Props {
6
+ children: React.ReactNode[];
7
+ }
8
+
9
+ export const AvatarRowList: React.FC<Props> = ({ children }) => {
10
+ const { t } = useTranslation();
11
+
12
+ return (
13
+ <Avatar.Group>
14
+ {children.length === 0 ? (
15
+ <Text c="dimmed" size="sm" fs="italic">
16
+ {t('common.notFound')}
17
+ </Text>
18
+ ) : (
19
+ children
20
+ )}
21
+ </Avatar.Group>
22
+ );
23
+ };
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { Avatar } from '@mantine/core';
3
+ import { EmptyAvatar } from '../EmptyAvatar';
4
+
5
+ interface Props {
6
+ children: React.ReactNode[];
7
+ }
8
+
9
+ export const AvatarSpan: React.FC<Props> = ({ children }) => {
10
+ return <Avatar.Group>{children.length === 0 ? <EmptyAvatar /> : children}</Avatar.Group>;
11
+ };
@@ -0,0 +1,10 @@
1
+ .entity-avatar {
2
+ transition: all 0.2s ease;
3
+ border: 2px solid var(--mantine-color-body);
4
+ }
5
+
6
+ .entity-avatar:hover {
7
+ transform: scale(1.25);
8
+ z-index: 100 !important;
9
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
10
+ }
@@ -0,0 +1,75 @@
1
+ import { Stack, Group, Text, Box, rem, RingProgress } from '@mantine/core';
2
+ import type { Relation } from 'omni-osint-crud-client';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ interface Props {
6
+ relation?: Relation;
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ export const RelationTooltip: React.FC<Props> = ({ relation, children }) => {
11
+ const { t } = useTranslation();
12
+ if (!relation) return <>{children}</>;
13
+
14
+ const confVal = relation.confidence || 0;
15
+ let confColor = 'red';
16
+ if (confVal >= 80) {
17
+ confColor = 'green';
18
+ } else if (confVal >= 50) {
19
+ confColor = 'yellow';
20
+ }
21
+
22
+ const formatDate = (ts?: number | null) => {
23
+ if (!ts) return 'N/A';
24
+ try {
25
+ const d = new Date(ts * 1000);
26
+ return d.toLocaleString(undefined, {
27
+ year: 'numeric',
28
+ month: 'numeric',
29
+ day: 'numeric',
30
+ hour: '2-digit',
31
+ minute: '2-digit',
32
+ hour12: false,
33
+ });
34
+ } catch {
35
+ return 'Invalid Date';
36
+ }
37
+ };
38
+
39
+ return (
40
+ <Stack gap="xs" p={4}>
41
+ <Group justify="space-between" align="center">
42
+ <Text fw={700} size="sm" style={{ lineHeight: 1 }}>
43
+ {relation.label || t('tooltip.relation')}
44
+ </Text>
45
+ <Group gap={4}>
46
+ <Text size="xs" c="dimmed">
47
+ {t('tooltip.confidence')}
48
+ </Text>
49
+ <RingProgress
50
+ size={36}
51
+ thickness={3}
52
+ roundCaps
53
+ sections={[{ value: relation.confidence || 0, color: confColor }]}
54
+ label={
55
+ <Text c={confColor} fw={700} ta="center" size="xs" style={{ fontSize: 9 }}>
56
+ {relation.confidence || 0}
57
+ </Text>
58
+ }
59
+ />
60
+ </Group>
61
+ </Group>
62
+
63
+ <Box>{children}</Box>
64
+
65
+ <Group justify="space-between" mt={4}>
66
+ <Text size="xs" c="dimmed" style={{ fontSize: rem(10) }}>
67
+ {t('tooltip.createdDate')}: {formatDate(relation.created_at)}
68
+ </Text>
69
+ <Text size="xs" c="dimmed" style={{ fontSize: rem(10) }}>
70
+ {t('tooltip.updatedDate')}: {formatDate(relation.updated_at)}
71
+ </Text>
72
+ </Group>
73
+ </Stack>
74
+ );
75
+ };
@@ -0,0 +1,46 @@
1
+ import { Badge, Group, Paper, Stack, Text, Title } from "@mantine/core";
2
+ import { type Event } from "omni-osint-crud-client";
3
+ import { useTranslation } from "react-i18next";
4
+ import React from "react";
5
+
6
+ interface Props {
7
+ event: Event;
8
+ background?: string;
9
+ withBorder?: boolean;
10
+ action?: React.ReactNode;
11
+ }
12
+
13
+ export const EventCard: React.FC<Props> = ({
14
+ event,
15
+ background,
16
+ withBorder = true,
17
+ action,
18
+ }) => {
19
+ const { t } = useTranslation();
20
+
21
+ return (
22
+ <Paper p="xs" bg={background} withBorder={withBorder}>
23
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
24
+ <Stack gap={0}>
25
+ <Title>{event.title || t("event.title")}</Title>
26
+ {event.happened_at && (
27
+ <Text c="dimmed">
28
+ {new Date(event.happened_at * 1000).toLocaleString()}
29
+ </Text>
30
+ )}
31
+ <Text truncate="end">
32
+ {event.description || t("event.description")}
33
+ </Text>
34
+ {event.tags && (
35
+ <Group gap="xs" mt="xs">
36
+ {event.tags.map((tag) => (
37
+ <Badge key={tag}>{tag}</Badge>
38
+ ))}
39
+ </Group>
40
+ )}
41
+ </Stack>
42
+ {action}
43
+ </Group>
44
+ </Paper>
45
+ );
46
+ };
@@ -0,0 +1,38 @@
1
+ import { Badge, Group, Paper, Stack, Title } from "@mantine/core";
2
+ import { type Organization } from "omni-osint-crud-client";
3
+ import { useTranslation } from "react-i18next";
4
+ import React from "react";
5
+
6
+ interface Props {
7
+ organization: Organization;
8
+ withBorder?: boolean;
9
+ action?: React.ReactNode;
10
+ background?: string;
11
+ }
12
+
13
+ export const OrganizationCard: React.FC<Props> = ({
14
+ organization,
15
+ withBorder = true,
16
+ action,
17
+ background,
18
+ }) => {
19
+ const { t } = useTranslation();
20
+
21
+ return (
22
+ <Paper withBorder={withBorder} p="xs" bg={background}>
23
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
24
+ <Stack gap={0}>
25
+ <Title>{organization.name || t("organization.name")}</Title>
26
+ {organization.tags && (
27
+ <Group gap="xs" mt="xs">
28
+ {organization.tags.map((tag) => (
29
+ <Badge key={tag}>{tag}</Badge>
30
+ ))}
31
+ </Group>
32
+ )}
33
+ </Stack>
34
+ {action}
35
+ </Group>
36
+ </Paper>
37
+ );
38
+ };
@@ -0,0 +1,46 @@
1
+ import { Badge, Group, Paper, Stack, Text, Title } from "@mantine/core";
2
+ import { type Person } from "omni-osint-crud-client";
3
+ import { useTranslation } from "react-i18next";
4
+ import React from "react";
5
+
6
+ interface Props {
7
+ person: Person;
8
+ withBorder?: boolean;
9
+ action?: React.ReactNode;
10
+ background?: string;
11
+ }
12
+
13
+ export const PersonCard: React.FC<Props> = ({
14
+ person,
15
+ withBorder = true,
16
+ action,
17
+ background,
18
+ }) => {
19
+ const { t } = useTranslation();
20
+
21
+ return (
22
+ <Paper withBorder={withBorder} p="xs" bg={background}>
23
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
24
+ <Stack gap={0}>
25
+ <Title>{person.name || t("person.name")}</Title>
26
+ {person.role && (
27
+ <Text c="dimmed">{person.role || t("person.role")}</Text>
28
+ )}
29
+ {person.aliases && (
30
+ <Text truncate="end">
31
+ {t("person.aliases")}: {person.aliases.join(", ")}
32
+ </Text>
33
+ )}
34
+ {person.tags && (
35
+ <Group gap="xs" mt="xs">
36
+ {person.tags.map((tag) => (
37
+ <Badge key={tag}>{tag}</Badge>
38
+ ))}
39
+ </Group>
40
+ )}
41
+ </Stack>
42
+ {action}
43
+ </Group>
44
+ </Paper>
45
+ );
46
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ ActionIcon,
3
+ Badge,
4
+ Group,
5
+ Paper,
6
+ Stack,
7
+ Text,
8
+ Title,
9
+ } from "@mantine/core";
10
+ import { type Source } from "omni-osint-crud-client";
11
+ import { useTranslation } from "react-i18next";
12
+ import React from "react";
13
+ import { LinkIcon } from "@heroicons/react/24/solid";
14
+
15
+ interface Props {
16
+ source: Source;
17
+ withBorder?: boolean;
18
+ action?: React.ReactNode;
19
+ background?: string;
20
+ }
21
+
22
+ export const SourceCard: React.FC<Props> = ({
23
+ source,
24
+ withBorder = true,
25
+ action,
26
+ background,
27
+ }) => {
28
+ const { t } = useTranslation();
29
+
30
+ return (
31
+ <Paper withBorder={withBorder} p="xs" bg={background}>
32
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
33
+ <Stack gap={0}>
34
+ <Group>
35
+ <Title>{source.name || t("source.name")}</Title>
36
+ {source.url && (
37
+ <ActionIcon
38
+ variant="subtle"
39
+ size="sm"
40
+ component="a"
41
+ href={source.url}
42
+ target="_blank"
43
+ >
44
+ <LinkIcon />
45
+ </ActionIcon>
46
+ )}
47
+ </Group>
48
+ <Text truncate="end">
49
+ {source.description || t("source.description")}
50
+ </Text>
51
+ {source.tags && (
52
+ <Group gap="xs" mt="xs">
53
+ {source.tags.map((tag) => (
54
+ <Badge key={tag}>{tag}</Badge>
55
+ ))}
56
+ </Group>
57
+ )}
58
+ </Stack>
59
+ {action}
60
+ </Group>
61
+ </Paper>
62
+ );
63
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ ActionIcon,
3
+ Badge,
4
+ Group,
5
+ Paper,
6
+ Stack,
7
+ Text,
8
+ Title,
9
+ } from "@mantine/core";
10
+ import { type Website } from "omni-osint-crud-client";
11
+ import { useTranslation } from "react-i18next";
12
+ import React from "react";
13
+ import { LinkIcon } from "@heroicons/react/24/solid";
14
+
15
+ interface Props {
16
+ website: Website;
17
+ withBorder?: boolean;
18
+ action?: React.ReactNode;
19
+ background?: string;
20
+ }
21
+
22
+ export const WebsiteCard: React.FC<Props> = ({
23
+ website,
24
+ withBorder = true,
25
+ action,
26
+ background,
27
+ }) => {
28
+ const { t } = useTranslation();
29
+
30
+ return (
31
+ <Paper withBorder={withBorder} p="xs" bg={background}>
32
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
33
+ <Stack gap={0}>
34
+ <Group>
35
+ <Title>{website.title || t("website.title")}</Title>
36
+ {website.url && (
37
+ <ActionIcon
38
+ variant="subtle"
39
+ size="sm"
40
+ component="a"
41
+ href={website.url}
42
+ target="_blank"
43
+ >
44
+ <LinkIcon />
45
+ </ActionIcon>
46
+ )}
47
+ </Group>
48
+ <Text truncate="end">
49
+ {website.description || t("website.description")}
50
+ </Text>
51
+ {website.tags && (
52
+ <Group gap="xs" mt="xs">
53
+ {website.tags.map((tag) => (
54
+ <Badge key={tag}>{tag}</Badge>
55
+ ))}
56
+ </Group>
57
+ )}
58
+ </Stack>
59
+ {action}
60
+ </Group>
61
+ </Paper>
62
+ );
63
+ };
@@ -0,0 +1,5 @@
1
+ export * from './EventCard';
2
+ export * from './PersonCard';
3
+ export * from './OrganizationCard';
4
+ export * from './WebsiteCard';
5
+ export * from './SourceCard';
package/src/env.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare module "*.css";
2
+ declare module "*.module.css";
package/src/i18n.ts ADDED
@@ -0,0 +1,22 @@
1
+ import i18n from "i18next";
2
+ import { initReactI18next } from "react-i18next";
3
+ import en from "./locales/en.json";
4
+ import zh from "./locales/zh.json";
5
+
6
+ i18n.use(initReactI18next).init({
7
+ resources: {
8
+ en: {
9
+ translation: en,
10
+ },
11
+ zh: {
12
+ translation: zh,
13
+ },
14
+ },
15
+ lng: "en",
16
+ fallbackLng: "en",
17
+ interpolation: {
18
+ escapeValue: false,
19
+ },
20
+ });
21
+
22
+ export default i18n;
@@ -0,0 +1,32 @@
1
+ import { ThemeIcon } from "@mantine/core";
2
+ import { CalendarDaysIcon } from "@heroicons/react/24/solid";
3
+ import { type Event } from "omni-osint-crud-client";
4
+ import { ICON_OPTIONS } from "./icons";
5
+
6
+ interface Props {
7
+ event: Event;
8
+ size?: number | string;
9
+ [key: string]: any;
10
+ }
11
+
12
+ /**
13
+ * Renders an icon for an event based on its type.
14
+ * @param event The event object, must contain 'type' and 'attributes'.
15
+ * @param props Additional props to pass to the icon.
16
+ * @returns A component displaying the event icon.
17
+ */
18
+ export const EventIcon: React.FC<Props> = ({ event, size = "md", ...props }) => {
19
+ const iconColor = String((event.attributes || {}).icon_color || "#0089ff");
20
+
21
+ const selectedType = ICON_OPTIONS.find(
22
+ (option) => option.value === event.type,
23
+ );
24
+ const Icon =
25
+ selectedType && selectedType.icon ? selectedType.icon : CalendarDaysIcon;
26
+
27
+ return (
28
+ <ThemeIcon size={size} radius="xl" color={iconColor}>
29
+ <Icon style={{ width: "70%", height: "70%", color: "white" }} {...props} />
30
+ </ThemeIcon>
31
+ );
32
+ };
@@ -0,0 +1,61 @@
1
+ import { type Event } from "omni-osint-crud-client";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Group, Select, ColorInput } from "@mantine/core";
4
+ import { ICON_OPTIONS } from "./icons";
5
+ import { EventIcon } from "./Icon";
6
+
7
+ interface EventIconSelectProps {
8
+ value: Event;
9
+ onChange: (value: Event) => void;
10
+ }
11
+
12
+ export const EventIconSelect: React.FC<EventIconSelectProps> = ({
13
+ value,
14
+ onChange,
15
+ }) => {
16
+ const { t } = useTranslation();
17
+ const colors = [
18
+ "#0089ff",
19
+ "#ff0000",
20
+ "#00ba21",
21
+ "#c18c17",
22
+ "#be4bdb",
23
+ "#ababab",
24
+ "#7950f2",
25
+ ];
26
+
27
+ const handleTypeChange = (type: string | null) => {
28
+ onChange({ ...value, type: type || undefined });
29
+ };
30
+
31
+ const handleColorChange = (color: string) => {
32
+ onChange({
33
+ ...value,
34
+ attributes: { ...(value.attributes || {}), icon_color: color },
35
+ });
36
+ };
37
+
38
+ const translatedOptions = ICON_OPTIONS.map((option) => ({
39
+ ...option,
40
+ label: t(`event.type.${option.label}`),
41
+ }));
42
+
43
+ return (
44
+ <Group>
45
+ <Select
46
+ leftSection={<EventIcon event={value} />}
47
+ defaultValue={translatedOptions[0].value}
48
+ value={value.type}
49
+ onChange={handleTypeChange}
50
+ data={translatedOptions}
51
+ style={{ flex: 1 }}
52
+ />
53
+ <ColorInput
54
+ value={String((value.attributes || {}).icon_color || colors[0])}
55
+ onChange={handleColorChange}
56
+ swatches={colors}
57
+ style={{ flex: 1 }}
58
+ />
59
+ </Group>
60
+ );
61
+ };
@@ -0,0 +1,118 @@
1
+ import { IconMdiHandcuffs } from '@/assets/icons/generated/mdi-handcuffs';
2
+ import { IconHugeiconsTradeUp } from '@/assets/icons/generated/hugeicons-trade-up';
3
+ import { IconGameIconsPistolGun } from '@/assets/icons/generated/game-icons-pistol-gun';
4
+ import { IconIcSharpOilBarrel } from '@/assets/icons/generated/ic-sharp-oil-barrel';
5
+ import { IconRiSpyFill } from '@/assets/icons/generated/ri-spy-fill';
6
+ import { IconFluentEmojiHighContrastMilitaryHelmet } from '@/assets/icons/generated/fluent-emoji-high-contrast-military-helmet';
7
+ import { IconMdiTank } from '@/assets/icons/generated/mdi-tank';
8
+ import { IconFaSolidShip } from '@/assets/icons/generated/fa-solid-ship';
9
+ import { IconMdiAirplane } from '@/assets/icons/generated/mdi-airplane';
10
+ import { IconGameIconsMissileLauncher } from '@/assets/icons/generated/game-icons-missile-launcher';
11
+ import { IconGameIconsBombingRun } from '@/assets/icons/generated/game-icons-bombing-run';
12
+ import { IconIonTrainSharp } from '@/assets/icons/generated/ion-train-sharp';
13
+ import { IconFlowbiteTruckSolid } from '@/assets/icons/generated/flowbite-truck-solid';
14
+ import { IconEmojioneMonotoneShip } from '@/assets/icons/generated/emojione-monotone-ship';
15
+ import { IconFluentEmojiHighContrastBrokenChain } from '@/assets/icons/generated/fluent-emoji-high-contrast-broken-chain';
16
+ import { IconRiExchangeBoxFill } from '@/assets/icons/generated/ri-exchange-box-fill';
17
+ import { IconMingcutePhoneCallFill } from '@/assets/icons/generated/mingcute-phone-call-fill';
18
+ import { IconBoxiconsAnnouncement } from '@/assets/icons/generated/boxicons-announcement';
19
+
20
+ interface IconOption {
21
+ value: string;
22
+ label: string;
23
+ icon?: React.FC<React.ComponentPropsWithoutRef<'svg'>>;
24
+ }
25
+
26
+ // Find icon items in https://icon-sets.iconify.design
27
+ export const ICON_OPTIONS: IconOption[] = [
28
+ {
29
+ value: 'announcement',
30
+ label: 'announcement',
31
+ icon: IconBoxiconsAnnouncement, // icon: boxicons:announcement
32
+ },
33
+ {
34
+ value: 'conversation',
35
+ label: 'conversation',
36
+ icon: IconMingcutePhoneCallFill, // icon: mingcute:phone-call-fill
37
+ },
38
+ {
39
+ value: 'trade',
40
+ label: 'trade',
41
+ icon: IconRiExchangeBoxFill, // icon: ri:exchange-box-fill
42
+ },
43
+ {
44
+ value: 'oil',
45
+ label: 'oil',
46
+ icon: IconIcSharpOilBarrel, // icon: ic:sharp-oil-barrel
47
+ },
48
+ {
49
+ value: 'exchange',
50
+ label: 'exchange',
51
+ icon: IconHugeiconsTradeUp, // icon: hugeicons:trade-up
52
+ },
53
+ {
54
+ value: 'supplychain-risk',
55
+ label: 'supplychain-risk',
56
+ icon: IconFluentEmojiHighContrastBrokenChain, // icon: fluent-emoji-high-contrast:broken-chain
57
+ },
58
+ {
59
+ value: 'ship',
60
+ label: 'ship',
61
+ icon: IconEmojioneMonotoneShip, // icon: emojione-monotone:ship
62
+ },
63
+ {
64
+ value: 'truck',
65
+ label: 'truck',
66
+ icon: IconFlowbiteTruckSolid, // icon: flowbite:truck-solid
67
+ },
68
+ {
69
+ value: 'train',
70
+ label: 'train',
71
+ icon: IconIonTrainSharp, // icon: ion:train-sharp
72
+ },
73
+ {
74
+ value: 'crime',
75
+ label: 'crime',
76
+ icon: IconMdiHandcuffs, // icon: mdi:handcuffs
77
+ },
78
+ {
79
+ value: 'shot',
80
+ label: 'shot',
81
+ icon: IconGameIconsPistolGun, // icon: game-icons:pistol-gun
82
+ },
83
+ {
84
+ value: 'bomb',
85
+ label: 'bomb',
86
+ icon: IconGameIconsBombingRun, // icon: game-icons:bombing-run
87
+ },
88
+ {
89
+ value: 'missile',
90
+ label: 'missile',
91
+ icon: IconGameIconsMissileLauncher, // icon: game-icons:missile-launcher
92
+ },
93
+ {
94
+ value: 'plane',
95
+ label: 'plane',
96
+ icon: IconMdiAirplane, // icon: mdi:airplane
97
+ },
98
+ {
99
+ value: 'naval',
100
+ label: 'naval',
101
+ icon: IconFaSolidShip, // icon: fa-solid:ship
102
+ },
103
+ {
104
+ value: 'tank',
105
+ label: 'tank',
106
+ icon: IconMdiTank, // icon: mdi:tank
107
+ },
108
+ {
109
+ value: 'infantry',
110
+ label: 'infantry',
111
+ icon: IconFluentEmojiHighContrastMilitaryHelmet, // icon: fluent-emoji-high-contrast:military-helmet
112
+ },
113
+ {
114
+ value: 'intelligence',
115
+ label: 'intelligence',
116
+ icon: IconRiSpyFill, // icon: ri:spy-fill
117
+ },
118
+ ]