Skip to content

Commit

Permalink
#780 Enums in ontology editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Polleps committed Jan 17, 2024
1 parent 66ae8bd commit 123f095
Show file tree
Hide file tree
Showing 23 changed files with 627 additions and 224 deletions.
1 change: 1 addition & 0 deletions browser/data-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@emotion/is-prop-valid": "^1.2.1",
"@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-scroll-area": "^1.0.1",
"@radix-ui/react-tabs": "^1.0.4",
"@tomic/react": "workspace:*",
"emoji-mart": "^5.5.2",
"polished": "^4.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ const formatter = new Intl.ListFormat('en-GB', {
export function InlineFormattedResourceList({
subjects,
}: InlineFormattedResourceListProps): JSX.Element {
// There are rare cases where a resource array can locally have an undefined value, we filter these out to prevent the formatter from throwing an error.
const filteredSubjects = subjects.filter(subject => subject !== undefined);

return (
<>
{formatter.formatToParts(subjects).map(({ type, value }) => {
{formatter.formatToParts(filteredSubjects).map(({ type, value }) => {
if (type === 'literal') {
return value;
}
Expand Down
4 changes: 4 additions & 0 deletions browser/data-browser/src/components/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,8 @@ const Flex = styled.div<FlexProps>`
& ${ButtonDefault} {
align-self: flex-start;
}
& > p {
margin: 0;
}
`;
72 changes: 72 additions & 0 deletions browser/data-browser/src/components/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { FC, PropsWithChildren } from 'react';
import * as RadixTabs from '@radix-ui/react-tabs';
import { styled } from 'styled-components';
import { transition } from '../helpers/transition';

type TabItem = {
label: string;
value: string;
};

interface TabsProps {
tabs: TabItem[];
className?: string;
label: string;
}

export const Tabs: FC<PropsWithChildren<TabsProps>> = ({
children,
tabs,
label,
className,
}) => {
return (
<RadixTabs.Root defaultValue={tabs[0].value} className={className}>
<TabList aria-label={label}>
{tabs.map(tab => (
<TabButton key={tab.value} value={tab.value}>
{tab.label}
</TabButton>
))}
</TabList>
{children}
</RadixTabs.Root>
);
};

interface TabPanelProps {
value: string;
}

export const TabPanel: FC<PropsWithChildren<TabPanelProps>> = ({
value,
children,
}) => {
return <RadixTabs.Content value={value}>{children}</RadixTabs.Content>;
};

const TabList = styled(RadixTabs.List)`
display: flex;
justify-content: space-evenly;
margin-bottom: ${p => p.theme.margin}rem;
`;

const TabButton = styled(RadixTabs.Trigger)`
background: none;
border: none;
color: ${p => p.theme.colors.text};
border-bottom: 1px solid ${p => p.theme.colors.bg2};
padding: 1rem;
flex: 1;
${transition('background', 'border-bottom')}
cursor: pointer;
&:hover,
&:focus-visible {
outline: none;
background: ${p => p.theme.colors.bg1};
}
&[data-state='active'] {
border-bottom: 2px solid ${p => p.theme.colors.main};
}
`;
77 changes: 77 additions & 0 deletions browser/data-browser/src/components/Tag/CreateTagRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Resource, core, dataBrowser, useStore } from '@tomic/react';
import { useState, useCallback, Suspense, lazy } from 'react';
import { FaPlus } from 'react-icons/fa';
import { randomItem } from '../../helpers/randomItem';
import { randomString } from '../../helpers/randomString';
import { stringToSlug } from '../../helpers/stringToSlug';
import { Button } from '../Button';
import { Row } from '../Row';
import { InputWrapper, InputStyled } from '../forms/InputStyles';
import { tagColours } from './tagColours';

const EmojiInput = lazy(() => import('../../chunks/EmojiInput/EmojiInput'));

interface CreateTagRowProps {
parent: string;
onNewTag: (tag: Resource) => void;
}

export function CreateTagRow({ parent, onNewTag }: CreateTagRowProps) {
const store = useStore();
const [tagName, setTagName] = useState<string>('');
const [emoji, setEmoji] = useState<string | undefined>();
const [resetKey, setResetKey] = useState<number>(0);

const createNewTag = useCallback(async () => {
const tag = await store.newResource({
subject: `${parent}/${randomString()}`,
parent,
isA: dataBrowser.classes.tag,
propVals: {
[core.properties.shortname]: tagName,
[dataBrowser.properties.color]: randomItem(tagColours),
},
});

if (emoji) {
await tag.set(dataBrowser.properties.emoji, emoji, store);
}

onNewTag(tag);
setTagName('');
setEmoji(undefined);
setResetKey(prev => prev + 1);
}, [parent, store, tagName, emoji, onNewTag]);

const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setTagName(stringToSlug(e.target.value));
}, []);

const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
createNewTag();
}
},
[createNewTag],
);

return (
<Suspense fallback={<div>Loading...</div>}>
<Row>
<InputWrapper>
<EmojiInput onChange={setEmoji} key={resetKey} />
<InputStyled
placeholder='New tag'
value={tagName}
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
</InputWrapper>
<Button title='Add tag' onClick={createNewTag} disabled={!tagName}>
<FaPlus />
</Button>
</Row>
</Suspense>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,19 @@ import { lighten, setLightness, setSaturation } from 'polished';
import * as RadixPopover from '@radix-ui/react-popover';
import { useCallback, useMemo, useState } from 'react';
import { styled } from 'styled-components';
import { transition } from '../../../helpers/transition';
import { Popover } from '../../../components/Popover';
import { PalettePicker } from '../../../components/PalettePicker';
import { Button } from '../../../components/Button';
import { Column, Row } from '../../../components/Row';
import { transition } from '../../helpers/transition';
import { Popover } from '../Popover';
import { PalettePicker } from '../PalettePicker';
import { Button } from '../Button';
import { Column, Row } from '../Row';
import { FaTrash } from 'react-icons/fa';
import { fadeIn } from '../../../helpers/commonAnimations';
import { fadeIn } from '../../helpers/commonAnimations';
import { tagColours } from './tagColours';

interface TagProps {
subject: string;
}

export const tagColors = [
'#FFBE0B',
'#FB5607',
'#FF006E',
'#8338EC',
'#3A86FF',
'#5FF56E',
];

const useTagData = (subject: string) => {
const resource = useResource(subject);
const [title] = useTitle(resource);
Expand Down Expand Up @@ -74,11 +66,13 @@ const TagWrapper = styled.span<TagWrapperProps>`
padding-block: 0.4rem;
border-radius: 1em;
border: 1px solid var(--tag-mid-color);
color: var(--tag-dark-color);
color: ${p =>
p.theme.darkMode ? 'var(--tag-light-color)' : 'var(--tag-dark-color)'};
line-height: 1;
text-align: center;
min-width: 3rem;
background-color: var(--tag-light-color);
background-color: ${p =>
p.theme.darkMode ? 'var(--tag-dark-color)' : 'var(--tag-light-color)'};
&.selected-tag {
text-decoration: underline;
Expand Down Expand Up @@ -152,7 +146,7 @@ export function EditableTag({
>
<PopoverContent>
<Column>
<PalettePicker palette={tagColors} onChange={handleColorChange} />
<PalettePicker palette={tagColours} onChange={handleColorChange} />
<DeleteButton onClick={() => onDelete(subject)}>
<Row gap='0.5rem'>
<FaTrash />
Expand Down
2 changes: 2 additions & 0 deletions browser/data-browser/src/components/Tag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Tag';
export * from './CreateTagRow';
8 changes: 8 additions & 0 deletions browser/data-browser/src/components/Tag/tagColours.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const tagColours = [
'#FFBE0B',
'#FB5607',
'#FF006E',
'#8338EC',
'#3A86FF',
'#5FF56E',
];
17 changes: 9 additions & 8 deletions browser/data-browser/src/components/forms/AtomicSelectInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Resource, useValue } from '@tomic/react';

import { InputWrapper } from './InputStyles';
import { styled, css } from 'styled-components';
import { styled } from 'styled-components';

interface AtomicSelectInputProps {
resource: Resource;
Expand All @@ -11,6 +11,7 @@ interface AtomicSelectInputProps {
label: string;
}[];
commit?: boolean;
onChange?: (value: string) => void;
}

type Props = AtomicSelectInputProps &
Expand All @@ -21,12 +22,14 @@ export function AtomicSelectInput({
property,
options,
commit = false,
onChange,
...props
}: Props): JSX.Element {
const [value, setValue] = useValue(resource, property, { commit });

const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setValue(e.target.value);
onChange?.(e.target.value);
};

return (
Expand All @@ -51,20 +54,18 @@ const StyledInputWrapper = styled(InputWrapper)`
const SelectWrapper = styled.span<{ disabled: boolean }>`
width: 100%;
padding-inline: 0.2rem;
${p =>
p.disabled &&
css`
background-color: ${props => props.theme.colors.bg1};
`}
background-color: ${p =>
p.disabled ? p.theme.colors.bg1 : p.theme.colors.bg};
`;

const Select = styled.select`
cursor: pointer;
width: 100%;
border: none;
outline: none;
height: 2rem;
background-color: transparent;
color: ${p => p.theme.colors.text};
&:disabled {
color: ${props => props.theme.colors.textLight};
background-color: transparent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import { Column, Row } from '../Row';
import { styled } from 'styled-components';
import { useIndexDependantCallback } from '../../hooks/useIndexDependantCallback';

interface InputResourceArrayProps extends InputProps {
isA?: string;
}

export default function InputResourceArray({
resource,
property,
commit,
...props
}: InputProps): JSX.Element {
}: InputResourceArrayProps): JSX.Element {
const [err, setErr] = useState<ArrayError | undefined>(undefined);
const [array, setArray] = useArray(resource, property.subject, {
validate: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export function SearchBoxWindow({
...(isA ? { [core.properties.isA]: isA } : {}),
},
parents: scopes ?? [drive, 'https://atomicdata.dev'],
// If a classtype is given we want to prefill the searchbox with data.
allowEmptyQuery: !!isA,
}),
[isA, scopes],
);
Expand Down Expand Up @@ -188,16 +190,18 @@ export function SearchBoxWindow({
/>
</SearchInputWrapper>
<ResultBox data-testid='searchbox-results'>
{!searchValue && <CenteredMessage>Start Searching</CenteredMessage>}
{!searchValue && results.length === 0 && (
<CenteredMessage>Start Searching</CenteredMessage>
)}
<StyledScrollArea>
<ul>
{onCreateItem ? (
{onCreateItem && searchValue ? (
<ResultLine
selected={selectedIndex === 0}
onMouseOver={() => handleMouseMove(0)}
onClick={() => onCreateItem(searchValue)}
>
Create {searchValue}
Create <CreateLineInputText>{searchValue}</CreateLineInputText>
</ResultLine>
) : null}
{results.map((result, i) => (
Expand Down Expand Up @@ -238,6 +242,8 @@ const SearchInputWrapper = styled.div`
`;

const Input = styled.input`
background-color: transparent;
color: ${p => p.theme.colors.text};
padding: 0.5rem;
height: 100%;
flex: 1;
Expand Down Expand Up @@ -313,3 +319,8 @@ const StyledScrollArea = styled(ScrollArea)`
overflow: hidden;
height: 100%;
`;

const CreateLineInputText = styled.span`
color: ${p => p.theme.colors.textLight};
font-style: italic;
`;
6 changes: 6 additions & 0 deletions browser/data-browser/src/views/OntologyPage/LabelText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { styled } from 'styled-components';

export const LabelText = styled.span`
font-weight: bold;
color: ${p => p.theme.colors.textLight};
`;
Loading

0 comments on commit 123f095

Please sign in to comment.