mirror of
https://github.com/responsively-org/responsively-app
synced 2024-09-20 22:31:59 +00:00
Extracted VisionSimulationDropDown for reuse
This commit is contained in:
parent
101fb1b6e5
commit
45156abf07
2 changed files with 224 additions and 152 deletions
|
@ -2,12 +2,14 @@ import { Icon } from '@iconify/react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { DropDown } from 'renderer/components/DropDown';
|
import { DropDown } from 'renderer/components/DropDown';
|
||||||
|
import {
|
||||||
const redgreen = ['Deuteranopia', 'Deuteranomaly', 'Protanopia', 'Protanomaly'];
|
BLUE_YELLOW,
|
||||||
const blueyellow = ['Tritanopia', 'Tritanomaly'];
|
FULL,
|
||||||
const full = ['Achromatomaly', 'Achromatopsia'];
|
RED_GREEN,
|
||||||
const visualimpairments = ['Cataract', 'Farsightedness', 'Glaucome'];
|
SUNLIGHT,
|
||||||
const sunlight = ['Solarize'];
|
VISUAL_IMPAIRMENTS,
|
||||||
|
VisionSimulationDropDown,
|
||||||
|
} from 'renderer/components/VisionSimulationDropDown';
|
||||||
|
|
||||||
interface InjectedCss {
|
interface InjectedCss {
|
||||||
key: string;
|
key: string;
|
||||||
|
@ -20,45 +22,6 @@ interface Props {
|
||||||
webview: Electron.WebviewTag | null;
|
webview: Electron.WebviewTag | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuItemLabel = ({
|
|
||||||
label,
|
|
||||||
isActive,
|
|
||||||
}: {
|
|
||||||
label: string;
|
|
||||||
isActive: boolean;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div className="justify-normal flex w-full flex-shrink-0 items-center gap-1 whitespace-nowrap">
|
|
||||||
<Icon
|
|
||||||
icon="ic:round-check"
|
|
||||||
className={cx('opacity-0', {
|
|
||||||
'opacity-100': isActive,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className={cx({
|
|
||||||
'font-semibold text-black dark:text-white': isActive,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const MenuItemHeader = ({ label }: { label: string }) => {
|
|
||||||
return (
|
|
||||||
<div className="relative flex w-full min-w-44 items-center justify-between gap-1 whitespace-nowrap">
|
|
||||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
|
||||||
<div className="w-full border-t border-gray-300 dark:border-gray-600" />
|
|
||||||
</div>
|
|
||||||
<span className="mxl-1 z-10 flex-shrink-0 bg-slate-100 pr-2 dark:bg-slate-900">
|
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ColorBlindnessTools = ({ webview }: Props) => {
|
export const ColorBlindnessTools = ({ webview }: Props) => {
|
||||||
const [injectCss, setInjectCss] = useState<InjectedCss>();
|
const [injectCss, setInjectCss] = useState<InjectedCss>();
|
||||||
|
|
||||||
|
@ -217,114 +180,30 @@ export const ColorBlindnessTools = ({ webview }: Props) => {
|
||||||
return applyCss(visualImpairment, css, js);
|
return applyCss(visualImpairment, css, js);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const applySimulation = async (simulation = '') => {
|
||||||
|
if (
|
||||||
|
RED_GREEN.indexOf(simulation) !== -1 ||
|
||||||
|
BLUE_YELLOW.indexOf(simulation) !== -1 ||
|
||||||
|
FULL.indexOf(simulation) !== -1
|
||||||
|
) {
|
||||||
|
return applyColorDeficiency(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VISUAL_IMPAIRMENTS.indexOf(simulation) !== -1) {
|
||||||
|
return applyVisualImpairment(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUNLIGHT.indexOf(simulation) !== -1) {
|
||||||
|
return applySunlight(simulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clearSimulation();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropDown
|
<VisionSimulationDropDown
|
||||||
className={cx('rounded-lg text-xs', {
|
simulationName={injectCss?.name}
|
||||||
'bg-slate-400/60': injectCss?.name != null,
|
onChange={applySimulation}
|
||||||
})}
|
|
||||||
label={<Icon icon="bx:low-vision" fontSize={18} />}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="No deficiency" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label="Normal Vision"
|
|
||||||
isActive={injectCss?.name == null}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
clearSimulation();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="Red-green deficiency" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
...redgreen.map((x: string) => {
|
|
||||||
return {
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label={x}
|
|
||||||
isActive={injectCss?.name === x.toLowerCase()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
applyColorDeficiency(x.toLowerCase());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="Blue-yellow deficiency" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
...blueyellow.map((x: string) => {
|
|
||||||
return {
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label={x}
|
|
||||||
isActive={injectCss?.name === x.toLowerCase()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
applyColorDeficiency(x.toLowerCase());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="Full color deficiency" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
...full.map((x: string) => {
|
|
||||||
return {
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label={x}
|
|
||||||
isActive={injectCss?.name === x.toLowerCase()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
applyColorDeficiency(x.toLowerCase());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="Visual impairment" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
...visualimpairments.map((x: string) => {
|
|
||||||
return {
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label={x}
|
|
||||||
isActive={injectCss?.name === x.toLowerCase()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
applyVisualImpairment(x.toLowerCase());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
label: <MenuItemHeader label="Temporary impairment" />,
|
|
||||||
onClick: null,
|
|
||||||
},
|
|
||||||
...sunlight.map((x: string) => {
|
|
||||||
return {
|
|
||||||
label: (
|
|
||||||
<MenuItemLabel
|
|
||||||
label={x}
|
|
||||||
isActive={injectCss?.name === x.toLowerCase()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
onClick: () => {
|
|
||||||
applySunlight(x.toLowerCase());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
import cx from 'classnames';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import { DropDown } from '../DropDown';
|
||||||
|
|
||||||
|
const MenuItemLabel = ({
|
||||||
|
label,
|
||||||
|
isActive,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="justify-normal flex w-full flex-shrink-0 items-center gap-1 whitespace-nowrap">
|
||||||
|
<Icon
|
||||||
|
icon="ic:round-check"
|
||||||
|
className={cx('opacity-0', {
|
||||||
|
'opacity-100': isActive,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={cx({
|
||||||
|
'font-semibold text-black dark:text-white': isActive,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MenuItemHeader = ({ label }: { label: string }) => {
|
||||||
|
return (
|
||||||
|
<div className="relative flex w-full min-w-44 items-center justify-between gap-1 whitespace-nowrap">
|
||||||
|
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||||
|
<div className="w-full border-t border-gray-300 dark:border-gray-600" />
|
||||||
|
</div>
|
||||||
|
<span className="mxl-1 z-10 flex-shrink-0 bg-slate-100 pr-2 dark:bg-slate-900">
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SIMULATIONS = {
|
||||||
|
DEUTERANOPIA: 'deuteranopia',
|
||||||
|
DEUTERANOMALY: 'deuteranomaly',
|
||||||
|
PROTANOPIA: 'protanopia',
|
||||||
|
PROTANOMALY: 'protanomaly',
|
||||||
|
TRITANOPIA: 'tritanopia',
|
||||||
|
TRITANOMALY: 'tritanomaly',
|
||||||
|
ACHROMATOMALY: 'achromatomaly',
|
||||||
|
ACHROMATOPSIA: 'achromatopsia',
|
||||||
|
CATARACT: 'cataract',
|
||||||
|
FAR: 'farsightedness',
|
||||||
|
GLAUCOME: 'glaucoma',
|
||||||
|
SOLARIZE: 'solarize',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RED_GREEN = [
|
||||||
|
SIMULATIONS.DEUTERANOPIA,
|
||||||
|
SIMULATIONS.DEUTERANOMALY,
|
||||||
|
SIMULATIONS.PROTANOPIA,
|
||||||
|
SIMULATIONS.PROTANOMALY,
|
||||||
|
];
|
||||||
|
export const BLUE_YELLOW = [SIMULATIONS.TRITANOPIA, SIMULATIONS.TRITANOMALY];
|
||||||
|
export const FULL = [SIMULATIONS.ACHROMATOMALY, SIMULATIONS.ACHROMATOPSIA];
|
||||||
|
export const VISUAL_IMPAIRMENTS = [
|
||||||
|
SIMULATIONS.CATARACT,
|
||||||
|
SIMULATIONS.FAR,
|
||||||
|
SIMULATIONS.GLAUCOME,
|
||||||
|
];
|
||||||
|
export const SUNLIGHT = [SIMULATIONS.SOLARIZE];
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
simulationName: string | undefined;
|
||||||
|
onChange: (name: string | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VisionSimulationDropDown = ({
|
||||||
|
simulationName,
|
||||||
|
onChange,
|
||||||
|
}: Props) => {
|
||||||
|
return (
|
||||||
|
<DropDown
|
||||||
|
className={cx('rounded-lg text-xs', {
|
||||||
|
'bg-slate-400/60': simulationName != null,
|
||||||
|
})}
|
||||||
|
label={<Icon icon="bx:low-vision" fontSize={18} />}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="No deficiency" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label="Normal Vision"
|
||||||
|
isActive={simulationName === undefined}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(undefined);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="Red-green deficiency" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
...RED_GREEN.map((x: string) => {
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label={x}
|
||||||
|
isActive={simulationName === x.toLowerCase()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(x.toLowerCase());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="Blue-yellow deficiency" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
...BLUE_YELLOW.map((x: string) => {
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label={x}
|
||||||
|
isActive={simulationName === x.toLowerCase()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(x.toLowerCase());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="Full color deficiency" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
...FULL.map((x: string) => {
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label={x}
|
||||||
|
isActive={simulationName === x.toLowerCase()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(x.toLowerCase());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="Visual impairment" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
...VISUAL_IMPAIRMENTS.map((x: string) => {
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label={x}
|
||||||
|
isActive={simulationName === x.toLowerCase()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(x.toLowerCase());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
label: <MenuItemHeader label="Temporary impairment" />,
|
||||||
|
onClick: null,
|
||||||
|
},
|
||||||
|
...SUNLIGHT.map((x: string) => {
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<MenuItemLabel
|
||||||
|
label={x}
|
||||||
|
isActive={simulationName === x.toLowerCase()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onClick: () => {
|
||||||
|
onChange(x.toLowerCase());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in a new issue