@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.
- package/LICENSE +201 -0
- package/README.md +76 -0
- package/package.json +82 -0
- package/src/App.tsx +245 -0
- package/src/assets/icons/generated/basil-document-solid.tsx +8 -0
- package/src/assets/icons/generated/boxicons-announcement.tsx +8 -0
- package/src/assets/icons/generated/boxicons-book.tsx +8 -0
- package/src/assets/icons/generated/codicon-organization.tsx +8 -0
- package/src/assets/icons/generated/emojione-monotone-ship.tsx +8 -0
- package/src/assets/icons/generated/fa-solid-ship.tsx +8 -0
- package/src/assets/icons/generated/flowbite-truck-solid.tsx +8 -0
- package/src/assets/icons/generated/fluent-emoji-high-contrast-broken-chain.tsx +8 -0
- package/src/assets/icons/generated/fluent-emoji-high-contrast-military-helmet.tsx +8 -0
- package/src/assets/icons/generated/game-icons-bombing-run.tsx +8 -0
- package/src/assets/icons/generated/game-icons-missile-launcher.tsx +8 -0
- package/src/assets/icons/generated/game-icons-pistol-gun.tsx +8 -0
- package/src/assets/icons/generated/gg-website.tsx +8 -0
- package/src/assets/icons/generated/hugeicons-trade-up.tsx +8 -0
- package/src/assets/icons/generated/ic-sharp-oil-barrel.tsx +8 -0
- package/src/assets/icons/generated/ion-train-sharp.tsx +8 -0
- package/src/assets/icons/generated/mdi-account-school.tsx +8 -0
- package/src/assets/icons/generated/mdi-account-tie-hat.tsx +8 -0
- package/src/assets/icons/generated/mdi-account-tie.tsx +19 -0
- package/src/assets/icons/generated/mdi-airplane.tsx +8 -0
- package/src/assets/icons/generated/mdi-factory.tsx +19 -0
- package/src/assets/icons/generated/mdi-forum.tsx +8 -0
- package/src/assets/icons/generated/mdi-handcuffs.tsx +8 -0
- package/src/assets/icons/generated/mdi-tank.tsx +19 -0
- package/src/assets/icons/generated/mingcute-government-line.tsx +25 -0
- package/src/assets/icons/generated/mingcute-phone-call-fill.tsx +8 -0
- package/src/assets/icons/generated/pixel-technology.tsx +8 -0
- package/src/assets/icons/generated/ri-exchange-box-fill.tsx +8 -0
- package/src/assets/icons/generated/ri-seedling-line.tsx +8 -0
- package/src/assets/icons/generated/ri-spy-fill.tsx +8 -0
- package/src/assets/icons/generated/streamline-cyber-newspaper-2.tsx +8 -0
- package/src/assets/icons/generated/streamline-flex-deepfake-technology-1-solid.tsx +8 -0
- package/src/assets/icons/generated/uit-social-media-logo.tsx +8 -0
- package/src/avatars/EmptyAvatar.tsx +12 -0
- package/src/avatars/EventAvatar.tsx +40 -0
- package/src/avatars/OrganizationAvatar.tsx +43 -0
- package/src/avatars/PersonAvatar.tsx +41 -0
- package/src/avatars/SourceAvatar.tsx +67 -0
- package/src/avatars/WebsiteAvatar.tsx +40 -0
- package/src/avatars/index.ts +12 -0
- package/src/avatars/layouts/AvatarDropdown.tsx +48 -0
- package/src/avatars/layouts/AvatarRowList.tsx +23 -0
- package/src/avatars/layouts/AvatarSpan.tsx +11 -0
- package/src/avatars/layouts/EntityStyles.css +10 -0
- package/src/avatars/layouts/RelationTooltip.tsx +75 -0
- package/src/cards/EventCard.tsx +46 -0
- package/src/cards/OrganizationCard.tsx +38 -0
- package/src/cards/PersonCard.tsx +46 -0
- package/src/cards/SourceCard.tsx +63 -0
- package/src/cards/WebsiteCard.tsx +63 -0
- package/src/cards/index.ts +5 -0
- package/src/env.d.ts +2 -0
- package/src/i18n.ts +22 -0
- package/src/icons/Event/Icon.tsx +32 -0
- package/src/icons/Event/Select.tsx +61 -0
- package/src/icons/Event/icons.ts +118 -0
- package/src/icons/Organization/Icon.tsx +41 -0
- package/src/icons/Organization/Select.tsx +61 -0
- package/src/icons/Organization/icons.ts +53 -0
- package/src/icons/Person/Icon.tsx +34 -0
- package/src/icons/Person/Select.tsx +55 -0
- package/src/icons/Person/icons.ts +27 -0
- package/src/icons/Source/Icon.tsx +35 -0
- package/src/icons/Source/Select.tsx +61 -0
- package/src/icons/Source/icons.ts +40 -0
- package/src/icons/Website/Icon.tsx +39 -0
- package/src/icons/Website/Select.tsx +61 -0
- package/src/icons/Website/icons.ts +35 -0
- package/src/icons/index.ts +10 -0
- package/src/index.tsx +3 -0
- package/src/locales/en.json +75 -0
- package/src/locales/zh.json +76 -0
- package/src/main.tsx +22 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ThemeIcon } from "@mantine/core";
|
|
2
|
+
import { BuildingOfficeIcon } from "@heroicons/react/24/solid";
|
|
3
|
+
import { type Organization } from "omni-osint-crud-client";
|
|
4
|
+
import { ICON_OPTIONS } from "./icons";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
organization: Organization;
|
|
8
|
+
size?: number | string;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders an icon for an organization based on its type.
|
|
14
|
+
* @param organization The organization object, must contain 'type' and 'attributes'.
|
|
15
|
+
* @param props Additional props to pass to the icon.
|
|
16
|
+
* @returns A component displaying the organization icon.
|
|
17
|
+
*/
|
|
18
|
+
export const OrganizationIcon: React.FC<Props> = ({
|
|
19
|
+
organization,
|
|
20
|
+
size = "md",
|
|
21
|
+
...props
|
|
22
|
+
}) => {
|
|
23
|
+
const iconColor = String(
|
|
24
|
+
(organization.attributes || {}).icon_color || "#0089ff",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const selectedType = ICON_OPTIONS.find(
|
|
28
|
+
(option) => option.value === organization.type,
|
|
29
|
+
);
|
|
30
|
+
const Icon =
|
|
31
|
+
selectedType && selectedType.icon ? selectedType.icon : BuildingOfficeIcon;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<ThemeIcon variant="filled" size={size} radius="xl" color={iconColor}>
|
|
35
|
+
<Icon
|
|
36
|
+
style={{ width: "70%", height: "70%", color: "white" }}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</ThemeIcon>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type Organization } 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 { OrganizationIcon } from "./Icon";
|
|
6
|
+
|
|
7
|
+
interface OrganizationIconSelectProps {
|
|
8
|
+
value: Organization;
|
|
9
|
+
onChange: (value: Organization) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const OrganizationIconSelect: React.FC<OrganizationIconSelectProps> = ({
|
|
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(`organization.type.${option.label}`),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Group>
|
|
45
|
+
<Select
|
|
46
|
+
leftSection={<OrganizationIcon organization={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,53 @@
|
|
|
1
|
+
import { IconRiSeedlingLine } from '@/assets/icons/generated/ri-seedling-line';
|
|
2
|
+
import { IconMingcuteGovernmentLine } from '@/assets/icons/generated/mingcute-government-line';
|
|
3
|
+
import { IconStreamlineFlexDeepfakeTechnology1Solid } from '@/assets/icons/generated/streamline-flex-deepfake-technology-1-solid';
|
|
4
|
+
import { IconPixelTechnology } from '@/assets/icons/generated/pixel-technology';
|
|
5
|
+
import { IconMdiFactory } from '@/assets/icons/generated/mdi-factory';
|
|
6
|
+
import { IconCodiconOrganization } from '@/assets/icons/generated/codicon-organization';
|
|
7
|
+
|
|
8
|
+
import { BuildingOfficeIcon } from '@heroicons/react/24/solid';
|
|
9
|
+
|
|
10
|
+
interface IconOption {
|
|
11
|
+
value: string;
|
|
12
|
+
label: string;
|
|
13
|
+
icon?: React.FC<React.ComponentPropsWithoutRef<'svg'>>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Find icon items in https://icon-sets.iconify.design
|
|
17
|
+
export const ICON_OPTIONS: IconOption[] = [
|
|
18
|
+
{
|
|
19
|
+
value: 'company',
|
|
20
|
+
label: 'company',
|
|
21
|
+
icon: BuildingOfficeIcon,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
value: 'government',
|
|
25
|
+
label: 'government',
|
|
26
|
+
icon: IconMingcuteGovernmentLine, // icon: mingcute:government-line
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: 'military',
|
|
30
|
+
label: 'military',
|
|
31
|
+
icon: IconCodiconOrganization, // icon: codicon:organization
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: 'manufacturing',
|
|
35
|
+
label: 'manufacturing',
|
|
36
|
+
icon: IconMdiFactory, // icon: mdi:factory
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: 'agriculture',
|
|
40
|
+
label: 'agriculture',
|
|
41
|
+
icon: IconRiSeedlingLine, // icon: ri:seedling-line
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: 'semi-conductor',
|
|
45
|
+
label: 'semi-conductor',
|
|
46
|
+
icon: IconPixelTechnology, // icon: pixel:technology
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
value: 'technology',
|
|
50
|
+
label: 'technology',
|
|
51
|
+
icon: IconStreamlineFlexDeepfakeTechnology1Solid, // icon: streamline-flex:deepfake-technology-1-solid
|
|
52
|
+
},
|
|
53
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ThemeIcon } from "@mantine/core";
|
|
2
|
+
import { UserIcon } from "@heroicons/react/24/solid";
|
|
3
|
+
import { type Person } from "omni-osint-crud-client";
|
|
4
|
+
import { ICON_OPTIONS } from "./icons";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
person: Person;
|
|
8
|
+
size?: number | string;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders an icon for a person based on its type.
|
|
14
|
+
* @param person The person object, must contain 'type' and 'attributes'.
|
|
15
|
+
* @param props Additional props to pass to the icon.
|
|
16
|
+
* @returns A component displaying the person icon.
|
|
17
|
+
*/
|
|
18
|
+
export const PersonIcon: React.FC<Props> = ({ person, size = "md", ...props }) => {
|
|
19
|
+
const iconColor = String((person.attributes || {}).icon_color || "#0089ff");
|
|
20
|
+
|
|
21
|
+
const selectedType = ICON_OPTIONS.find(
|
|
22
|
+
(option) => option.value === person.type,
|
|
23
|
+
);
|
|
24
|
+
const Icon = selectedType && selectedType.icon ? selectedType.icon : UserIcon;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ThemeIcon variant="filled" size={size} radius="xl" color={iconColor}>
|
|
28
|
+
<Icon
|
|
29
|
+
style={{ width: "70%", height: "70%", color: "white" }}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
</ThemeIcon>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Person } 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 { PersonIcon } from './Icon';
|
|
6
|
+
|
|
7
|
+
interface PersonIconSelectProps {
|
|
8
|
+
value: Person;
|
|
9
|
+
onChange: (value: Person) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const PersonIconSelect: React.FC<PersonIconSelectProps> = ({ value, onChange }) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const colors = [
|
|
15
|
+
"#0089ff",
|
|
16
|
+
"#ff0000",
|
|
17
|
+
"#00ba21",
|
|
18
|
+
"#c18c17",
|
|
19
|
+
"#be4bdb",
|
|
20
|
+
"#ababab",
|
|
21
|
+
"#7950f2",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const handleTypeChange = (type: string | null) => {
|
|
25
|
+
onChange({ ...value, type: type || undefined });
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleColorChange = (color: string) => {
|
|
29
|
+
onChange({ ...value, attributes: { ...(value.attributes || {}), icon_color: color } });
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const translatedOptions = ICON_OPTIONS.map((option) => ({
|
|
33
|
+
...option,
|
|
34
|
+
label: t(`person.type.${option.label}`),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Group>
|
|
39
|
+
<Select
|
|
40
|
+
leftSection={<PersonIcon person={value} />}
|
|
41
|
+
defaultValue={translatedOptions[0].value}
|
|
42
|
+
value={value.type}
|
|
43
|
+
onChange={handleTypeChange}
|
|
44
|
+
data={translatedOptions}
|
|
45
|
+
style={{ flex: 1 }}
|
|
46
|
+
/>
|
|
47
|
+
<ColorInput
|
|
48
|
+
value={String((value.attributes || {}).icon_color || colors[0])}
|
|
49
|
+
onChange={handleColorChange}
|
|
50
|
+
swatches={colors}
|
|
51
|
+
style={{ flex: 1 }}
|
|
52
|
+
/>
|
|
53
|
+
</Group>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IconMdiAccountSchool } from '@/assets/icons/generated/mdi-account-school';
|
|
2
|
+
import { IconMdiAccountTieHat } from '@/assets/icons/generated/mdi-account-tie-hat';
|
|
3
|
+
import { IconMdiAccountTie } from '@/assets/icons/generated/mdi-account-tie';
|
|
4
|
+
interface IconOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: React.FC<React.ComponentPropsWithoutRef<'svg'>>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Find icon items in https://icon-sets.iconify.design
|
|
11
|
+
export const ICON_OPTIONS: IconOption[] = [
|
|
12
|
+
{
|
|
13
|
+
value: 'professional',
|
|
14
|
+
label: 'professional',
|
|
15
|
+
icon: IconMdiAccountTie, // icon: mdi:account-tie
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: 'gov-official',
|
|
19
|
+
label: 'gov-official',
|
|
20
|
+
icon: IconMdiAccountTieHat, // icon: mdi:account-tie-hat
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: 'school-personel',
|
|
24
|
+
label: 'school-personel',
|
|
25
|
+
icon: IconMdiAccountSchool, // icon: mdi:account-school
|
|
26
|
+
},
|
|
27
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ThemeIcon } from "@mantine/core";
|
|
2
|
+
import { DocumentIcon } from "@heroicons/react/24/solid";
|
|
3
|
+
import { type Source } from "omni-osint-crud-client";
|
|
4
|
+
import { ICON_OPTIONS } from "./icons";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
source: Source;
|
|
8
|
+
size?: number | string;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders an icon for a source based on its type.
|
|
14
|
+
* @param source The source object, must contain 'type' and 'attributes'.
|
|
15
|
+
* @param props Additional props to pass to the icon.
|
|
16
|
+
* @returns A component displaying the source icon.
|
|
17
|
+
*/
|
|
18
|
+
export const SourceIcon: React.FC<Props> = ({ source, size = "md", ...props }) => {
|
|
19
|
+
const iconColor = String((source.attributes || {}).icon_color || "#ababab");
|
|
20
|
+
|
|
21
|
+
const selectedType = ICON_OPTIONS.find(
|
|
22
|
+
(option) => option.value === source.type,
|
|
23
|
+
);
|
|
24
|
+
const Icon =
|
|
25
|
+
selectedType && selectedType.icon ? selectedType.icon : DocumentIcon;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<ThemeIcon variant="filled" size={size} radius="xl" color={iconColor}>
|
|
29
|
+
<Icon
|
|
30
|
+
style={{ width: "70%", height: "70%", color: "white" }}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
</ThemeIcon>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type Source } 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 { SourceIcon } from "./Icon";
|
|
6
|
+
|
|
7
|
+
interface SourceIconSelectProps {
|
|
8
|
+
value: Source;
|
|
9
|
+
onChange: (value: Source) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const SourceIconSelect: React.FC<SourceIconSelectProps> = ({
|
|
13
|
+
value,
|
|
14
|
+
onChange,
|
|
15
|
+
}) => {
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
const colors = [
|
|
18
|
+
"#ababab",
|
|
19
|
+
"#0089ff",
|
|
20
|
+
"#ff0000",
|
|
21
|
+
"#00ba21",
|
|
22
|
+
"#c18c17",
|
|
23
|
+
"#be4bdb",
|
|
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(`source.type.${option.label}`),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Group>
|
|
45
|
+
<Select
|
|
46
|
+
leftSection={<SourceIcon source={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,40 @@
|
|
|
1
|
+
import { IconUitSocialMediaLogo } from '@/assets/icons/generated/uit-social-media-logo';
|
|
2
|
+
import { IconStreamlineCyberNewspaper2 } from '@/assets/icons/generated/streamline-cyber-newspaper-2';
|
|
3
|
+
import { IconBasilDocumentSolid } from '@/assets/icons/generated/basil-document-solid';
|
|
4
|
+
import { IconBoxiconsBook } from '@/assets/icons/generated/boxicons-book';
|
|
5
|
+
import { IconGgWebsite } from '@/assets/icons/generated/gg-website';
|
|
6
|
+
|
|
7
|
+
interface IconOption {
|
|
8
|
+
value: string;
|
|
9
|
+
label: string;
|
|
10
|
+
icon?: React.FC<React.ComponentPropsWithoutRef<'svg'>>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Find icon items in https://icon-sets.iconify.design
|
|
14
|
+
export const ICON_OPTIONS: IconOption[] = [
|
|
15
|
+
{
|
|
16
|
+
value: 'news',
|
|
17
|
+
label: 'news',
|
|
18
|
+
icon: IconStreamlineCyberNewspaper2, // icon: streamline-cyber:newspaper-2
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: 'website',
|
|
22
|
+
label: 'website',
|
|
23
|
+
icon: IconGgWebsite, // icon: gg:website
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: 'social-media',
|
|
27
|
+
label: 'social-media',
|
|
28
|
+
icon: IconUitSocialMediaLogo, // icon: uit:social-media-logo
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'book',
|
|
32
|
+
label: 'book',
|
|
33
|
+
icon: IconBoxiconsBook, // icon: boxicons:book
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'paper',
|
|
37
|
+
label: 'paper',
|
|
38
|
+
icon: IconBasilDocumentSolid, // icon: basil:document-solid
|
|
39
|
+
},
|
|
40
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ThemeIcon } from "@mantine/core";
|
|
2
|
+
import { GlobeAltIcon } from "@heroicons/react/24/solid";
|
|
3
|
+
import { type Website } from "omni-osint-crud-client";
|
|
4
|
+
import { ICON_OPTIONS } from "./icons";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
website: Website;
|
|
8
|
+
size?: number | string;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renders an icon for a website based on its type.
|
|
14
|
+
* @param website The website object, must contain 'type' and 'attributes'.
|
|
15
|
+
* @param props Additional props to pass to the icon.
|
|
16
|
+
* @returns A component displaying the website icon.
|
|
17
|
+
*/
|
|
18
|
+
export const WebsiteIcon: React.FC<Props> = ({
|
|
19
|
+
website,
|
|
20
|
+
size = "md",
|
|
21
|
+
...props
|
|
22
|
+
}) => {
|
|
23
|
+
const iconColor = String((website.attributes || {}).icon_color || "#0089ff");
|
|
24
|
+
|
|
25
|
+
const selectedType = ICON_OPTIONS.find(
|
|
26
|
+
(option) => option.value === website.type,
|
|
27
|
+
);
|
|
28
|
+
const Icon =
|
|
29
|
+
selectedType && selectedType.icon ? selectedType.icon : GlobeAltIcon;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<ThemeIcon variant="filled" size={size} radius="xl" color={iconColor}>
|
|
33
|
+
<Icon
|
|
34
|
+
style={{ width: "70%", height: "70%", color: "white" }}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
</ThemeIcon>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type Website } 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 { WebsiteIcon } from "./Icon";
|
|
6
|
+
|
|
7
|
+
interface WebsiteIconSelectProps {
|
|
8
|
+
value: Website;
|
|
9
|
+
onChange: (value: Website) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const WebsiteIconSelect: React.FC<WebsiteIconSelectProps> = ({
|
|
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, title: 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(`website.type.${option.label}`),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Group>
|
|
45
|
+
<Select
|
|
46
|
+
leftSection={<WebsiteIcon website={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,35 @@
|
|
|
1
|
+
import { IconMdiForum } from '@/assets/icons/generated/mdi-forum';
|
|
2
|
+
import { IconStreamlineCyberNewspaper2 } from '@/assets/icons/generated/streamline-cyber-newspaper-2';
|
|
3
|
+
import { IconMingcuteGovernmentLine } from '@/assets/icons/generated/mingcute-government-line';
|
|
4
|
+
|
|
5
|
+
import { BuildingOfficeIcon } from '@heroicons/react/24/solid';
|
|
6
|
+
|
|
7
|
+
interface IconOption {
|
|
8
|
+
value: string;
|
|
9
|
+
label: string;
|
|
10
|
+
icon?: React.FC<React.ComponentPropsWithoutRef<'svg'>>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Find icon items in https://icon-sets.iconify.design
|
|
14
|
+
export const ICON_OPTIONS: IconOption[] = [
|
|
15
|
+
{
|
|
16
|
+
value: 'company',
|
|
17
|
+
label: 'company',
|
|
18
|
+
icon: BuildingOfficeIcon,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: 'government',
|
|
22
|
+
label: 'government',
|
|
23
|
+
icon: IconMingcuteGovernmentLine, // icon: mingcute:government-line
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: 'news',
|
|
27
|
+
label: 'news',
|
|
28
|
+
icon: IconStreamlineCyberNewspaper2, // icon: streamline-cyber:newspaper-2
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'forum',
|
|
32
|
+
label: 'forum',
|
|
33
|
+
icon: IconMdiForum, // icon: mdi:forum
|
|
34
|
+
},
|
|
35
|
+
]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { EventIcon} from './Event/Icon';
|
|
2
|
+
export { EventIconSelect } from './Event/Select';
|
|
3
|
+
export { OrganizationIcon } from './Organization/Icon';
|
|
4
|
+
export { OrganizationIconSelect } from './Organization/Select';
|
|
5
|
+
export { PersonIcon } from './Person/Icon';
|
|
6
|
+
export { PersonIconSelect } from './Person/Select';
|
|
7
|
+
export { SourceIcon } from './Source/Icon';
|
|
8
|
+
export { SourceIconSelect } from './Source/Select';
|
|
9
|
+
export { WebsiteIcon } from './Website/Icon';
|
|
10
|
+
export { WebsiteIconSelect } from './Website/Select';
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": {
|
|
3
|
+
"type": {
|
|
4
|
+
"news": "News",
|
|
5
|
+
"website": "Website",
|
|
6
|
+
"social-media": "Social Media",
|
|
7
|
+
"book": "Book",
|
|
8
|
+
"paper": "Paper"
|
|
9
|
+
},
|
|
10
|
+
"name": "Name",
|
|
11
|
+
"description": "Description"
|
|
12
|
+
},
|
|
13
|
+
"person": {
|
|
14
|
+
"type": {
|
|
15
|
+
"professional": "Professional",
|
|
16
|
+
"gov-official": "Government Official",
|
|
17
|
+
"school-personel": "School Personnel"
|
|
18
|
+
},
|
|
19
|
+
"name": "Name",
|
|
20
|
+
"role": "Role",
|
|
21
|
+
"aliases": "Aliases"
|
|
22
|
+
},
|
|
23
|
+
"organization": {
|
|
24
|
+
"type": {
|
|
25
|
+
"company": "Company",
|
|
26
|
+
"government": "Government",
|
|
27
|
+
"military": "Military",
|
|
28
|
+
"manufacturing": "Manufacturing",
|
|
29
|
+
"agriculture": "Agriculture",
|
|
30
|
+
"semi-conductor": "Semi-conductor",
|
|
31
|
+
"technology": "Technology"
|
|
32
|
+
},
|
|
33
|
+
"name": "Name"
|
|
34
|
+
},
|
|
35
|
+
"website": {
|
|
36
|
+
"type": {
|
|
37
|
+
"company": "Company",
|
|
38
|
+
"government": "Government",
|
|
39
|
+
"news": "News",
|
|
40
|
+
"forum": "Forum"
|
|
41
|
+
},
|
|
42
|
+
"title": "Title",
|
|
43
|
+
"description": "Description"
|
|
44
|
+
},
|
|
45
|
+
"event": {
|
|
46
|
+
"type": {
|
|
47
|
+
"announcement": "Announcement",
|
|
48
|
+
"conversation": "Conversation",
|
|
49
|
+
"exchange": "Exchange",
|
|
50
|
+
"oil": "Oil",
|
|
51
|
+
"trade": "Trade",
|
|
52
|
+
"supplychain-risk": "Supply Chain Risk",
|
|
53
|
+
"ship": "Ship",
|
|
54
|
+
"truck": "Truck",
|
|
55
|
+
"train": "Train",
|
|
56
|
+
"crime": "Crime",
|
|
57
|
+
"shot": "Shot",
|
|
58
|
+
"bomb": "Bomb",
|
|
59
|
+
"missile": "Missile",
|
|
60
|
+
"plane": "Plane",
|
|
61
|
+
"naval": "Naval",
|
|
62
|
+
"tank": "Tank",
|
|
63
|
+
"infantry": "Infantry",
|
|
64
|
+
"intelligence": "Intelligence"
|
|
65
|
+
},
|
|
66
|
+
"title": "Title",
|
|
67
|
+
"description": "Description"
|
|
68
|
+
},
|
|
69
|
+
"tooltip": {
|
|
70
|
+
"relation": "Related",
|
|
71
|
+
"confidence": "Confidence",
|
|
72
|
+
"createdDate": "Created Date",
|
|
73
|
+
"updatedDate": "Updated Date"
|
|
74
|
+
}
|
|
75
|
+
}
|