chore: prettier

This commit is contained in:
41666 2020-10-10 04:33:54 -04:00
parent ccf89d8480
commit 70fa51d4a1
67 changed files with 1811 additions and 1838 deletions

View file

@ -1,17 +1,17 @@
# DB
Roleypoly's DB schemas, connectors, and other useful database admin tools.
Roleypoly's DB schemas, connectors, and other useful database admin tools.
## Tools
### ent
ent schema and the files it generates.
ent schema and the files it generates.
Edit nothing outside of the `schemas` folder, as all others are generated.
When done editing, do `go generate ./ent` to update generation.
*Failing to generate files will make CI fail.*
_Failing to generate files will make CI fail._
All schemas must be backwards compatible with previous versions of this library, and be compatible with **CockroachDB**-based Postgres.
All schemas must be backwards compatible with previous versions of this library, and be compatible with **CockroachDB**-based Postgres.

View file

@ -1,30 +1,30 @@
import { text } from "@storybook/addon-knobs";
import * as React from "react";
import { Avatar } from "./Avatar";
import { text } from '@storybook/addon-knobs';
import * as React from 'react';
import { Avatar } from './Avatar';
export default {
title: "Atoms/Avatar",
component: Avatar,
argTypes: {
initials: { control: "text" },
},
args: {
initials: "KR",
},
title: 'Atoms/Avatar',
component: Avatar,
argTypes: {
initials: { control: 'text' },
},
args: {
initials: 'KR',
},
};
export const WithInitials = ({ initials, ...rest }) => (
<Avatar src="https://i.imgur.com/epMSRQH.png" size={48} {...rest}>
{initials}
</Avatar>
<Avatar src="https://i.imgur.com/epMSRQH.png" size={48} {...rest}>
{initials}
</Avatar>
);
export const WithText = ({ initials, ...rest }) => (
<Avatar size={48} {...rest}>
{initials}
</Avatar>
<Avatar size={48} {...rest}>
{initials}
</Avatar>
);
export const Empty = (args) => <Avatar size={48} {...args}></Avatar>;
export const DeliberatelyEmpty = (args) => (
<Avatar size={48} deliberatelyEmpty={true} {...args}></Avatar>
<Avatar size={48} deliberatelyEmpty={true} {...args}></Avatar>
);

View file

@ -1,46 +1,45 @@
import { AvatarProps } from "./Avatar";
import styled, { css } from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import { palette } from "roleypoly/src/design-system/atoms/colors";
import { AvatarProps } from './Avatar';
import styled, { css } from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
import { palette } from 'roleypoly/src/design-system/atoms/colors';
type ContainerProps = Pick<AvatarProps, "size"> &
Pick<AvatarProps, "deliberatelyEmpty">;
type ContainerProps = Pick<AvatarProps, 'size'> & Pick<AvatarProps, 'deliberatelyEmpty'>;
export const Container = styled.div<ContainerProps>`
border-radius: 100%;
box-sizing: border-box;
width: ${(props: ContainerProps) => props.size || 48}px;
height: ${(props: ContainerProps) => props.size || 48}px;
min-width: ${(props: ContainerProps) => props.size || 48}px;
min-height: ${(props: ContainerProps) => props.size || 48}px;
display: flex;
justify-content: center;
align-items: center;
color: ${palette.grey100};
position: relative;
background-color: ${palette.grey500};
font-weight: bold;
text-align: center;
line-height: 1;
overflow: hidden;
font-size: ${(props: ContainerProps) => props.size};
${(props) =>
props.deliberatelyEmpty &&
css`
border: 4px solid rgba(0, 0, 0, 0.25);
background-color: ${palette.taupe400};
color: ${palette.taupe600};
`}
border-radius: 100%;
box-sizing: border-box;
width: ${(props: ContainerProps) => props.size || 48}px;
height: ${(props: ContainerProps) => props.size || 48}px;
min-width: ${(props: ContainerProps) => props.size || 48}px;
min-height: ${(props: ContainerProps) => props.size || 48}px;
display: flex;
justify-content: center;
align-items: center;
color: ${palette.grey100};
position: relative;
background-color: ${palette.grey500};
font-weight: bold;
text-align: center;
line-height: 1;
overflow: hidden;
font-size: ${(props: ContainerProps) => props.size};
${(props) =>
props.deliberatelyEmpty &&
css`
border: 4px solid rgba(0, 0, 0, 0.25);
background-color: ${palette.taupe400};
color: ${palette.taupe600};
`}
`;
type ImageProps = Pick<AvatarProps, "src">;
type ImageProps = Pick<AvatarProps, 'src'>;
export const Image = styled.div<ImageProps>`
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
border-radius: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
border-radius: 100%;
`;

View file

@ -1,27 +1,24 @@
import * as React from "react";
import {
Logomark as BrandingLogomark,
Logotype as BrandingLogotype,
} from "./Branding";
import styled from "styled-components";
import * as React from 'react';
import { Logomark as BrandingLogomark, Logotype as BrandingLogotype } from './Branding';
import styled from 'styled-components';
export default {
title: "Atoms/Branding",
title: 'Atoms/Branding',
};
const Wrapper = styled.div`
background-color: black;
padding: 2em;
background-color: black;
padding: 2em;
`;
export const Logomark = () => (
<Wrapper>
<BrandingLogomark />
</Wrapper>
<Wrapper>
<BrandingLogomark />
</Wrapper>
);
export const Logotype = () => (
<Wrapper>
<BrandingLogotype />
</Wrapper>
<Wrapper>
<BrandingLogotype />
</Wrapper>
);

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,11 @@
import * as React from "react";
import { BreakpointDebugTool } from "./DebugTool";
import { BreakpointsProvider } from "./BreakpointProvider";
import * as React from 'react';
import { BreakpointDebugTool } from './DebugTool';
import { BreakpointsProvider } from './BreakpointProvider';
export default {
title: "Atoms/Breakpoints",
decorators: [(story) => <BreakpointsProvider>{story()}</BreakpointsProvider>],
component: BreakpointDebugTool,
title: 'Atoms/Breakpoints',
decorators: [(story) => <BreakpointsProvider>{story()}</BreakpointsProvider>],
component: BreakpointDebugTool,
};
export const DebugTool = () => <BreakpointDebugTool />;

View file

@ -1,22 +1,22 @@
import * as React from "react";
import { withContext } from "roleypoly/src/common/utils/withContext";
import * as React from 'react';
import { withContext } from 'roleypoly/src/common/utils/withContext';
export type ScreenSize = {
onSmallScreen: boolean;
onTablet: boolean;
onDesktop: boolean;
onSmallScreen: boolean;
onTablet: boolean;
onDesktop: boolean;
};
export type BreakpointProps = {
screenSize: ScreenSize;
screenSize: ScreenSize;
};
const defaultScreenSize: BreakpointProps = {
screenSize: {
onSmallScreen: true,
onDesktop: false,
onTablet: false,
},
screenSize: {
onSmallScreen: true,
onDesktop: false,
onTablet: false,
},
};
export const BreakpointContext = React.createContext(defaultScreenSize);
@ -24,4 +24,4 @@ export const BreakpointContext = React.createContext(defaultScreenSize);
export const useBreakpointContext = () => React.useContext(BreakpointContext);
export const withBreakpoints = <T>(Component: React.ComponentType<T>) =>
withContext(BreakpointContext, Component as any);
withContext(BreakpointContext, Component as any);

View file

