mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-06-16 09:39:09 +00:00
chore: update prettier tab width for consistency (#175)
This commit is contained in:
parent
a931f8c69c
commit
f24d2fcc99
247 changed files with 7224 additions and 7375 deletions
|
@ -4,10 +4,10 @@ import { roleCategory } from '../../fixtures/storyData';
|
|||
import { Role } from './Role';
|
||||
|
||||
it('fires an OnClick handler when clicked', () => {
|
||||
const onClickMock = jest.fn();
|
||||
const view = shallow(
|
||||
<Role role={roleCategory[0]} selected={true} onClick={onClickMock} />
|
||||
);
|
||||
view.simulate('click');
|
||||
expect(onClickMock).toBeCalledWith(false);
|
||||
const onClickMock = jest.fn();
|
||||
const view = shallow(
|
||||
<Role role={roleCategory[0]} selected={true} onClick={onClickMock} />
|
||||
);
|
||||
view.simulate('click');
|
||||
expect(onClickMock).toBeCalledWith(false);
|
||||
});
|
||||
|
|
|
@ -5,75 +5,65 @@ import { roleCategory } from '../../fixtures/storyData';
|
|||
import { Role as RoleComponent } from './Role';
|
||||
|
||||
export default {
|
||||
title: 'Atoms/Role',
|
||||
component: RoleComponent,
|
||||
decorators: [withColors],
|
||||
title: 'Atoms/Role',
|
||||
component: RoleComponent,
|
||||
decorators: [withColors],
|
||||
};
|
||||
|
||||
const Demo = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
`;
|
||||
|
||||
const RoleWithState = (props: any) => {
|
||||
const [selected, updateSelected] = React.useState(false);
|
||||
return (
|
||||
<div style={{ padding: 5 }}>
|
||||
<RoleComponent
|
||||
{...props}
|
||||
selected={selected}
|
||||
onClick={(next) => updateSelected(next)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
const [selected, updateSelected] = React.useState(false);
|
||||
return (
|
||||
<div style={{ padding: 5 }}>
|
||||
<RoleComponent
|
||||
{...props}
|
||||
selected={selected}
|
||||
onClick={(next) => updateSelected(next)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Role = () => (
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleWithState key={idx} role={c} />
|
||||
))}
|
||||
</Demo>
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleWithState key={idx} role={c} />
|
||||
))}
|
||||
</Demo>
|
||||
);
|
||||
|
||||
export const Selected = () => (
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={c} selected={true} />
|
||||
))}
|
||||
</Demo>
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={c} selected={true} />
|
||||
))}
|
||||
</Demo>
|
||||
);
|
||||
|
||||
export const Unselected = () => (
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={c} selected={false} />
|
||||
))}
|
||||
</Demo>
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={c} selected={false} />
|
||||
))}
|
||||
</Demo>
|
||||
);
|
||||
|
||||
export const DisabledByPosition = () => (
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent
|
||||
key={idx}
|
||||
role={{ ...c, safety: 1 }}
|
||||
selected={false}
|
||||
disabled
|
||||
/>
|
||||
))}
|
||||
</Demo>
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={{ ...c, safety: 1 }} selected={false} disabled />
|
||||
))}
|
||||
</Demo>
|
||||
);
|
||||
|
||||
export const DisabledByDanger = () => (
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent
|
||||
key={idx}
|
||||
role={{ ...c, safety: 2 }}
|
||||
selected={false}
|
||||
disabled
|
||||
/>
|
||||
))}
|
||||
</Demo>
|
||||
<Demo>
|
||||
{roleCategory.map((c, idx) => (
|
||||
<RoleComponent key={idx} role={{ ...c, safety: 2 }} selected={false} disabled />
|
||||
))}
|
||||
</Demo>
|
||||
);
|
||||
|
|
|
@ -3,80 +3,80 @@ import { transitions } from '@roleypoly/design-system/atoms/timings';
|
|||
import styled, { css } from 'styled-components';
|
||||
|
||||
export type StyledProps = {
|
||||
selected: boolean;
|
||||
defaultColor: boolean;
|
||||
disabled: boolean;
|
||||
type?: 'delete';
|
||||
selected: boolean;
|
||||
defaultColor: boolean;
|
||||
disabled: boolean;
|
||||
type?: 'delete';
|
||||
};
|
||||
|
||||
export const Circle = styled.div<StyledProps>`
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 25px;
|
||||
background-color: ${(props) =>
|
||||
props.defaultColor && !props.selected ? 'transparent' : 'var(--role-color)'};
|
||||
border: 1px solid
|
||||
${(props) =>
|
||||
props.defaultColor
|
||||
? 'var(--role-color)'
|
||||
: props.selected
|
||||
? 'var(--role-accent)'
|
||||
: 'transparent'};
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: border ${transitions.in2in}s ease-in-out,
|
||||
background-color ${transitions.in2in}s ease-in-out;
|
||||
flex-shrink: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 25px;
|
||||
background-color: ${(props) =>
|
||||
props.defaultColor && !props.selected ? 'transparent' : 'var(--role-color)'};
|
||||
border: 1px solid
|
||||
${(props) =>
|
||||
props.defaultColor
|
||||
? 'var(--role-color)'
|
||||
: props.selected
|
||||
? 'var(--role-accent)'
|
||||
: 'transparent'};
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: border ${transitions.in2in}s ease-in-out,
|
||||
background-color ${transitions.in2in}s ease-in-out;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
fill-opacity: ${(props) => (props.selected || props.disabled ? 1 : 0)};
|
||||
transition: fill-opacity ${transitions.in2in}s ease-in-out;
|
||||
fill: ${(props) =>
|
||||
props.disabled && props.defaultColor
|
||||
? 'var(--role-color)'
|
||||
: 'var(--role-contrast)'};
|
||||
}
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
fill-opacity: ${(props) => (props.selected || props.disabled ? 1 : 0)};
|
||||
transition: fill-opacity ${transitions.in2in}s ease-in-out;
|
||||
fill: ${(props) =>
|
||||
props.disabled && props.defaultColor
|
||||
? 'var(--role-color)'
|
||||
: 'var(--role-contrast)'};
|
||||
}
|
||||
`;
|
||||
|
||||
export const Outer = styled.div<StyledProps>`
|
||||
border-radius: 24px;
|
||||
background-color: ${(props) =>
|
||||
props.selected && !props.defaultColor ? 'var(--role-color)' : palette.taupe100};
|
||||
color: ${(props) => (props.selected ? 'var(--role-contrast)' : palette.grey600)};
|
||||
transition: color ${transitions.in2in}s ease-in-out,
|
||||
background-color ${transitions.in2in}s ease-in-out,
|
||||
transform ${transitions.actionable}s ease-in-out,
|
||||
box-shadow ${transitions.actionable}s ease-in-out;
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
${(props) =>
|
||||
!props.disabled
|
||||
? css`
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
${Circle} svg {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
}
|
||||
border-radius: 24px;
|
||||
background-color: ${(props) =>
|
||||
props.selected && !props.defaultColor ? 'var(--role-color)' : palette.taupe100};
|
||||
color: ${(props) => (props.selected ? 'var(--role-contrast)' : palette.grey600)};
|
||||
transition: color ${transitions.in2in}s ease-in-out,
|
||||
background-color ${transitions.in2in}s ease-in-out,
|
||||
transform ${transitions.actionable}s ease-in-out,
|
||||
box-shadow ${transitions.actionable}s ease-in-out;
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
${(props) =>
|
||||
!props.disabled
|
||||
? css`
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
${Circle} svg {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 0 0 transparent;
|
||||
}
|
||||
`
|
||||
: null};
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 0 0 transparent;
|
||||
}
|
||||
`
|
||||
: null};
|
||||
`;
|
||||
|
||||
export const Text = styled.div`
|
||||
padding: 0 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 0 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
|
|
@ -7,94 +7,94 @@ import { FaCheck, FaTimes } from 'react-icons/fa';
|
|||
import * as styled from './Role.styled';
|
||||
|
||||
type Props = {
|
||||
role: RPCRole;
|
||||
selected: boolean;
|
||||
disabled?: boolean;
|
||||
onClick?: (newState: boolean) => void;
|
||||
tooltipId?: string;
|
||||
type?: 'delete';
|
||||
role: RPCRole;
|
||||
selected: boolean;
|
||||
disabled?: boolean;
|
||||
onClick?: (newState: boolean) => void;
|
||||
tooltipId?: string;
|
||||
type?: 'delete';
|
||||
};
|
||||
|
||||
const getColorsFromBase = (baseColor: chroma.Color, contrastCheckThrow: number = 5) => {
|
||||
// Which has more contrast? Stepping up or stepping down?
|
||||
const contrastColorUp = baseColor.brighten(contrastCheckThrow);
|
||||
const contrastColorDown = baseColor.darken(contrastCheckThrow);
|
||||
// Which has more contrast? Stepping up or stepping down?
|
||||
const contrastColorUp = baseColor.brighten(contrastCheckThrow);
|
||||
const contrastColorDown = baseColor.darken(contrastCheckThrow);
|
||||
|
||||
if (
|
||||
chroma.contrast(baseColor, contrastColorUp) >
|
||||
chroma.contrast(baseColor, contrastColorDown)
|
||||
) {
|
||||
return {
|
||||
contrastColor: baseColor.brighten(3),
|
||||
accentColor: baseColor.brighten(2),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
contrastColor: baseColor.darken(3),
|
||||
accentColor: baseColor.darken(2),
|
||||
};
|
||||
}
|
||||
if (
|
||||
chroma.contrast(baseColor, contrastColorUp) >
|
||||
chroma.contrast(baseColor, contrastColorDown)
|
||||
) {
|
||||
return {
|
||||
contrastColor: baseColor.brighten(3),
|
||||
accentColor: baseColor.brighten(2),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
contrastColor: baseColor.darken(3),
|
||||
accentColor: baseColor.darken(2),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const Role = (props: Props) => {
|
||||
const colorVars = {
|
||||
'--role-color': 'white',
|
||||
'--role-contrast': 'hsl(0,0,0%)',
|
||||
'--role-accent': 'hsl(0,0,70%)',
|
||||
};
|
||||
const colorVars = {
|
||||
'--role-color': 'white',
|
||||
'--role-contrast': 'hsl(0,0,0%)',
|
||||
'--role-accent': 'hsl(0,0,70%)',
|
||||
};
|
||||
|
||||
if (props.role.color !== 0) {
|
||||
const baseColor = numberToChroma(props.role.color);
|
||||
const { accentColor, contrastColor } = getColorsFromBase(baseColor, 5);
|
||||
colorVars['--role-color'] = baseColor.css();
|
||||
colorVars['--role-accent'] = accentColor.css();
|
||||
colorVars['--role-contrast'] = contrastColor.css();
|
||||
}
|
||||
if (props.role.color !== 0) {
|
||||
const baseColor = numberToChroma(props.role.color);
|
||||
const { accentColor, contrastColor } = getColorsFromBase(baseColor, 5);
|
||||
colorVars['--role-color'] = baseColor.css();
|
||||
colorVars['--role-accent'] = accentColor.css();
|
||||
colorVars['--role-contrast'] = contrastColor.css();
|
||||
}
|
||||
|
||||
const styledProps: styled.StyledProps = {
|
||||
selected: props.selected,
|
||||
defaultColor: props.role.color === 0,
|
||||
disabled: !!props.disabled,
|
||||
type: props.type,
|
||||
};
|
||||
const styledProps: styled.StyledProps = {
|
||||
selected: props.selected,
|
||||
defaultColor: props.role.color === 0,
|
||||
disabled: !!props.disabled,
|
||||
type: props.type,
|
||||
};
|
||||
|
||||
const extra = !props.disabled
|
||||
? {}
|
||||
: {
|
||||
'data-tip': disabledReason(props.role),
|
||||
'data-for': props.tooltipId,
|
||||
};
|
||||
const extra = !props.disabled
|
||||
? {}
|
||||
: {
|
||||
'data-tip': disabledReason(props.role),
|
||||
'data-for': props.tooltipId,
|
||||
};
|
||||
|
||||
return (
|
||||
<styled.Outer
|
||||
{...styledProps}
|
||||
style={colorVars as any}
|
||||
onClick={() => !props.disabled && props.onClick?.(!props.selected)}
|
||||
{...extra}
|
||||
>
|
||||
<styled.Circle {...styledProps}>
|
||||
{!props.disabled && props.type !== 'delete' ? <FaCheck /> : <FaTimes />}
|
||||
</styled.Circle>
|
||||
<styled.Text>{props.role.name}</styled.Text>
|
||||
</styled.Outer>
|
||||
);
|
||||
return (
|
||||
<styled.Outer
|
||||
{...styledProps}
|
||||
style={colorVars as any}
|
||||
onClick={() => !props.disabled && props.onClick?.(!props.selected)}
|
||||
{...extra}
|
||||
>
|
||||
<styled.Circle {...styledProps}>
|
||||
{!props.disabled && props.type !== 'delete' ? <FaCheck /> : <FaTimes />}
|
||||
</styled.Circle>
|
||||
<styled.Text>{props.role.name}</styled.Text>
|
||||
</styled.Outer>
|
||||
);
|
||||
};
|
||||
|
||||
const disabledReason = (role: RPCRole) => {
|
||||
switch (role.safety) {
|
||||
case RoleSafety.HigherThanBot:
|
||||
return `This role is above Roleypoly's own role.`;
|
||||
case RoleSafety.DangerousPermissions:
|
||||
const rolePermissions = BigInt(role.permissions);
|
||||
let permissionHits: string[] = [];
|
||||
switch (role.safety) {
|
||||
case RoleSafety.HigherThanBot:
|
||||
return `This role is above Roleypoly's own role.`;
|
||||
case RoleSafety.DangerousPermissions:
|
||||
const rolePermissions = BigInt(role.permissions);
|
||||
let permissionHits: string[] = [];
|
||||
|
||||
evaluatePermission(rolePermissions, permissions.ADMINISTRATOR) &&
|
||||
permissionHits.push('Administrator');
|
||||
evaluatePermission(rolePermissions, permissions.MANAGE_ROLES) &&
|
||||
permissionHits.push('Manage Roles');
|
||||
evaluatePermission(rolePermissions, permissions.ADMINISTRATOR) &&
|
||||
permissionHits.push('Administrator');
|
||||
evaluatePermission(rolePermissions, permissions.MANAGE_ROLES) &&
|
||||
permissionHits.push('Manage Roles');
|
||||
|
||||
return `This role has unsafe permissions: ${permissionHits.join(', ')}`;
|
||||
default:
|
||||
return `This role is disabled.`;
|
||||
}
|
||||
return `This role has unsafe permissions: ${permissionHits.join(', ')}`;
|
||||
default:
|
||||
return `This role is disabled.`;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue