Skip to content
This repository has been archived by the owner on Mar 23, 2022. It is now read-only.

Commit

Permalink
ADD - Affliction icon besides text (#231)
Browse files Browse the repository at this point in the history
Signed-off-by: RaenonX <[email protected]>
  • Loading branch information
RaenonX committed Aug 6, 2021
1 parent 5c92bd6 commit c273ae6
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 5 deletions.
101 changes: 100 additions & 1 deletion src/components/elements/markdown/main.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import userEvent from '@testing-library/user-event';

import {renderReact} from '../../../../test/render/main';
import {SupportedLanguages, UnitType} from '../../../api-def/api';
import {DepotPaths, SimpleUnitInfo} from '../../../api-def/resources';
import {DepotPaths, SimpleUnitInfo, StatusEnums} from '../../../api-def/resources';
import {Markdown} from './main';
import {makeAfflictionIconMarkdown} from './transformers/text/icon/utils';


describe('Markdown', () => {
Expand Down Expand Up @@ -314,4 +315,102 @@ describe('Markdown', () => {
expect(await screen.findByText('Analysis')).toBeInTheDocument();
});
});

describe('Markdown - Affliction Icon', () => {
const status: StatusEnums['status'] = [
{
name: 'POISON',
code: 1,
imagePath: 'poison.png',
trans: {
[SupportedLanguages.CHT]: 'Poison CHT',
[SupportedLanguages.EN]: 'Poison',
[SupportedLanguages.JP]: 'Poison JP',
},
},
];

it('shows affliction icon in sentence', async () => {
const markdown = 'Afflicts poison';

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getByText(/Poison/)).toBeInTheDocument();
expect(screen.getByText('', {selector: 'img'})).toHaveAttribute('src', DepotPaths.getImageURL('poison.png'));
});

it('does not show multiple affliction icons for one if already exists', async () => {
const markdown = `${makeAfflictionIconMarkdown(status[0])} poison`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getAllByText(/poison/).length).toBe(1);
expect(screen.getAllByText('', {selector: 'img'}).length).toBe(1);
});

it('shows multiple affliction icons for different afflictions', async () => {
const markdown = `Afflicts poison, also afflicts poison`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getAllByText('', {selector: 'img'}).length).toBe(2);
});

it('shows affliction icon in table cell', async () => {
const markdown = `head | col 2\n:---: | :---:\nX | poison`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getByText(/Poison/)).toBeInTheDocument();
expect(screen.getByText('', {selector: 'img'})).toHaveAttribute('src', DepotPaths.getImageURL('poison.png'));
});

it('shows affliction icon in <strong> text', async () => {
const markdown = `**Afflicts poison**.`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getByText(/Poison/)).toBeInTheDocument();
expect(screen.getByText('', {selector: 'img'})).toHaveAttribute('src', DepotPaths.getImageURL('poison.png'));
});

it('shows affliction icon in heading', async () => {
const markdown = `### Afflicts poison`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getByText(/Poison/)).toBeInTheDocument();
expect(screen.getByText('', {selector: 'img'})).toHaveAttribute('src', DepotPaths.getImageURL('poison.png'));
});