@ -1,83 +1,83 @@
// TODO: port to new story
import * as React from "react";
import { atomStories } from "atoms/atoms.story";
import { Button, ButtonProps } from "./Button";
import { text as textKnob } from "@storybook/addon-knobs";
import { FaDiscord } from "react-icons/fa";
import { styled } from "@storybook/theming";
import * as React from 'react';
import { atomStories } from 'atoms/atoms.story';
import { Button, ButtonProps } from './Button';
import { text as textKnob } from '@storybook/addon-knobs';
import { FaDiscord } from 'react-icons/fa';
import { styled } from '@storybook/theming';
const largeStory = atomStories("Button/Large", module);
const smallStory = atomStories("Button/Small", module);
const largeStory = atomStories('Button/Large', module);
const smallStory = atomStories('Button/Small', module);
const colorModes: NonNullable<ButtonProps["color"]>[] = [
"primary",
"secondary",
"discord",
"muted",
const colorModes: NonNullable<ButtonProps['color']>[] = [
'primary',
'secondary',
'discord',
'muted',
];
const Margin = styled.div`
margin-top: 5px;
display: flex;
align-items: center;
margin-top: 5px;
display: flex;
align-items: center;
`;
const storyTemplate = (props: Omit<ButtonProps, "children">) => () => {
const text = textKnob("Button content", "Example Button");
const storyTemplate = (props: Omit<ButtonProps, 'children'>) => () => {
const text = textKnob('Button content', 'Example Button');
return (
<div>
{colorModes.map((color, i) => (
<Margin key={i}>
<Button {...props} color={color}>
{text}
</Button>
<div style={{ marginLeft: "1em" }}>
{color[0].toUpperCase()}
{color.slice(1)}
</div>
</Margin>
))}
</div>
);
return (
<div>
{colorModes.map((color, i) => (
<Margin key={i}>
<Button {...props} color={color}>
{text}
</Button>
<div style={{ marginLeft: '1em' }}>
{color[0].toUpperCase()}
{color.slice(1)}
</div>
</Margin>
))}
</div>
);
};
const storyBuilder = (
story: typeof largeStory,
size: NonNullable<ButtonProps["size"]>
story: typeof largeStory,
size: NonNullable<ButtonProps['size']>
) => {
story.add(
"Normal",
storyTemplate({
size,
})
);
story.add(
'Normal',
storyTemplate({
size,
})
);
story.add(
"Icon",
storyTemplate({
size,
icon: (
<div style={{ position: "relative", top: 3 }}>
<FaDiscord />
</div>
),
})
);
story.add(
'Icon',
storyTemplate({
size,
icon: (
<div style={{ position: 'relative', top: 3 }}>
<FaDiscord />
</div>
),
})
);
story.add(
"Loading",
storyTemplate({
size,
icon: (
<div style={{ position: "relative", top: 3 }}>
<FaDiscord />
</div>
),
loading: true,
})
);
story.add(
'Loading',
storyTemplate({
size,
icon: (
<div style={{ position: 'relative', top: 3 }}>
<FaDiscord />
</div>
),
loading: true,
})
);
};
storyBuilder(largeStory, "large");
storyBuilder(smallStory, "small");
storyBuilder(largeStory, 'large');
storyBuilder(smallStory, 'small');

View file

@ -1,106 +1,106 @@
import styled, { css } from "styled-components";
import { text400, text300 } from "roleypoly/src/design-system/atoms/typography";
import { fontCSS } from "roleypoly/src/design-system/atoms/fonts";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled, { css } from 'styled-components';
import { text400, text300 } from 'roleypoly/src/design-system/atoms/typography';
import { fontCSS } from 'roleypoly/src/design-system/atoms/fonts';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export const IconContainer = styled.div`
margin-right: 0.6rem;
font-size: 1.75em;
margin-right: 0.6rem;
font-size: 1.75em;
`;
const base = css`
${fontCSS}
appearance: none;
display: block;
background-color: ${palette.taupe300};
color: ${palette.grey500};
border-radius: 3px;
border: 2px solid rgba(0, 0, 0, 0.55);
transition: all 0.15s ease-in-out;
outline: 0;
position: relative;
user-select: none;
cursor: pointer;
white-space: nowrap;
::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
opacity: 0;
${fontCSS}
appearance: none;
display: block;
background-color: ${palette.taupe300};
color: ${palette.grey500};
border-radius: 3px;
border: 2px solid rgba(0, 0, 0, 0.55);
transition: all 0.15s ease-in-out;
}
outline: 0;
position: relative;
user-select: none;
cursor: pointer;
white-space: nowrap;
:hover {
transform: translateY(-1px);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
:active {
transform: translateY(1px);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.25);
::after {
opacity: 0.1;
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
opacity: 0;
transition: all 0.15s ease-in-out;
}
:hover {
transform: translateY(-1px);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
:active {
transform: translateY(1px);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.25);
::after {
opacity: 0.1;
}
}
}
`;
const colors = {
primary: css`
background-color: ${palette.green400};
color: ${palette.taupe100};
`,
secondary: css``,
discord: css`
background-color: ${palette.discord400};
border: 2px solid ${palette.discord200};
`,
muted: css`
border: 2px solid rgba(0, 0, 0, 0.15);
background: none;
:hover {
background-color: ${palette.taupe200};
}
`,
primary: css`
background-color: ${palette.green400};
color: ${palette.taupe100};
`,
secondary: css``,
discord: css`
background-color: ${palette.discord400};
border: 2px solid ${palette.discord200};
`,
muted: css`
border: 2px solid rgba(0, 0, 0, 0.15);
background: none;
:hover {
background-color: ${palette.taupe200};
}
`,
};
const sizes = {
small: css`
${text300}
padding: 4px 8px;
`,
large: css`
${text400}
padding: 12px 32px;
width: 100%;
`,
small: css`
${text300}
padding: 4px 8px;
`,
large: css`
${text400}
padding: 12px 32px;
width: 100%;
`,
};
const modifiers = {
withIcon: css`
display: flex;
align-items: center;
justify-content: center;
`,
withLoading: css`
pointer-events: none;
`,
withIcon: css`
display: flex;
align-items: center;
justify-content: center;
`,
withLoading: css`
pointer-events: none;
`,
};
export type ButtonComposerOptions = {
size: keyof typeof sizes;
color: keyof typeof colors;
modifiers?: Array<keyof typeof modifiers>;
size: keyof typeof sizes;
color: keyof typeof colors;
modifiers?: Array<keyof typeof modifiers>;
};
export const Button = styled.button<ButtonComposerOptions>`
${base}
${(props) => props.size in sizes && sizes[props.size]}
${base}
${(props) => props.size in sizes && sizes[props.size]}
${(props) => props.color in colors && colors[props.color]}
${(props) => props.modifiers?.map((m) => modifiers[m])}
`;

View file

@ -1,164 +1,162 @@
import * as React from "react";
import { palette } from "./colors";
import styled from "styled-components";
import chroma from "chroma-js";
import { AmbientSmall } from "roleypoly/src/design-system/atoms/typography";
import * as React from 'react';
import { palette } from './colors';
import styled from 'styled-components';
import chroma from 'chroma-js';
import { AmbientSmall } from 'roleypoly/src/design-system/atoms/typography';
type RatioList = {
color1: string[];
color2: string[];
ratio: string;
color1: string[];
color2: string[];
ratio: string;
};
export default {
title: "Atoms/Colors",
title: 'Atoms/Colors',
};
const Swatch = styled.div`
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
width: 250px;
height: 100px;
margin: 10px;
display: inline-block;
background-color: #fff;
border: 1px solid #fff;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
width: 250px;
height: 100px;
margin: 10px;
display: inline-block;
background-color: #fff;
border: 1px solid #fff;
`;
const SwatchColor = styled.div`
height: 72px;
height: 72px;
`;
const Label = styled.div`
font-size: 12px;
display: flex;
justify-content: space-between;
padding: 6px;
color: ${palette.taupe100};
p {
margin: 0;
}
font-size: 12px;
display: flex;
justify-content: space-between;
padding: 6px;
color: ${palette.taupe100};
p {
margin: 0;
}
`;
export const Colors = () => {
return (
<div>
{Object.entries(palette).map(([name, color], i) => (
<Swatch key={i}>
<SwatchColor style={{ backgroundColor: color }} />
<Label>
<p>{name}</p>
<p>
<code>var(--{name})</code>
</p>
</Label>
</Swatch>
))}
</div>
);
return (
<div>
{Object.entries(palette).map(([name, color], i) => (
<Swatch key={i}>
<SwatchColor style={{ backgroundColor: color }} />
<Label>
<p>{name}</p>
<p>
<code>var(--{name})</code>
</p>
</Label>
</Swatch>
))}
</div>
);
};
export const ContrastRatios = () => {
const allRatios = getAllRatios(palette);
const allRatios = getAllRatios(palette);
return (
<div>
<p>
<b>WCAG Contrast Calculations.</b>
<br />
Marked in <span style={getWCAGStyle(7.1)}>Green</span> is 7.0+ or AAA.
Acceptable for Text.
<br />
Marked in <span style={getWCAGStyle(4.6)}>Orange</span> is 4.5+ or AA.
Acceptable for UI.
<br />
All below 4.5 is unacceptable.
<br />
<AmbientSmall>
WCAG Contrast testing disabled for this page.
</AmbientSmall>
</p>
<ContrastTable>
<thead>
<tr>
<th colSpan={2}>Swatch</th>
<th>Ratio</th>
<th>Color 1</th>
<th>Color 2</th>
</tr>
</thead>
<tbody>
{allRatios.map((ratio, i) => (
<tr key={i}>
<td style={{ backgroundColor: ratio.color1[1] }}>&nbsp;</td>
<td style={{ backgroundColor: ratio.color2[1] }}>&nbsp;</td>
<td style={getWCAGStyle(+ratio.ratio)}>{ratio.ratio}</td>
<td>{ratio.color1[0]}</td>
<td>{ratio.color2[0]}</td>
<td
style={{
color: ratio.color1[1],
backgroundColor: ratio.color2[1],
paddingRight: "0.1em",
}}
>
oh my god my
</td>
<td
style={{
color: ratio.color2[1],
backgroundColor: ratio.color1[1],
paddingLeft: "0.1em",
}}
>
shin how dare you
</td>
</tr>
))}
</tbody>
</ContrastTable>
</div>
);
return (
<div>
<p>
<b>WCAG Contrast Calculations.</b>
<br />
Marked in <span style={getWCAGStyle(7.1)}>Green</span> is 7.0+ or AAA.
Acceptable for Text.
<br />
Marked in <span style={getWCAGStyle(4.6)}>Orange</span> is 4.5+ or AA.
Acceptable for UI.
<br />
All below 4.5 is unacceptable.
<br />
<AmbientSmall>WCAG Contrast testing disabled for this page.</AmbientSmall>
</p>
<ContrastTable>
<thead>
<tr>
<th colSpan={2}>Swatch</th>
<th>Ratio</th>
<th>Color 1</th>
<th>Color 2</th>
</tr>
</thead>
<tbody>
{allRatios.map((ratio, i) => (
<tr key={i}>
<td style={{ backgroundColor: ratio.color1[1] }}>&nbsp;</td>
<td style={{ backgroundColor: ratio.color2[1] }}>&nbsp;</td>
<td style={getWCAGStyle(+ratio.ratio)}>{ratio.ratio}</td>
<td>{ratio.color1[0]}</td>
<td>{ratio.color2[0]}</td>
<td
style={{
color: ratio.color1[1],
backgroundColor: ratio.color2[1],
paddingRight: '0.1em',
}}
>
oh my god my
</td>
<td
style={{
color: ratio.color2[1],
backgroundColor: ratio.color1[1],
paddingLeft: '0.1em',
}}
>
shin how dare you
</td>
</tr>
))}
</tbody>
</ContrastTable>
</div>
);
};
const ContrastTable = styled.table`
td,
th {
padding: 6px 10px;
}
td,
th {
padding: 6px 10px;
}
`;
const getWCAGStyle = (ratio: number): React.CSSProperties => {
if (ratio >= 7) {
return { color: "green", fontWeight: "bold" };
}
if (ratio >= 7) {
return { color: 'green', fontWeight: 'bold' };
}
if (ratio >= 4.5) {
return { color: "orange", fontWeight: "bold" };
}
if (ratio >= 4.5) {
return { color: 'orange', fontWeight: 'bold' };
}
return {};
return {};
};
const getAllRatios = (input: typeof palette) =>
Object.entries(input)
.filter(([name]) => !name.startsWith("discord"))
.reduce((acc, [name, color]) => {
return [
...acc,
...Object.entries(palette)
.filter(([name]) => !name.startsWith("discord"))
.map(([matchName, matchColor]) => ({
color1: [name, color],
color2: [matchName, matchColor],
ratio: chroma.contrast(color, matchColor).toFixed(2),
})),
];
}, [] as RatioList[])
.filter(({ ratio }) => +ratio !== 1)
.sort((a, b) => {
if (+a.ratio > +b.ratio) {
return -1;
}
return 1;
})
.filter((_, i) => i % 2 === 0);
Object.entries(input)
.filter(([name]) => !name.startsWith('discord'))
.reduce((acc, [name, color]) => {
return [
...acc,
...Object.entries(palette)
.filter(([name]) => !name.startsWith('discord'))
.map(([matchName, matchColor]) => ({
color1: [name, color],
color2: [matchName, matchColor],
ratio: chroma.contrast(color, matchColor).toFixed(2),
})),
];
}, [] as RatioList[])
.filter(({ ratio }) => +ratio !== 1)
.sort((a, b) => {
if (+a.ratio > +b.ratio) {
return -1;
}
return 1;
})
.filter((_, i) => i % 2 === 0);

View file

@ -1,36 +1,36 @@
import { css, createGlobalStyle } from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import chroma from "chroma-js";
import { css, createGlobalStyle } from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
import chroma from 'chroma-js';
export const palette = {
taupe100: "#332D2D",
taupe200: "#453E3D",
taupe300: "#5D5352",
taupe400: "#756867",
taupe500: "#AB9B9A",
taupe600: "#EBD6D4",
taupe100: '#332D2D',
taupe200: '#453E3D',
taupe300: '#5D5352',
taupe400: '#756867',
taupe500: '#AB9B9A',
taupe600: '#EBD6D4',
discord100: "#23272A",
discord200: "#2C2F33",
discord400: "#7289DA",
discord500: "#99AAB5",
discord100: '#23272A',
discord200: '#2C2F33',
discord400: '#7289DA',
discord500: '#99AAB5',
green400: "#46B646",
green400: '#46B646',
red400: "#E95353",
red400: '#E95353',
gold400: "#EFCF24",
gold400: '#EFCF24',
grey100: "#1C1010",
grey500: "#DBD9D9",
grey600: "#F2EFEF",
grey100: '#1C1010',
grey500: '#DBD9D9',
grey600: '#F2EFEF',
};
const getPaletteCSS = () =>
Object.entries(palette).reduce(
(acc, [key, color]) => ({ ...acc, [`--${key}`]: color }),
{}
);
Object.entries(palette).reduce(
(acc, [key, color]) => ({ ...acc, [`--${key}`]: color }),
{}
);
export const colorVars = css(getPaletteCSS());
@ -41,5 +41,5 @@ export const GlobalStyleColors = createGlobalStyle`
`;
export const numberToChroma = (colorInt: number) => {
return chroma(colorInt);
return chroma(colorInt);
};

View file

@ -1,2 +1,2 @@
export * from "./colors";
export * as utils from "./withColors";
export * from './colors';
export * as utils from './withColors';

View file

@ -1,8 +1,8 @@
import * as React from "react";
import { DotOverlay } from "./DotOverlay";
import * as React from 'react';
import { DotOverlay } from './DotOverlay';
export default {
title: "Atoms/Dot Overlay",
title: 'Atoms/Dot Overlay',
};
export const Dark = () => <DotOverlay />;

View file

@ -1,39 +1,39 @@
import styled from "styled-components";
import * as React from "react";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled from 'styled-components';
import * as React from 'react';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
const dotOverlayBase = styled.div`
opacity: 0.6;
pointer-events: none;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: -10;
background-size: 27px 27px;
opacity: 0.6;
pointer-events: none;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: -10;
background-size: 27px 27px;
`;
const DotOverlayDark = styled(dotOverlayBase)`
background-image: radial-gradient(
circle,
#332d2d,
#332d2d 1px,
transparent 1px,
transparent
);
background-image: radial-gradient(
circle,
#332d2d,
#332d2d 1px,
transparent 1px,
transparent
);
`;
const DotOverlayLight = styled(dotOverlayBase)`
background-image: radial-gradient(
circle,
#dbd9d9,
#dbd9d9 1px,
transparent 1px,
transparent
);
background-image: radial-gradient(
circle,
#dbd9d9,
#dbd9d9 1px,
transparent 1px,
transparent
);
`;
export const DotOverlay = ({ light }: { light?: boolean }) => {
return light ? <DotOverlayLight /> : <DotOverlayDark />;
return light ? <DotOverlayLight /> : <DotOverlayDark />;
};

View file

@ -1,28 +1,28 @@
import * as React from "react";
import { FaderOpacity, FaderSlide } from "./Fader";
import { Button } from "roleypoly/src/design-system/atoms/button";
import { action } from "@storybook/addon-actions";
import * as React from 'react';
import { FaderOpacity, FaderSlide } from './Fader';
import { Button } from 'roleypoly/src/design-system/atoms/button';
import { action } from '@storybook/addon-actions';
export default {
title: "Atoms/Fader",
component: FaderSlide,
args: {
isVisible: true,
},
title: 'Atoms/Fader',
component: FaderSlide,
args: {
isVisible: true,
},
};
export const Opacity = (args) => {
return (
<FaderOpacity {...args}>
<Button onClick={action("onClick")}>Click me!</Button>
</FaderOpacity>
);
return (
<FaderOpacity {...args}>
<Button onClick={action('onClick')}>Click me!</Button>
</FaderOpacity>
);
};
export const Slide = (args) => {
return (
<FaderSlide {...args}>
<Button onClick={action("onClick")}>Click me!</Button>
</FaderSlide>
);
return (
<FaderSlide {...args}>
<Button onClick={action('onClick')}>Click me!</Button>
</FaderSlide>
);
};

View file

@ -1,38 +1,36 @@
import * as React from "react";
import styled from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import * as React from 'react';
import styled from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export type FaderProps = {
isVisible: boolean;
children: React.ReactNode;
isVisible: boolean;
children: React.ReactNode;
};
const FaderOpacityStyled = styled.div<Pick<FaderProps, "isVisible">>`
opacity: ${(props) => (props.isVisible ? 1 : 0)};
pointer-events: ${(props) => (props.isVisible ? "unset" : "none")};
transition: opacity 0.35s ease-in-out;
const FaderOpacityStyled = styled.div<Pick<FaderProps, 'isVisible'>>`
opacity: ${(props) => (props.isVisible ? 1 : 0)};
pointer-events: ${(props) => (props.isVisible ? 'unset' : 'none')};
transition: opacity 0.35s ease-in-out;
`;
export const FaderOpacity = (props: FaderProps) => {
return (
<FaderOpacityStyled isVisible={props.isVisible}>
{props.children}
</FaderOpacityStyled>
);
return (
<FaderOpacityStyled isVisible={props.isVisible}>
{props.children}
</FaderOpacityStyled>
);
};
const FaderSlideStyled = styled.div<Pick<FaderProps, "isVisible">>`
max-height: ${(props) => (props.isVisible ? "4em" : "0")};
pointer-events: ${(props) => (props.isVisible ? "unset" : "none")};
transition: max-height 0.35s ease-in-out;
overflow: hidden;
transform: translateZ(0);
const FaderSlideStyled = styled.div<Pick<FaderProps, 'isVisible'>>`
max-height: ${(props) => (props.isVisible ? '4em' : '0')};
pointer-events: ${(props) => (props.isVisible ? 'unset' : 'none')};
transition: max-height 0.35s ease-in-out;
overflow: hidden;
transform: translateZ(0);
`;
export const FaderSlide = (props: FaderProps) => {
return (
<FaderSlideStyled isVisible={props.isVisible}>
{props.children}
</FaderSlideStyled>
);
return (
<FaderSlideStyled isVisible={props.isVisible}>{props.children}</FaderSlideStyled>
);
};

View file

@ -1,66 +1,62 @@
import * as React from "react";
import { UseFontStyled } from "./fonts";
import styled from "styled-components";
import * as React from 'react';
import { UseFontStyled } from './fonts';
import styled from 'styled-components';
import {
MediumTitle,
Text as TextBlock,
} from "roleypoly/src/design-system/atoms/typography";
MediumTitle,
Text as TextBlock,
} from 'roleypoly/src/design-system/atoms/typography';
const resetFont = (storyFn: () => React.ReactNode) => (
<FontReset>{storyFn()}</FontReset>
);
const resetFont = (storyFn: () => React.ReactNode) => <FontReset>{storyFn()}</FontReset>;
export default {
title: "Atoms/Fonts",
decorators: [resetFont],
title: 'Atoms/Fonts',
decorators: [resetFont],
};
const FontReset = styled.div`
font-family: sans-serif;
font-family: sans-serif;
`;
const CorrectlyFontedH2 = (props: { children: React.ReactNode }) => (
<UseFontStyled>
<MediumTitle>{props.children}</MediumTitle>
</UseFontStyled>
<UseFontStyled>
<MediumTitle>{props.children}</MediumTitle>
</UseFontStyled>
);
const Text = () => (
<>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et facilis alias
placeat cumque sapiente ad delectus omnis quae. Reiciendis quibusdam
deserunt repellat. Exercitationem modi incidunt autem nemo tempore eaque
soluta.
</p>
<p>
4312.
6.
6.
</p>
<p>
🔸🐕🔺💱🎊👽🐛 👨📼🕦📞 👱👆🍗👚🌈 🔝🔟🍉🔰🍲🏁🕗 🎡🐉🍲📻🔢🔄
💟💲🍻💜💩🔼 🎱🌸📛👫🌻 🗽🕜🐥👕🍈. 🐒🍚🔓📱🏦 🎦🌑🔛💙👣🔚 🔆🗻🌿🎳📲🍯
🌞💟🎌🍌 🔪📯🐎💮 👌👭🎋🏉🏰 📓🕃🎂💉🔩 🐟🌇👺🌊🌒 📪👅🍂🍁 🌖🐮🔽🌒📊.
🔤🍍🌸📷🎴 💏🍌📎👥👉👒 👝💜🔶🍣 💨🗼👈💉💉💰 🍐🕖🌰👝🕓🏊🐕 🏀📅📼📒
🐕🌈👋
</p>
</>
<>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et facilis alias
placeat cumque sapiente ad delectus omnis quae. Reiciendis quibusdam deserunt
repellat. Exercitationem modi incidunt autem nemo tempore eaque soluta.
</p>
<p>
4312.
6.
6.
</p>
<p>
🔸🐕🔺💱🎊👽🐛 👨📼🕦📞 👱👆🍗👚🌈 🔝🔟🍉🔰🍲🏁🕗 🎡🐉🍲📻🔢🔄 💟💲🍻💜💩🔼
🎱🌸📛👫🌻 🗽🕜🐥👕🍈. 🐒🍚🔓📱🏦 🎦🌑🔛💙👣🔚 🔆🗻🌿🎳📲🍯 🌞💟🎌🍌 🔪📯🐎💮
👌👭🎋🏉🏰 📓🕃🎂💉🔩 🐟🌇👺🌊🌒 📪👅🍂🍁 🌖🐮🔽🌒📊. 🔤🍍🌸📷🎴 💏🍌📎👥👉👒
👝💜🔶🍣 💨🗼👈💉💉💰 🍐🕖🌰👝🕓🏊🐕 🏀📅📼📒 🐕🌈👋
</p>
</>
);
export const Fonts = () => (
<TextBlock>
<section>
<CorrectlyFontedH2>Unstyled Default</CorrectlyFontedH2>
<Text />
</section>
<section>
<CorrectlyFontedH2>
Main (Source Han Sans Japanese, Source Sans)
</CorrectlyFontedH2>
<UseFontStyled>
<Text />
</UseFontStyled>
</section>
</TextBlock>
<TextBlock>
<section>
<CorrectlyFontedH2>Unstyled Default</CorrectlyFontedH2>
<Text />
</section>
<section>
<CorrectlyFontedH2>
Main (Source Han Sans Japanese, Source Sans)
</CorrectlyFontedH2>
<UseFontStyled>
<Text />
</UseFontStyled>
</section>
</TextBlock>
);

View file

@ -1,30 +1,30 @@
import * as React from "react";
import Head from "next/head";
import styled, { css } from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import * as React from 'react';
import Head from 'next/head';
import styled, { css } from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export const InjectTypekitFont = () => {
React.useEffect(() => {
(window as any).Typekit.load();
}, []);
return (
<Head>
<link
key="typekit-css-preload"
rel="preload"
href="https://use.typekit.net/bck0pci.js"
as="script"
/>
<script key="typekit-js" src="https://use.typekit.net/bck0pci.js" />
</Head>
);
React.useEffect(() => {
(window as any).Typekit.load();
}, []);
return (
<Head>
<link
key="typekit-css-preload"
rel="preload"
href="https://use.typekit.net/bck0pci.js"
as="script"
/>
<script key="typekit-js" src="https://use.typekit.net/bck0pci.js" />
</Head>
);
};
export const fontCSS = css`
font-family: "source-han-sans-japanese", "Source Sans Pro", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
font-family: 'source-han-sans-japanese', 'Source Sans Pro', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !important;
`;
export const UseFontStyled = styled.div`
${fontCSS}
${fontCSS}
`;

View file

@ -1,13 +1,13 @@
import * as React from "react";
import { HalfsiesContainer, HalfsiesItem } from "./Halfsies";
import * as React from 'react';
import { HalfsiesContainer, HalfsiesItem } from './Halfsies';
export default {
title: "Atoms/Halfsies",
title: 'Atoms/Halfsies',
};
export const Container = () => (
<HalfsiesContainer>
<HalfsiesItem>Lefty doo</HalfsiesItem>
<HalfsiesItem>Righty doo</HalfsiesItem>
</HalfsiesContainer>
<HalfsiesContainer>
<HalfsiesItem>Lefty doo</HalfsiesItem>
<HalfsiesItem>Righty doo</HalfsiesItem>
</HalfsiesContainer>
);

View file

@ -1,18 +1,18 @@
import styled, { css } from "styled-components";
import { onTablet } from "roleypoly/src/design-system/atoms/breakpoints";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled, { css } from 'styled-components';
import { onTablet } from 'roleypoly/src/design-system/atoms/breakpoints';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export const HalfsiesContainer = styled.div`
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
`;
export const HalfsiesItem = styled.div`
box-sizing: border-box;
flex: 1 1 100%;
${onTablet(css`
flex: 1 2 50%;
`)}
box-sizing: border-box;
flex: 1 1 100%;
${onTablet(css`
flex: 1 2 50%;
`)}
`;

View file

@ -1,74 +1,70 @@
import * as React from "react";
import { Hero as HeroComponent } from "./Hero";
import * as React from 'react';
import { Hero as HeroComponent } from './Hero';
export default {
title: "Atoms/Hero",
component: HeroComponent,
args: {
topSpacing: 75,
bottomSpacing: 25,
},
title: 'Atoms/Hero',
component: HeroComponent,
args: {
topSpacing: 75,
bottomSpacing: 25,
},
};
export const Hero = ({ topSpacing, bottomSpacing }) => {
return (
<StoryWrapper topSpacing={topSpacing} bottomSpacing={bottomSpacing}>
<HeroComponent topSpacing={topSpacing} bottomSpacing={bottomSpacing}>
<h1>This is it.</h1>
</HeroComponent>
</StoryWrapper>
);
return (
<StoryWrapper topSpacing={topSpacing} bottomSpacing={bottomSpacing}>
<HeroComponent topSpacing={topSpacing} bottomSpacing={bottomSpacing}>
<h1>This is it.</h1>
</HeroComponent>
</StoryWrapper>
);
};
type WrapperProps = {
children: React.ReactNode;
topSpacing: number;
bottomSpacing: number;
children: React.ReactNode;
topSpacing: number;
bottomSpacing: number;
};
const StoryWrapper = ({
topSpacing,
bottomSpacing,
...props
}: WrapperProps) => (
<div>
<div
style={{
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
height: "100vh",
}}
>
<div
style={{
height: topSpacing,
backgroundColor: "rgba(255,0,0,0.25)",
top: 0,
left: 0,
right: 0,
position: "absolute",
overflow: "hidden",
}}
>
topSpacing
</div>
<div
style={{
height: bottomSpacing,
backgroundColor: "rgba(0,0,255,0.25)",
bottom: 0,
left: 0,
right: 0,
position: "absolute",
overflow: "hidden",
}}
>
bottomSpacing
</div>
const StoryWrapper = ({ topSpacing, bottomSpacing, ...props }: WrapperProps) => (
<div>
<div
style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
height: '100vh',
}}
>
<div
style={{
height: topSpacing,
backgroundColor: 'rgba(255,0,0,0.25)',
top: 0,
left: 0,
right: 0,
position: 'absolute',
overflow: 'hidden',
}}
>
topSpacing
</div>
<div
style={{
height: bottomSpacing,
backgroundColor: 'rgba(0,0,255,0.25)',
bottom: 0,
left: 0,
right: 0,
position: 'absolute',
overflow: 'hidden',
}}
>
bottomSpacing
</div>
</div>
{props.children}
</div>
{props.children}
</div>
);

View file

@ -1,33 +1,31 @@
import * as React from "react";
import styled from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import * as React from 'react';
import styled from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
type HeroContainerProps = {
topSpacing: number;
bottomSpacing: number;
topSpacing: number;
bottomSpacing: number;
};
type HeroProps = Partial<HeroContainerProps> & {
children: React.ReactNode;
children: React.ReactNode;
};
const HeroContainer = styled.div<HeroContainerProps>`
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
overflow-x: hidden;
min-height: calc(
100vh - ${(props) => props.topSpacing + props.bottomSpacing}px
);
margin-top: ${(props) => props.topSpacing}px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
overflow-x: hidden;
min-height: calc(100vh - ${(props) => props.topSpacing + props.bottomSpacing}px);
margin-top: ${(props) => props.topSpacing}px;
`;
export const Hero = (props: HeroProps) => (
<HeroContainer
topSpacing={props.topSpacing || 0}
bottomSpacing={props.bottomSpacing || 0}
>
{props.children}
</HeroContainer>
<HeroContainer
topSpacing={props.topSpacing || 0}
bottomSpacing={props.bottomSpacing || 0}
>
{props.children}
</HeroContainer>
);

View file

@ -1,34 +1,34 @@
import * as React from "react";
import { Button } from "roleypoly/src/design-system/atoms/button";
import { Popover as PopoverComponent } from "./Popover";
import * as React from 'react';
import { Button } from 'roleypoly/src/design-system/atoms/button';
import { Popover as PopoverComponent } from './Popover';
export default {
title: "Atoms/Popover",
argTypes: {
canDefocus: { control: "boolean" },
},
args: {
canDefocus: true,
},
title: 'Atoms/Popover',
argTypes: {
canDefocus: { control: 'boolean' },
},
args: {
canDefocus: true,
},
};
export const Popover = ({ canDefocus }) => {
const [isOpen, setIsOpen] = React.useState(false);
const [isOpen, setIsOpen] = React.useState(false);
return (
<div style={{ padding: 50 }}>
<Button size="small" onClick={() => setIsOpen(!isOpen)}>
{!isOpen ? "Open" : "Close"} me!
</Button>
<PopoverComponent
position="top right"
active={isOpen}
onExit={() => setIsOpen(false)}
canDefocus={canDefocus}
headContent={<>Hello c:</>}
>
stuff
</PopoverComponent>
</div>
);
return (
<div style={{ padding: 50 }}>
<Button size="small" onClick={() => setIsOpen(!isOpen)}>
{!isOpen ? 'Open' : 'Close'} me!
</Button>
<PopoverComponent
position="top right"
active={isOpen}
onExit={() => setIsOpen(false)}
canDefocus={canDefocus}
headContent={<>Hello c:</>}
>
stuff
</PopoverComponent>
</div>
);
};

View file

@ -1,91 +1,88 @@
import {
onSmallScreen,
onTablet,
} from "roleypoly/src/design-system/atoms/breakpoints";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import { transitions } from "roleypoly/src/design-system/atoms/timings";
import styled, { css } from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import { onSmallScreen, onTablet } from 'roleypoly/src/design-system/atoms/breakpoints';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
import { transitions } from 'roleypoly/src/design-system/atoms/timings';
import styled, { css } from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
type PopoverStyledProps = {
active: boolean;
preferredWidth?: number;
active: boolean;
preferredWidth?: number;
};
export const PopoverBase = styled.div<PopoverStyledProps>`
box-sizing: border-box;
position: absolute;
background-color: ${palette.taupe100};
padding: 5px;
border: 2px solid rgba(0, 0, 0, 0.15);
border-radius: 3px;
z-index: 10;
transition: opacity ${transitions.out2in}s ease-in,
transform ${transitions.out2in}s ease-in;
min-width: ${(props) => props.preferredWidth || 320}px;
max-width: 100vw;
${(props) =>
!props.active &&
css`
transform: translateY(-2vh);
opacity: 0;
pointer-events: none;
`}
${onSmallScreen(css`
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
min-width: unset;
width: 100vw;
height: 100vh;
`)};
background-color: ${palette.taupe100};
padding: 5px;
border: 2px solid rgba(0, 0, 0, 0.15);
border-radius: 3px;
z-index: 10;
transition: opacity ${transitions.out2in}s ease-in,
transform ${transitions.out2in}s ease-in;
min-width: ${(props) => props.preferredWidth || 320}px;
max-width: 100vw;
${(props) =>
!props.active &&
css`
transform: translateY(-2vh);
opacity: 0;
pointer-events: none;
`}
${onSmallScreen(css`
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
min-width: unset;
width: 100vw;
height: 100vh;
`)};
`;
export const DefocusHandler = styled.div<PopoverStyledProps>`
background-color: rgba(0, 0, 0, 0.01);
position: fixed;
z-index: -1;
top: 0;
bottom: 0;
left: 0;
right: 0;
${(props) =>
!props.active &&
css`
display: none;
pointer-events: none;
`}
background-color: rgba(0, 0, 0, 0.01);
position: fixed;
z-index: -1;
top: 0;
bottom: 0;
left: 0;
right: 0;
${(props) =>
!props.active &&
css`
display: none;
pointer-events: none;
`}
`;
export const PopoverHead = styled.div`
display: flex;
align-items: center;
display: flex;
align-items: center;
`;
export const PopoverHeadCloser = styled.div`
flex: 0;
font-size: 2em;
cursor: pointer;
margin-right: 10px;
border-radius: 2em;
min-width: 1.4em;
height: 1.4em;
display: flex;
align-items: center;
justify-content: center;
${onTablet(
css`
display: none;
`
)}
flex: 0;
font-size: 2em;
cursor: pointer;
margin-right: 10px;
border-radius: 2em;
min-width: 1.4em;
height: 1.4em;
display: flex;
align-items: center;
justify-content: center;
${onTablet(
css`
display: none;
`
)}
&:hover {
background: rgba(0, 0, 0, 0.1);
}
&:hover {
background: rgba(0, 0, 0, 0.1);
}
`;
export const PopoverContent = styled.div`
padding: 5px;
padding: 5px;
`;

View file

@ -1,42 +1,42 @@
import * as React from "react";
import * as React from 'react';
import {
PopoverBase,
DefocusHandler,
PopoverHead,
PopoverHeadCloser,
PopoverContent,
} from "./Popover.styled";
import { globalOnKeyUp } from "roleypoly/src/design-system/atoms/key-events";
import { IoMdClose } from "react-icons/io";
PopoverBase,
DefocusHandler,
PopoverHead,
PopoverHeadCloser,
PopoverContent,
} from './Popover.styled';
import { globalOnKeyUp } from 'roleypoly/src/design-system/atoms/key-events';
import { IoMdClose } from 'react-icons/io';
type PopoverProps = {
children: React.ReactNode;
position: "top left" | "top right" | "bottom left" | "bottom right";
active: boolean;
canDefocus?: boolean;
onExit?: (type: "escape" | "defocus" | "explicit") => void;
headContent: React.ReactNode;
children: React.ReactNode;
position: 'top left' | 'top right' | 'bottom left' | 'bottom right';
active: boolean;
canDefocus?: boolean;
onExit?: (type: 'escape' | 'defocus' | 'explicit') => void;
headContent: React.ReactNode;
};
export const Popover = (props: PopoverProps) => {
globalOnKeyUp(["Escape"], () => props.onExit?.("escape"), props.active);
return (
<>
<PopoverBase active={props.active}>
<PopoverHead>
<PopoverHeadCloser onClick={() => props.onExit?.("explicit")}>
<IoMdClose />
</PopoverHeadCloser>
<div>{props.headContent}</div>
</PopoverHead>
<PopoverContent>{props.children}</PopoverContent>
</PopoverBase>
{props.canDefocus && (
<DefocusHandler
active={props.active}
onClick={() => props.onExit?.("defocus")}
/>
)}
</>
);
globalOnKeyUp(['Escape'], () => props.onExit?.('escape'), props.active);
return (
<>
<PopoverBase active={props.active}>
<PopoverHead>
<PopoverHeadCloser onClick={() => props.onExit?.('explicit')}>
<IoMdClose />
</PopoverHeadCloser>
<div>{props.headContent}</div>
</PopoverHead>
<PopoverContent>{props.children}</PopoverContent>
</PopoverBase>
{props.canDefocus && (
<DefocusHandler
active={props.active}
onClick={() => props.onExit?.('defocus')}
/>
)}
</>
);
};

View file

@ -1,79 +1,79 @@
import * as React from "react";
import { Role as RoleComponent } from "./Role";
import { roleCategory } from "roleypoly/hack/fixtures/storyData";
import { withColors } from "roleypoly/src/design-system/atoms/colors/withColors";
import styled from "styled-components";
import * as React from 'react';
import { Role as RoleComponent } from './Role';
import { roleCategory } from 'roleypoly/hack/fixtures/storyData';
import { withColors } from 'roleypoly/src/design-system/atoms/colors/withColors';
import styled from 'styled-components';
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>
);

