mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-06-15 17:19:10 +00:00
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:
parent
a37d481b18
commit
7d681d69d6
48 changed files with 927 additions and 1100 deletions
|
@ -31,6 +31,7 @@ export const BreakpointsProvider = (props: { children: React.ReactNode }) => {
|
|||
};
|
||||
|
||||
updateScreenSize();
|
||||
setImmediate(() => updateScreenSize());
|
||||
|
||||
mediaQueries.onDesktop.addEventListener('change', updateScreenSize);
|
||||
mediaQueries.onTablet.addEventListener('change', updateScreenSize);
|
||||
|
|
|
@ -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;
|
||||
`}
|
||||
`;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
`;
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
23
packages/design-system/atoms/toggle/Toggle.stories.tsx
Normal file
23
packages/design-system/atoms/toggle/Toggle.stories.tsx
Normal 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>
|
||||
);
|
||||
};
|
40
packages/design-system/atoms/toggle/Toggle.styled.tsx
Normal file
40
packages/design-system/atoms/toggle/Toggle.styled.tsx
Normal 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);
|
||||
`}
|
||||
}
|
||||
`;
|
20
packages/design-system/atoms/toggle/Toggle.tsx
Normal file
20
packages/design-system/atoms/toggle/Toggle.tsx
Normal 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>
|
||||
);
|
1
packages/design-system/atoms/toggle/index.ts
Normal file
1
packages/design-system/atoms/toggle/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './Toggle';
|
Loading…
Add table
Add a link
Reference in a new issue