Feat/editor category pass2 (#290)

* feat(design-system): add editor skeletons

* use css media queries rather than JS media queries

* init remake

* feat: add basis of toggle atom

* finish toggle

* use pointer cursor with toggle

* sync

* feat: add server message in editor

* cleanup storybook

* add short editor item and data model for categories

* chore: fix build by moving jest version downward

* chore: remove old category editor

* chore: fix EditorCategoryShort index

* add editor wiring and styling updates

* fix linting issues
This commit is contained in:
41666 2021-07-05 12:18:40 -05:00 committed by GitHub
parent a37d481b18
commit 7d681d69d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 927 additions and 1100 deletions

View file

@ -31,6 +31,7 @@ export const BreakpointsProvider = (props: { children: React.ReactNode }) => {
};
updateScreenSize();
setImmediate(() => updateScreenSize());
mediaQueries.onDesktop.addEventListener('change', updateScreenSize);
mediaQueries.onTablet.addEventListener('change', updateScreenSize);

View file

@ -1,13 +1,6 @@
import { onTablet } from '@roleypoly/design-system/atoms/breakpoints';
import styled, { css } from 'styled-components';
export const HalfsiesContainer = styled.div`
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
`;
export const HalfsiesItem = styled.div`
box-sizing: border-box;
flex: 1 1 100%;
@ -15,3 +8,16 @@ export const HalfsiesItem = styled.div`
flex: 1 2 50%;
`)}
`;
export const HalfsiesContainer = styled.div<{ center?: boolean }>`
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
${({ center }) =>
center &&
css`
align-content: center;
`}
`;

View file

@ -1,6 +1,22 @@
import { onSmallScreen } from '@roleypoly/design-system/atoms/breakpoints';
import { palette } from '@roleypoly/design-system/atoms/colors';
import { transitions } from '@roleypoly/design-system/atoms/timings';
import styled, { css } from 'styled-components';
import { palette } from '../colors';
import { transitions } from '../timings';
export const HideIfSmall = styled.div`
display: initial;
${onSmallScreen(css`
display: none;
`)}
`;
export const HideIfNotSmall = styled.div`
display: none;
${onSmallScreen(css`
display: initial;
`)}
`;
export const NavItem = styled.div<{ selected: boolean }>`
padding: 7px;
@ -35,6 +51,7 @@ export const DropdownNavOpener = styled.div`
cursor: pointer;
border-radius: 2px;
transition: background-color ${transitions.actionable}s ease-in-out;
width: 98vw;
&:hover {
background-color: ${palette.taupe300};

View file

@ -1,6 +1,5 @@
// thing should be everything visible on desktop/tablet and a popover when small
import { useBreakpointContext } from '@roleypoly/design-system/atoms/breakpoints';
import { Popover } from '@roleypoly/design-system/atoms/popover';
import { useState } from 'react';
import { GoChevronDown } from 'react-icons/go';
@ -8,6 +7,8 @@ import {
DropdownNavCurrent,
DropdownNavIcon,
DropdownNavOpener,
HideIfNotSmall,
HideIfSmall,
NavItem,
} from './QuickNav.styled';
@ -18,18 +19,17 @@ export type QuickNavProps = {
};
export const QuickNav = (props: QuickNavProps) => {
const breakpoints = useBreakpointContext();
if (breakpoints.screenSize.onSmallScreen) {
return <QuickNavCollapsed {...props} />;
}
return <QuickNavExpanded {...props} />;
return (
<>
<QuickNavExpanded {...props} />
<QuickNavCollapsed {...props} />
</>
);
};
export const QuickNavExpanded = (props: QuickNavProps) => {
return (
<div>
<HideIfSmall>
{props.navItems.map((navItem) => (
<NavItem
onClick={() => props.onNavChange?.(navItem)}
@ -39,7 +39,7 @@ export const QuickNavExpanded = (props: QuickNavProps) => {
{navItem}
</NavItem>
))}
</div>
</HideIfSmall>
);
};
@ -47,7 +47,7 @@ export const QuickNavCollapsed = (props: QuickNavProps) => {
const [popoverState, setPopoverState] = useState(false);
return (
<div>
<HideIfNotSmall>
{popoverState ? (
<Popover
headContent={<>Server Editor</>}
@ -80,6 +80,6 @@ export const QuickNavCollapsed = (props: QuickNavProps) => {
<DropdownNavCurrent>{props.currentNavItem}</DropdownNavCurrent>
</DropdownNavOpener>
)}
</div>
</HideIfNotSmall>
);
};

View file

@ -22,8 +22,9 @@ export const TabTitleRow = styled.div`
position: fixed;
${onSmallScreen(
css`
width: fit-content;
position: unset;
max-width: 100vw;
max-width: 98vw;
`
)}
`;
@ -65,5 +66,9 @@ export const TabContentTitle = styled.div`
${text500}
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 10px;
padding: 0.5em 7px;
`;
export const TabDepth = styled.div`
margin-left: 7px;
`;

View file

@ -10,6 +10,7 @@ import {
export type TabViewProps = {
children: React.ReactNode[];
initialTab?: number;
masthead?: React.ReactNode;
};
type TabProps = {
@ -39,6 +40,7 @@ export const TabView = (props: TabViewProps) => {
return (
<TabViewStyled>
<TabTitleRow>
{props.masthead && props.masthead}
<QuickNav
currentNavItem={tabNames[currentTab]}
navItems={tabNames}

View file

@ -1,8 +1,9 @@
import { palette } from '@roleypoly/design-system/atoms/colors';
import { fontCSS } from '@roleypoly/design-system/atoms/fonts';
import * as React from 'react';
import styled from 'styled-components';
import styled, { css } from 'styled-components';
const StyledTextInput = styled.input`
const common = css`
appearance: none;
border: 1px solid ${palette.taupe200};
border-radius: 3px;
@ -39,11 +40,14 @@ const StyledTextInput = styled.input`
}
`;
type TextInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
_override?: React.Component;
};
const StyledTextInput = styled.input`
${common};
`;
export const TextInput = (props: TextInputProps) => {
type TextInputProps<T extends HTMLInputElement | HTMLTextAreaElement> =
React.InputHTMLAttributes<T>;
export const TextInput = (props: TextInputProps<HTMLInputElement>) => {
const { ...rest } = props;
return <StyledTextInput {...rest} />;
};
@ -68,7 +72,7 @@ const IconInputContainer = styled.div`
width: 100%;
`;
type TextInputWithIconProps = TextInputProps & {
type TextInputWithIconProps = TextInputProps<HTMLInputElement> & {
icon: React.ReactNode;
};
@ -81,3 +85,27 @@ export const TextInputWithIcon = (props: TextInputWithIconProps) => {
</IconInputContainer>
);
};
const StyledTextarea = styled.textarea`
${common};
${fontCSS};
`;
export const MultilineTextInput = (
props: TextInputProps<HTMLTextAreaElement> & { rows?: number }
) => {
const { ...rest } = props;
const [value, setValue] = React.useState(String(props.value));
const rows = Math.min(10, Math.max(props.rows || 2, value.split(/\r?\n/).length));
return (
<StyledTextarea
{...rest}
rows={rows}
value={value}
onChange={(eventData) => {
setValue(eventData.target.value);
props.onChange?.(eventData);
}}
/>
);
};

View file

@ -0,0 +1,23 @@
import * as React from 'react';
import { Toggle } from './Toggle';
export default {
title: 'Atoms/Toggle',
component: Toggle,
};
export const toggle = (args) => <Toggle {...args}>Turn a cool thing on</Toggle>;
export const interactive = (args) => {
const [state, setState] = React.useState(true);
return (
<Toggle
{...args}
state={state}
onChange={(val) => {
setState(val);
args.onChange(val);
}}
>
Turn a cool thing on
</Toggle>
);
};

View file

@ -0,0 +1,40 @@
import { palette } from '@roleypoly/design-system/atoms/colors';
import styled, { css } from 'styled-components';
import { transitions } from '../timings';
export const ToggleState = styled.div`
height: 1em;
width: 1em;
border-radius: 1em;
background-color: ${palette.grey600};
position: absolute;
top: 0.15em;
left: 0.15em;
transform: translateX(0);
@media (prefers-reduced-motion: no-preference) {
transition: transform ${transitions.actionable}s ease-in-out;
}
`;
export const ToggleSwitch = styled.div<{ state: boolean }>`
display: inline-block;
background-color: ${(props) => (props.state ? palette.green200 : 'rgba(0,0,0,0.45)')};
height: 1.3em;
width: 2.6em;
border-radius: 1.3em;
position: relative;
border: 1px solid rgba(0, 0, 0, 0.1);
top: 0.23em;
transition: background-color ${transitions.in2in}s ease-in-out;
cursor: pointer;
margin-right: 0.5em;
${ToggleState} {
${(props) =>
props.state === true &&
css`
transform: translateX(1.3em);
`}
}
`;

View file

@ -0,0 +1,20 @@
import { ToggleState, ToggleSwitch } from './Toggle.styled';
type ToggleProps = {
onChange?: (newState: boolean) => void;
children: React.ReactNode;
state: boolean;
};
export const Toggle = (props: ToggleProps) => (
<div
onClick={() => {
props.onChange?.(!props.state);
}}
>
<ToggleSwitch state={props.state}>
<ToggleState />
</ToggleSwitch>
{props.children}
</div>
);

View file

@ -0,0 +1 @@
export * from './Toggle';