it('shows affliction icon in colored text', async () => {
const markdown = `::[green] Afflicts poison::`;

renderReact(
() => <Markdown>{markdown}</Markdown>,
{resources: {afflictions: {status}}},
);

expect(screen.getByText(/Poison/)).toBeInTheDocument();
expect(screen.getByText('', {selector: 'img'})).toHaveAttribute('src', DepotPaths.getImageURL('poison.png'));
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const IDENTIFIER_SEPARATOR = '|';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
img {
&.afflictionIcon {
margin: 0 0.2rem;
}
}
42 changes: 42 additions & 0 deletions src/components/elements/markdown/transformers/text/icon/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';

import {DepotPaths} from '../../../../../../api-def/resources';
import {AppReactContext} from '../../../../../../context/app/main';
import {useI18n} from '../../../../../../i18n/hook';
import {Image} from '../../../../common/image';
import {TextComponentProps} from '../types';
import {IDENTIFIER_SEPARATOR} from './const';
import styles from './main.module.css';
import {IconType} from './types';


export const Icon = ({children}: TextComponentProps) => {
const {lang} = useI18n();
const context = React.useContext(AppReactContext);

const [type, identifier] = children.split(IDENTIFIER_SEPARATOR, 2);

if (type === IconType.AFFLICTION && context?.resources.afflictions.status.length) {
const statusEnum = context?.resources.afflictions.status.find((entry) => entry.name === identifier);

if (!statusEnum) {
// Identifier invalid / not found
return <>{children}</>;
}

if (!statusEnum.imagePath) {
// No image to show
return <></>;
}

return (
<Image
text={statusEnum.trans[lang]}
src={DepotPaths.getImageURL(statusEnum.imagePath)}
className={styles.afflictionIcon}
/>
);
}

return <>{children}</>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const IconType = {
AFFLICTION: 'aff',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {EnumEntry} from '../../../../../../api-def/resources';
import {iconSyntax} from '../syntax';
import {IDENTIFIER_SEPARATOR} from './const';
import {IconType} from './types';


export const makeAfflictionIconMarkdown = (affliction: EnumEntry) => {
return `${iconSyntax.start}${IconType.AFFLICTION}${IDENTIFIER_SEPARATOR}${affliction.name}${iconSyntax.end}`;
};
15 changes: 14 additions & 1 deletion src/components/elements/markdown/transformers/text/main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React from 'react';

import {AppReactContext} from '../../../../../context/app/main';
import {useI18n} from '../../../../../i18n/hook';
import {syntaxCollection} from './syntax';
import {TextComponentProps} from './types';
import {injectMarkdownToText} from './utils';


export const Text = ({children}: TextComponentProps) => {
Expand Down Expand Up @@ -44,6 +47,9 @@ type TextChildrenProps = {
}

export const TextChildren = ({children}: TextChildrenProps) => {
const {lang} = useI18n();
const context = React.useContext(AppReactContext);

if (!children) {
return <></>;
}
Expand All @@ -53,7 +59,14 @@ export const TextChildren = ({children}: TextChildrenProps) => {
{
children.map((child, idx) => {
if (typeof child === 'string') {
return <Text key={idx}>{child}</Text>;
const injected = injectMarkdownToText(
lang, child,
{
afflictions: context?.resources.afflictions.status || [],
},
);

return <Text key={idx}>{injected}</Text>;
}

return <React.Fragment key={idx}>{child}</React.Fragment>;
Expand Down
8 changes: 8 additions & 0 deletions src/components/elements/markdown/transformers/text/syntax.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import {CalcExpression} from '../math/main';
import {ColoredText} from './color';
import {EnlargedTextLevel2, EnlargedTextLevel3} from './enlarge';
import {Icon} from './icon/main';
import {Syntax} from './types';
import {MarkdownUnitName} from './unit';


export const iconSyntax: Syntax = {
start: '{',
end: '}',
Component: Icon,
};

const colorSyntax: Syntax = {
start: '::',
end: '::',
Expand Down Expand Up @@ -37,6 +44,7 @@ const enlargeLv2Syntax: Syntax = {

// NOTE: Order matters!
export const syntaxCollection = [
iconSyntax,
colorSyntax,
calcSyntax,
unitSyntax,
Expand Down
72 changes: 72 additions & 0 deletions src/components/elements/markdown/transformers/text/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {expect} from '@jest/globals';

import {SupportedLanguages} from '../../../../../api-def/api';
import {StatusEnums} from '../../../../../api-def/resources';
import {makeAfflictionIconMarkdown} from './icon/utils';
import {injectMarkdownToText} from './utils';


describe('Text injection', () => {
const afflictions: StatusEnums['status'] = [
{
name: 'POISON',
code: 1,
imagePath: 'poison.png',
trans: {
[SupportedLanguages.CHT]: 'Poison CHT',
[SupportedLanguages.EN]: 'Poison',
[SupportedLanguages.JP]: 'Poison JP',
},
},
];

it('does not inject anything', async () => {
const injected = injectMarkdownToText(SupportedLanguages.EN, 'Text', {afflictions});

expect(injected).toBe('Text');
});

it('injects affliction icon before affliction text', async () => {
const injected = injectMarkdownToText(SupportedLanguages.EN, 'Poison', {afflictions});

expect(injected).toBe(`${makeAfflictionIconMarkdown(afflictions[0])}Poison`);
});

it('injects affliction icon in a sentence', async () => {
const injected = injectMarkdownToText(SupportedLanguages.EN, 'Afflicts Poison', {afflictions});

expect(injected).toBe(`Afflicts ${makeAfflictionIconMarkdown(afflictions[0])}Poison`);
});

it('injects affliction icon in a continuous word', async () => {
const injected = injectMarkdownToText(SupportedLanguages.EN, 'ApplyPoison', {afflictions});

expect(injected).toBe(`Apply${makeAfflictionIconMarkdown(afflictions[0])}Poison`);
});

it('injects affliction icon case-insensitively', async () => {
const injected = injectMarkdownToText(SupportedLanguages.EN, 'Afflicts poison', {afflictions});

expect(injected).toBe(`Afflicts ${makeAfflictionIconMarkdown(afflictions[0])}Poison`);
});

it('does not inject affliction icon if already exists', async () => {
const injected = injectMarkdownToText(
SupportedLanguages.EN,
`${makeAfflictionIconMarkdown(afflictions[0])}Poison`,
{afflictions},
);

expect(injected).toBe(`${makeAfflictionIconMarkdown(afflictions[0])}Poison`);
});

it('does not inject affliction icon if already exists (precedes with space)', async () => {
const injected = injectMarkdownToText(
SupportedLanguages.EN,
`${makeAfflictionIconMarkdown(afflictions[0])} Poison`,
{afflictions},
);

expect(injected).toBe(`${makeAfflictionIconMarkdown(afflictions[0])} Poison`);
});
});
24 changes: 24 additions & 0 deletions src/components/elements/markdown/transformers/text/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {SupportedLanguages} from '../../../../../api-def/api';
import {StatusEnums} from '../../../../../api-def/resources';
import {IDENTIFIER_SEPARATOR} from './icon/const';
import {makeAfflictionIconMarkdown} from './icon/utils';
import {iconSyntax} from './syntax';


type Resources = {
afflictions?: StatusEnums['status'],
}

export const injectMarkdownToText = (lang: SupportedLanguages, text: string, resources: Resources): string => {
// Affliction icons
if (resources.afflictions?.length) {
resources.afflictions.forEach((entry) => {
text = text.replace(
new RegExp(`(^|([^${iconSyntax.end}${IDENTIFIER_SEPARATOR} ]) ?)${entry.trans[lang]}`, 'gi'),
`$1${makeAfflictionIconMarkdown(entry)}${entry.trans[lang]}`,
);
});
}

return text;
};
4 changes: 1 addition & 3 deletions test/render/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ const RenderWrapper = ({store, options, children}: React.PropsWithChildren<Wrapp
params: options?.contextParams || {},
resources: overrideObject(
{
afflictions: {
status: [] as Array<EnumEntry>,
},
afflictions: {status: [] as Array<EnumEntry>},
simpleUnitInfo: {},
},
options?.resources,
Expand Down

0 comments on commit c273ae6

Please sign in to comment.