View file

@ -1,84 +1,79 @@
import styled, { css } from "styled-components";
import { transitions } from "roleypoly/src/design-system/atoms/timings";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled, { css } from 'styled-components';
import { transitions } from 'roleypoly/src/design-system/atoms/timings';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export type StyledProps = {
selected: boolean;
defaultColor: boolean;
disabled: boolean;
selected: boolean;
defaultColor: boolean;
disabled: boolean;
};
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);
}
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);
}
&:active {
transform: translateY(0);
box-shadow: 0 0 0 transparent;
}
`
: null};
&:active {
transform: translateY(0);
box-shadow: 0 0 0 transparent;
}
`
: null};
`;
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 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;
`;

View file

@ -1,80 +1,80 @@
import * as React from "react";
import { Role as RPCRole } from "@roleypoly/rpc/shared";
import * as styled from "./Role.styled";
import { FaCheck, FaTimes } from "react-icons/fa";
import { numberToChroma } from "roleypoly/src/design-system/atoms/colors";
import chroma from "chroma-js";
import * as React from 'react';
import { Role as RPCRole } from '@roleypoly/rpc/shared';
import * as styled from './Role.styled';
import { FaCheck, FaTimes } from 'react-icons/fa';
import { numberToChroma } from 'roleypoly/src/design-system/atoms/colors';
import chroma from 'chroma-js';
type Props = {
role: RPCRole.AsObject;
selected: boolean;
disabled?: boolean;
onClick?: (newState: boolean) => void;
tooltipId?: string;
role: RPCRole.AsObject;
selected: boolean;
disabled?: boolean;
onClick?: (newState: boolean) => void;
tooltipId?: string;
};
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 contrastColorUp = baseColor.brighten(5);
const contrastColorDown = baseColor.darken(5);
const ratio = chroma.contrast(contrastColorDown, baseColor);
const contrastColor = ratio > 2 ? contrastColorDown : contrastColorUp;
const accentColor = ratio > 2 ? baseColor.darken(2) : baseColor.brighten(2);
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 contrastColorUp = baseColor.brighten(5);
const contrastColorDown = baseColor.darken(5);
const ratio = chroma.contrast(contrastColorDown, baseColor);
const contrastColor = ratio > 2 ? contrastColorDown : contrastColorUp;
const accentColor = ratio > 2 ? baseColor.darken(2) : baseColor.brighten(2);
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,
};
const styledProps: styled.StyledProps = {
selected: props.selected,
defaultColor: props.role.color === 0,
disabled: !!props.disabled,
};
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 ? <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 ? <FaCheck /> : <FaTimes />}
</styled.Circle>
<styled.Text>{props.role.name}</styled.Text>
</styled.Outer>
);
};
const disabledReason = (role: RPCRole.AsObject) => {
switch (role.safety) {
case RPCRole.RoleSafety.HIGHERTHANBOT:
return `This role is above Roleypoly's own role.`;
case RPCRole.RoleSafety.DANGEROUSPERMISSIONS:
const { permissions } = role;
let permissionHits: string[] = [];
switch (role.safety) {
case RPCRole.RoleSafety.HIGHERTHANBOT:
return `This role is above Roleypoly's own role.`;
case RPCRole.RoleSafety.DANGEROUSPERMISSIONS:
const { permissions } = role;
let permissionHits: string[] = [];
(permissions & 0x00000008) === 0x00000008 &&
permissionHits.push("Administrator");
(permissions & 0x10000000) === 0x10000000 &&
permissionHits.push("Manage Roles");
(permissions & 0x00000008) === 0x00000008 &&
permissionHits.push('Administrator');
(permissions & 0x10000000) === 0x10000000 &&
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.`;
}
};

View file

@ -1,14 +1,14 @@
import { Space as SpaceComponent } from "./Space";
import * as React from "react";
import { Space as SpaceComponent } from './Space';
import * as React from 'react';
export default {
title: "Atoms",
title: 'Atoms',
};
export const Space = () => (
<>
hello world
<SpaceComponent />
but im over here
</>
<>
hello world
<SpaceComponent />
but im over here
</>
);

View file

@ -1,6 +1,6 @@
import styled from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export const Space = styled.div`
height: 15px;
height: 15px;
`;

View file

@ -1,22 +1,22 @@
import * as React from "react";
import { SparkleOverlay } from "./Sparkle";
import { Button } from "roleypoly/src/design-system/atoms/button";
import { Hero } from "roleypoly/src/design-system/atoms/hero";
import * as React from 'react';
import { SparkleOverlay } from './Sparkle';
import { Button } from 'roleypoly/src/design-system/atoms/button';
import { Hero } from 'roleypoly/src/design-system/atoms/hero';
export default {
title: "Atoms/Sparkle",
component: SparkleOverlay,
args: {
size: -10,
opacity: 1,
repeatCount: 3,
},
title: 'Atoms/Sparkle',
component: SparkleOverlay,
args: {
size: -10,
opacity: 1,
repeatCount: 3,
},
};
export const ExampleButton = (args) => (
<Hero>
<SparkleOverlay {...args}>
<Button>Yo check this!</Button>
</SparkleOverlay>
</Hero>
<Hero>
<SparkleOverlay {...args}>
<Button>Yo check this!</Button>
</SparkleOverlay>
</Hero>
);

View file

@ -1,55 +1,52 @@
import * as React from "react";
import styled from "styled-components";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import { SparklePatternAlpha, SparklePatternBeta } from "./Shapes";
import * as React from 'react';
import styled from 'styled-components';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
import { SparklePatternAlpha, SparklePatternBeta } from './Shapes';
type Props = {
children: React.ReactNode;
size?: number;
opacity?: number;
repeatCount?: number;
children: React.ReactNode;
size?: number;
opacity?: number;
repeatCount?: number;
};
const SparkleContainer = styled.div`
position: relative;
position: relative;
`;
type EffectProps = {
effectSize: Props["size"];
effectOpacity: Props["opacity"];
effectSize: Props['size'];
effectOpacity: Props['opacity'];
};
const SparkleEffect = styled.div<EffectProps>`
position: absolute;
top: ${(props) => props.effectSize}px;
bottom: ${(props) => props.effectSize}px;
left: ${(props) => props.effectSize}px;
right: ${(props) => props.effectSize}px;
display: flex;
justify-content: space-between;
z-index: 5;
opacity: ${(props) => props.effectOpacity};
pointer-events: none;
position: absolute;
top: ${(props) => props.effectSize}px;
bottom: ${(props) => props.effectSize}px;
left: ${(props) => props.effectSize}px;
right: ${(props) => props.effectSize}px;
display: flex;
justify-content: space-between;
z-index: 5;
opacity: ${(props) => props.effectOpacity};
pointer-events: none;
`;
export const SparkleOverlay = (props: Props) => (
<SparkleContainer>
<SparkleEffect
effectSize={props.size || 0}
effectOpacity={props.opacity || 1}
>
<SparklePatternAlpha
repeatCount={props.repeatCount}
height="100%"
strokeColor={palette.gold400}
/>
<SparklePatternBeta
repeatCount={props.repeatCount}
height="100%"
strokeColor={palette.gold400}
/>
</SparkleEffect>
{props.children}
</SparkleContainer>
<SparkleContainer>
<SparkleEffect effectSize={props.size || 0} effectOpacity={props.opacity || 1}>
<SparklePatternAlpha
repeatCount={props.repeatCount}
height="100%"
strokeColor={palette.gold400}
/>
<SparklePatternBeta
repeatCount={props.repeatCount}
height="100%"
strokeColor={palette.gold400}
/>
</SparkleEffect>
{props.children}
</SparkleContainer>
);

View file

@ -0,0 +1,24 @@
import * as React from 'react';
import { TabView, Tab } from './TabView';
export default {
title: 'Atoms/Tab View',
argTypes: {
tabCount: { control: 'range', min: 1, max: 100 },
},
args: {
tabCount: 10,
},
};
export const ManyTabs = ({ tabCount }) => {
const tabs = [...'0'.repeat(tabCount)].reduce(
(acc, _, idx) => ({
...acc,
[`Tab ${idx + 1}`]: <Tab>{() => <div>tab {idx + 1}</div>}</Tab>,
}),
{}
);
return <TabView>{tabs}</TabView>;
};

View file

@ -1,37 +0,0 @@
import * as React from 'react';
import { atomStories } from 'atoms/atoms.story';
import { TabView, Tab } from './TabView';
import { number } from '@storybook/addon-knobs';
const story = atomStories('Tab View', module);
story.add('Multiple Tabs', () => (
<TabView>
{{
'Tab 1': <Tab>{() => <div>tab 1</div>}</Tab>,
'Tab 2': <Tab>{() => <div>tab 2</div>}</Tab>,
}}
</TabView>
));
story.add('Single Tab', () => (
<TabView>
{{
'Tab 1': <Tab>{() => <div>tab 1</div>}</Tab>,
}}
</TabView>
));
story.add('Many Tabs', () => {
const amount = number('Tab Count', 10);
const tabs = [...'0'.repeat(amount)].reduce(
(acc, _, idx) => ({
...acc,
[`Tab ${idx + 1}`]: <Tab>{() => <div>tab {idx + 1}</div>}</Tab>,
}),
{}
);
return <TabView>{tabs}</TabView>;
});

View file

@ -1,43 +1,43 @@
import styled, { css } from "styled-components";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import { transitions } from "roleypoly/src/design-system/atoms/timings";
import { onTablet } from "roleypoly/src/design-system/atoms/breakpoints";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled, { css } from 'styled-components';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
import { transitions } from 'roleypoly/src/design-system/atoms/timings';
import { onTablet } from 'roleypoly/src/design-system/atoms/breakpoints';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
export const TabViewStyled = styled.div``;
export const TabTitleRow = styled.div`
display: flex;
border-bottom: 1px solid ${palette.taupe100};
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
display: flex;
border-bottom: 1px solid ${palette.taupe100};
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
`;
export const TabTitle = styled.div<{ selected: boolean }>`
flex: 1;
text-align: center;
padding: 0.7em 1em;
border-bottom: 3px solid transparent;
transition: border-color ${transitions.in2out}s ease-in-out,
color ${transitions.in2out}s ease-in-out;
cursor: pointer;
color: ${palette.taupe500};
${(props) =>
props.selected
? css`
color: unset;
border-bottom-color: ${palette.taupe500};
`
: css`
&:hover {
border-bottom-color: ${palette.taupe300};
color: unset;
}
`};
${onTablet(css`
padding: 0.45em 1em;
`)}
flex: 1;
text-align: center;
padding: 0.7em 1em;
border-bottom: 3px solid transparent;
transition: border-color ${transitions.in2out}s ease-in-out,
color ${transitions.in2out}s ease-in-out;
cursor: pointer;
color: ${palette.taupe500};
${(props) =>
props.selected
? css`
color: unset;
border-bottom-color: ${palette.taupe500};
`
: css`
&:hover {
border-bottom-color: ${palette.taupe300};
color: unset;
}
`};
${onTablet(css`
padding: 0.45em 1em;
`)}
`;
export const TabContent = styled.div``;

View file

@ -7,6 +7,7 @@ export type TabViewProps = {
};
type TabProps = {
title: string;
children: () => React.ReactNode;
};

View file

@ -1,36 +1,36 @@
import * as React from "react";
import { TextInput, TextInputWithIcon } from "./TextInput";
import { SmallTitle } from "roleypoly/src/design-system/atoms/typography";
import { FiKey } from "react-icons/fi";
import * as React from 'react';
import { TextInput, TextInputWithIcon } from './TextInput';
import { SmallTitle } from 'roleypoly/src/design-system/atoms/typography';
import { FiKey } from 'react-icons/fi';
export default {
title: "Atoms/Text Input",
argTypes: {
placeholder: { control: "text" },
},
args: {
placeholder: "Fill me in!",
},
title: 'Atoms/Text Input',
argTypes: {
placeholder: { control: 'text' },
},
args: {
placeholder: 'Fill me in!',
},
};
export const Common = (args) => (
<div>
<SmallTitle>TextInput</SmallTitle>
<div>
<TextInput {...args} />
<SmallTitle>TextInput</SmallTitle>
<div>
<TextInput {...args} />
</div>
<div>
<TextInput {...args} disabled />
</div>
<SmallTitle>TextInputWithIcon</SmallTitle>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} />
</div>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} disabled />
</div>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} type="password" />
</div>
</div>
<div>
<TextInput {...args} disabled />
</div>
<SmallTitle>TextInputWithIcon</SmallTitle>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} />
</div>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} disabled />
</div>
<div>
<TextInputWithIcon icon={<FiKey />} {...args} type="password" />
</div>
</div>
);

View file

@ -1,83 +1,83 @@
import * as React from "react";
import styled from "styled-components";
import { palette } from "roleypoly/src/design-system/atoms/colors";
import * as React from 'react';
import styled from 'styled-components';
import { palette } from 'roleypoly/src/design-system/atoms/colors';
const StyledTextInput = styled.input`
appearance: none;
border: 1px solid ${palette.taupe200};
border-radius: 3px;
line-height: 163%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: ${palette.taupe300};
color: ${palette.grey600};
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
position: relative;
width: 100%;
box-sizing: border-box;
max-width: 97vw;
appearance: none;
border: 1px solid ${palette.taupe200};
border-radius: 3px;
line-height: 163%;
padding: 12px 16px;
font-size: 1.2rem;
background-color: ${palette.taupe300};
color: ${palette.grey600};
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
position: relative;
width: 100%;
box-sizing: border-box;
max-width: 97vw;
:focus {
outline: none;
border-color: ${palette.grey100};
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.25);
}
:focus {
outline: none;
border-color: ${palette.grey100};
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.25);
}
[disabled],
:disabled {
cursor: not-allowed;
color: rgba(255, 255, 255, 0.75);
font-style: italic;
}
[disabled],
:disabled {
cursor: not-allowed;
color: rgba(255, 255, 255, 0.75);
font-style: italic;
}
:hover:not([disabled]) {
border-color: ${palette.grey100};
}
:hover:not([disabled]) {
border-color: ${palette.grey100};
}
::placeholder {
color: ${palette.taupe500};
}
::placeholder {
color: ${palette.taupe500};
}
`;
type TextInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
_override?: React.Component;
_override?: React.Component;
};
export const TextInput = (props: TextInputProps) => {
const { ...rest } = props;
return <StyledTextInput {...rest} />;
const { ...rest } = props;
return <StyledTextInput {...rest} />;
};
const StyledTextInputWithIcon = styled(StyledTextInput)`
padding-left: 36px;
padding-left: 36px;
`;
const IconContainer = styled.div`
position: absolute;
left: 12px;
top: 0;
bottom: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 12px;
top: 0;
bottom: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
`;
const IconInputContainer = styled.div`
position: relative;
width: 100%;
position: relative;
width: 100%;
`;
type TextInputWithIconProps = TextInputProps & {
icon: React.ReactNode;
icon: React.ReactNode;
};
export const TextInputWithIcon = (props: TextInputWithIconProps) => {
const { icon, ...rest } = props;
return (
<IconInputContainer>
<IconContainer>{icon}</IconContainer>
<StyledTextInputWithIcon {...rest}></StyledTextInputWithIcon>
</IconInputContainer>
);
const { icon, ...rest } = props;
return (
<IconInputContainer>
<IconContainer>{icon}</IconContainer>
<StyledTextInputWithIcon {...rest}></StyledTextInputWithIcon>
</IconInputContainer>
);
};

View file

@ -1,16 +1,16 @@
import * as React from "react";
import { Typist } from "./Typist";
import * as React from 'react';
import { Typist } from './Typist';
export default {
title: "Atoms/Typist",
component: Typist,
args: {
charTimeout: 75,
resetTimeout: 2000,
lines: ["hello world", "and again", "a third", "story time!"],
},
title: 'Atoms/Typist',
component: Typist,
args: {
charTimeout: 75,
resetTimeout: 2000,
lines: ['hello world', 'and again', 'a third', 'story time!'],
},
};
export const Looping = (args) => {
return <Typist {...args} />;
return <Typist {...args} />;
};

View file

@ -1,37 +1,37 @@
import * as React from "react";
import * as React from 'react';
type TypistProps = {
resetTimeout: number;
charTimeout: number;
lines: string[];
resetTimeout: number;
charTimeout: number;
lines: string[];
};
export const Typist = (props: TypistProps) => {
const [outputText, setOutputText] = React.useState("");
const [currentLine, setCurrentLine] = React.useState(0);
const [outputText, setOutputText] = React.useState('');
const [currentLine, setCurrentLine] = React.useState(0);
React.useEffect(() => {
const fullLine = props.lines[currentLine];
React.useEffect(() => {
const fullLine = props.lines[currentLine];
if (outputText === fullLine) {
const timeout = setTimeout(() => {
setOutputText("");
setCurrentLine((currentLine + 1) % props.lines.length);
}, props.resetTimeout);
if (outputText === fullLine) {
const timeout = setTimeout(() => {
setOutputText('');
setCurrentLine((currentLine + 1) % props.lines.length);
}, props.resetTimeout);
return () => {
clearTimeout(timeout);
};
}
return () => {
clearTimeout(timeout);
};
}
const timeout = setTimeout(() => {
setOutputText(fullLine.slice(0, outputText.length + 1));
}, props.charTimeout);
const timeout = setTimeout(() => {
setOutputText(fullLine.slice(0, outputText.length + 1));
}, props.charTimeout);
return () => {
clearTimeout(timeout);
};
}, [currentLine, outputText]);
return () => {
clearTimeout(timeout);
};
}, [currentLine, outputText]);
return <>{outputText}</>;
return <>{outputText}</>;
};

View file

@ -1,109 +1,109 @@
import * as React from "react";
import * as typography from "./typography";
import styled from "styled-components";
import * as React from 'react';
import * as typography from './typography';
import styled from 'styled-components';
export default {
title: "Atoms/Typography",
title: 'Atoms/Typography',
};
const Text = () => (
<>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et facilis alias
placeat cumque sapiente ad delectus omnis quae. Reiciendis quibusdam
deserunt repellat. Exercitationem modi incidunt autem nemo tempore eaque
soluta.
</p>
<p>
4312.
6.
6.
</p>
<p>
🔸🐕🔺💱🎊👽🐛 👨📼🕦📞 👱👆🍗👚🌈 🔝🔟🍉🔰🍲🏁🕗 🎡🐉🍲📻🔢🔄
💟💲🍻💜💩🔼 🎱🌸📛👫🌻 🗽🕜🐥👕🍈. 🐒🍚🔓📱🏦 🎦🌑🔛💙👣🔚 🔆🗻🌿🎳📲🍯
🌞💟🎌🍌 🔪📯🐎💮 👌👭🎋🏉🏰 📓🕃🎂💉🔩 🐟🌇👺🌊🌒 📪👅🍂🍁 🌖🐮🔽🌒📊.
🔤🍍🌸📷🎴 💏🍌📎👥👉👒 👝💜🔶🍣 💨🗼👈💉💉💰 🍐🕖🌰👝🕓🏊🐕 🏀📅📼📒
🐕🌈👋
</p>
</>
<>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et facilis alias
placeat cumque sapiente ad delectus omnis quae. Reiciendis quibusdam deserunt
repellat. Exercitationem modi incidunt autem nemo tempore eaque soluta.
</p>
<p>
4312.
6.
6.
</p>
<p>
🔸🐕🔺💱🎊👽🐛 👨📼🕦📞 👱👆🍗👚🌈 🔝🔟🍉🔰🍲🏁🕗 🎡🐉🍲📻🔢🔄 💟💲🍻💜💩🔼
🎱🌸📛👫🌻 🗽🕜🐥👕🍈. 🐒🍚🔓📱🏦 🎦🌑🔛💙👣🔚 🔆🗻🌿🎳📲🍯 🌞💟🎌🍌 🔪📯🐎💮
👌👭🎋🏉🏰 📓🕃🎂💉🔩 🐟🌇👺🌊🌒 📪👅🍂🍁 🌖🐮🔽🌒📊. 🔤🍍🌸📷🎴 💏🍌📎👥👉👒
👝💜🔶🍣 💨🗼👈💉💉💰 🍐🕖🌰👝🕓🏊🐕 🏀📅📼📒 🐕🌈👋
</p>
</>
);
const swatches: [string, string | undefined, string][] = [
["text900", "LargeTitle", "Used for large titles."],
["text800", "MediumTitle", "Used for medium titles."],
["text700", "SmallTitle", "Used for small titles."],
["text600", "AccentTitle", "Used for accenting titles."],
["text500", "LargeText", "Used for general large font text blocks."],
["text400", "Text", "Used for less important font text blocks."],
["text300", undefined, "Used for smaller UI elements."],
["text200", "AmbientLarge", "Used for ambient text."],
["text100", "AmbientSmall", "Used for ambient text."],
['text900', 'LargeTitle', 'Used for large titles.'],
['text800', 'MediumTitle', 'Used for medium titles.'],
['text700', 'SmallTitle', 'Used for small titles.'],
['text600', 'AccentTitle', 'Used for accenting titles.'],
['text500', 'LargeText', 'Used for general large font text blocks.'],
['text400', 'Text', 'Used for less important font text blocks.'],
['text300', undefined, 'Used for smaller UI elements.'],
['text200', 'AmbientLarge', 'Used for ambient text.'],
['text100', 'AmbientSmall', 'Used for ambient text.'],
];
const Section = styled.section`
margin: 3.26rem;
margin: 3.26rem;
`;
const swatch = (mixin: typeof typography.text900) =>
styled.p`
${mixin}
`;
styled.p`
${mixin}
`;
const Usage = styled.code`
${typography.text300}
${typography.text300}
`;
const Description = styled.i`
${typography.text200}
${typography.text200}
`;
export const Sizes = () => (
<div>
{swatches.map(([mixin, componentName, usage], i) => {
const Component = swatch((typography as any)[mixin]);
return (
<Section key={i}>
<div>
<Component>The quick brown fox jumped over the lazy dog.</Component>
</div>
<div>
<Usage>
<code>
@{mixin} {componentName && `<${componentName} />`}
</code>
</Usage>
</div>
<div>
<Description>{usage}</Description>
</div>
</Section>
);
})}
</div>
<div>
{swatches.map(([mixin, componentName, usage], i) => {
const Component = swatch((typography as any)[mixin]);
return (
<Section key={i}>
<div>
<Component>
The quick brown fox jumped over the lazy dog.
</Component>
</div>
<div>
<Usage>
<code>
@{mixin} {componentName && `<${componentName} />`}
</code>
</Usage>
</div>
<div>
<Description>{usage}</Description>
</div>
</Section>
);
})}
</div>
);
const SpacingHead = styled.p`
${typography.text700}
${typography.text700}
`;
const SpacingSection = styled(Section)`
max-width: 50vw;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
max-width: 50vw;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
`;
export const Spacing = () => (
<div>
{swatches.map(([mixin], i) => {
const Component = swatch((typography as any)[mixin]);
return (
<SpacingSection key={i}>
<SpacingHead>@{mixin}</SpacingHead>
<Component>
<Text />
</Component>
</SpacingSection>
);
})}
</div>
<div>
{swatches.map(([mixin], i) => {
const Component = swatch((typography as any)[mixin]);
return (
<SpacingSection key={i}>
<SpacingHead>@{mixin}</SpacingHead>
<Component>
<Text />
</Component>
</SpacingSection>
);
})}
</div>
);

View file

@ -1,88 +1,88 @@
import styled, { css } from "styled-components";
import * as _ from "styled-components"; // tslint:disable-line:no-duplicate-imports
import styled, { css } from 'styled-components';
import * as _ from 'styled-components'; // tslint:disable-line:no-duplicate-imports
const reset = css`
margin: 0;
line-height: 163%;
padding: 0;
font-weight: 400;
text-decoration: none;
font-size-adjust: 0.75;
margin: 0;
line-height: 163%;
padding: 0;
font-weight: 400;
text-decoration: none;
font-size-adjust: 0.75;
`;
export const text900 = css`
${reset}
font-size: 2.3rem;
${reset}
font-size: 2.3rem;
`;
export const text800 = css`
${reset}
font-size: 2rem;
${reset}
font-size: 2rem;
`;
export const text700 = css`
${reset}
font-size: 1.7rem;
${reset}
font-size: 1.7rem;
`;
export const text600 = css`
${reset}
font-size: 1.4rem;
${reset}
font-size: 1.4rem;
`;
export const text500 = css`
${reset}
font-size: 1.2rem;
${reset}
font-size: 1.2rem;
`;
export const text400 = css`
${reset}
font-size: 1rem;
${reset}
font-size: 1rem;
`;
export const text300 = css`
${reset}
font-size: 0.9rem;
${reset}
font-size: 0.9rem;
`;
export const text200 = css`
${reset}
font-size: 0.7rem;
${reset}
font-size: 0.7rem;
`;
export const text100 = css`
${reset}
font-size: 0.5rem;
${reset}
font-size: 0.5rem;
`;
export const LargeTitle = styled.span`
${text900}
${text900}
`;
export const MediumTitle = styled.span`
${text800}
${text800}
`;
export const SmallTitle = styled.span`
${text700}
${text700}
`;
export const AccentTitle = styled.span`
${text600}
${text600}
`;
export const LargeText = styled.span`
${text500}
${text500}
`;
export const Text = styled.span`
${text400}
${text400}
`;
export const AmbientLarge = styled.span`
${text200}
${text200}
`;
export const AmbientSmall = styled.span`
${text100}
${text100}
`;

View file

@ -4,9 +4,9 @@ This package houses the dev-container image.
It includes:
- go (1.15.2)
- bazel (latest via bazelisk)
- node (latest lts via nvm)
- go (1.15.2)
- bazel (latest via bazelisk)
- node (latest lts via nvm)
As well as any other tooling within VSCode Dev Containers.
@ -20,5 +20,5 @@ bazel run //srv/dev-container && docker run -it --rm bazel/src/dev-container:dev
To just use, this is published to two registries. There is no effective difference, except that GitHub's registry requires login, and Docker Hub does not.
- `docker pull roleypoly/dev-container:main`
- `docker pull docker.pkg.github.com/roleypoly/roleypoly/dev-container:main`
- `docker pull roleypoly/dev-container:main`
- `docker pull docker.pkg.github.com/roleypoly/roleypoly/dev-container:main`

View file

@ -4,18 +4,18 @@ Service for handling Discord OAuth flow.
## Responsibilities
- Redirect users to relevant Discord OAuth page w/ state
- Handle redirect from Discord OAuth flow and process the token
- Modify active session to include relevant data
- v3: for parity, this is just user data
- _vNext: get guilds from oauth and cache_
- _vNext: Source of truth for user guilds_
- Redirect users to relevant Discord OAuth page w/ state
- Handle redirect from Discord OAuth flow and process the token
- Modify active session to include relevant data
- v3: for parity, this is just user data
- _vNext: get guilds from oauth and cache_
- _vNext: Source of truth for user guilds_
## Boundaries & Services
- **Inbound**
- HTTP: /discord-auth/\*
- gRPC: DiscordAuthService
- **Outbound**
- Redis
- gRPC: SessionService
- **Inbound**
- HTTP: /discord-auth/\*
- gRPC: DiscordAuthService
- **Outbound**
- Redis
- gRPC: SessionService

View file

@ -1 +1 @@
console.log("hello world");
console.log('hello world');