feat(UI): add initial server picker

This commit is contained in:
41666 2020-12-19 20:10:23 -05:00
parent d4e8e8330a
commit e758c09fbf
19 changed files with 319 additions and 12 deletions

View file

@ -43,6 +43,7 @@
"react-is": "^17.0.1",
"react-tooltip": "^4.2.11",
"styled-components": "^5.2.1",
"styled-normalize": "^8.0.7",
"swr": "^0.3.9"
},
"devDependencies": {

View file

@ -140,6 +140,13 @@ export const guild: Guild = {
roles: [],
};
export const roleypolyGuild: GuildSlug = {
name: 'Roleypoly',
id: '386659935687147521',
permissionLevel: 0,
icon: 'ffee638c73ff9c972554f64ca34d67ee',
};
export const guildMap: { [x: string]: GuildSlug } = {
'emoji megaporium': {
name: guild.name,
@ -147,12 +154,7 @@ export const guildMap: { [x: string]: GuildSlug } = {
permissionLevel: 0,
icon: guild.icon,
},
Roleypoly: {
name: 'Roleypoly',
id: '203493697696956418',
permissionLevel: 0,
icon: 'ff08d36f5aee1ff48f8377b65d031ab0',
},
Roleypoly: roleypolyGuild,
'chamber of secrets': {
name: 'chamber of secrets',
id: 'aaa',
@ -234,6 +236,6 @@ export const mastheadSlugs: GuildSlug[] = guildEnum.guilds.map<GuildSlug>(
id: guild.guild.id,
name: guild.guild.name,
icon: guild.guild.icon,
permissionLevel: idx % 3,
permissionLevel: 1 << idx % 3,
})
);

View file

@ -0,0 +1,13 @@
import { SmallTitle } from 'roleypoly/design-system/atoms/typography';
import { Collapse } from './Collapse';
export default {
title: 'Atoms/Collapse',
component: Collapse,
};
export const collapse = (args) => (
<SmallTitle>
Hello, <Collapse {...args}>small</Collapse> world!
</SmallTitle>
);

View file

@ -0,0 +1,10 @@
import styled, { css } from 'styled-components';
import { onSmallScreen } from '../breakpoints';
export const Collapse = styled.span<{ preventCollapse?: boolean }>`
${(props) =>
!props.preventCollapse &&
onSmallScreen(css`
display: none;
`)}
`;

View file

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

View file

@ -96,3 +96,13 @@ export const Link = styled.a`
color: ${palette.taupe600};
}
`;
export const CompletelyStylelessLink = styled.a`
color: inherit;
text-decoration: none;
:visited,
:active,
:hover {
color: inherit;
}
`;

View file

@ -0,0 +1,12 @@
import { roleypolyGuild } from 'roleypoly/common/types/storyData';
import { ServerListingCard } from './ServerListingCard';
export default {
title: 'Molecules/Server Listing Card',
component: ServerListingCard,
args: {
guild: { ...roleypolyGuild, permissionLevel: 4 },
},
};
export const serverListingCard = (args) => <ServerListingCard {...args} />;

View file

@ -0,0 +1,89 @@
import { onSmallScreen, onTablet } from 'roleypoly/design-system/atoms/breakpoints';
import { palette } from 'roleypoly/design-system/atoms/colors';
import { transitions } from 'roleypoly/design-system/atoms/timings';
import { text200, text500 } from 'roleypoly/design-system/atoms/typography';
import styled, { css } from 'styled-components';
export const CardLine = styled.div<{ left?: boolean }>`
justify-content: center;
align-items: center;
display: flex;
padding: 5px;
box-sizing: border-box;
${(props) =>
props.left &&
css`
flex: 1;
justify-content: flex-end;
align-items: flex-end;
`}
`;
export const MaxWidthTitle = styled.div`
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export const PermissionTagStyled = styled.div<{ hiddenOnSmall?: boolean }>`
${text200}
display: inline-block;
background-color: ${palette.taupe200};
padding: 4px 6px;
border-radius: 2px;
svg {
position: relative;
top: 1px;
${onTablet(
css`
margin-right: 2px;
`
)}
}
${(props) =>
props.hiddenOnSmall &&
onSmallScreen(
css`
display: none;
`
)}
`;
export const CardBase = styled.div`
${text500}
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-color: ${palette.taupe300};
overflow-x: hidden;
text-align: center;
display: flex;
align-items: center;
padding: 10px;
border-radius: 3px;
cursor: pointer;
user-select: none;
transform: translate(0);
transition: transform ease-in-out ${transitions.actionable}s,
box-shadow ease-in-out ${transitions.actionable}s,
border-color ease-in-out ${transitions.out2in}s;
box-sizing: border-box;
max-width: 98vw;
:hover {
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
transform: translate(0, -1px);
}
:active {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
transform: translate(0);
}
${onTablet(css`
flex-direction: column;
justify-content: left;
`)}
`;

View file

@ -0,0 +1,60 @@
import * as React from 'react';
import { GoPerson, GoStar, GoZap } from 'react-icons/go';
import { GuildSlug, UserGuildPermissions } from 'roleypoly/common/types';
import { Avatar, utils } from 'roleypoly/design-system/atoms/avatar';
import { Collapse } from 'roleypoly/design-system/atoms/collapse';
import {
CardBase,
CardLine,
MaxWidthTitle,
PermissionTagStyled,
} from './ServerListingCard.styled';
type ServerListingProps = {
guild: GuildSlug;
};
export const ServerListingCard = (props: ServerListingProps) => (
<CardBase>
<CardLine>
<Avatar
hash={props.guild.icon}
src={utils.avatarHash(props.guild.id, props.guild.icon, 'icons')}
>
{utils.initialsFromName(props.guild.name)}
</Avatar>
</CardLine>
<MaxWidthTitle>{props.guild.name}</MaxWidthTitle>
<CardLine left>
<PermissionTag permissionLevel={props.guild.permissionLevel} />
</CardLine>
</CardBase>
);
const PermissionTag = (props: { permissionLevel: UserGuildPermissions }) => {
switch (props.permissionLevel) {
case UserGuildPermissions.Admin:
return (
<PermissionTagStyled>
<GoStar />
<Collapse>Administrator</Collapse>
</PermissionTagStyled>
);
case UserGuildPermissions.Manager:
return (
<PermissionTagStyled>
<GoZap />
<Collapse>Role Manager</Collapse>
</PermissionTagStyled>
);
default:
return (
<PermissionTagStyled hiddenOnSmall>
<GoPerson />
<Collapse>Member</Collapse>
</PermissionTagStyled>
);
}
return null;
};

View file

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

View file

@ -0,0 +1,12 @@
import { mastheadSlugs } from 'roleypoly/common/types/storyData';
import { ServersListing } from './ServersListing';
export default {
title: 'Organisms/Servers Listing',
component: ServersListing,
args: {
guilds: mastheadSlugs,
},
};
export const serversListing = (args) => <ServersListing {...args} />;

View file

@ -0,0 +1,23 @@
import { onTablet } from 'roleypoly/design-system/atoms/breakpoints';
import styled, { css } from 'styled-components';
export const ContentContainer = styled.div`
display: flex;
flex-direction: column;
max-width: calc(98vw - 15px);
padding-bottom: 25px;
${onTablet(css`
flex-direction: row;
flex-wrap: wrap;
`)}
`;
export const CardContainer = styled.div`
box-sizing: border-box;
margin-bottom: 5px;
${onTablet(css`
margin: 5px;
flex-basis: 30%;
max-width: 30%;
`)}
`;

View file

@ -0,0 +1,33 @@
import Link from 'next/link';
import * as React from 'react';
import { GuildSlug } from 'roleypoly/common/types';
import { sortBy } from 'roleypoly/common/utils/sortBy';
import { CompletelyStylelessLink } from 'roleypoly/design-system/atoms/typography';
import { ServerListingCard } from 'roleypoly/design-system/molecules/server-listing-card';
import { CardContainer, ContentContainer } from './ServersListing.styled';
type ServersListingProps = {
guilds: GuildSlug[];
};
export const ServersListing = (props: ServersListingProps) => (
<ContentContainer>
{props.guilds &&
sortBy(props.guilds, 'name', (a: string, b: string) =>
a.toLowerCase() > b.toLowerCase() ? 1 : -1
).map((guild, idx) => (
<CardContainer key={idx}>
<Link
as={`/s/${guild.id}`}
href={`/s/[id]`}
prefetch={false}
passHref
>
<CompletelyStylelessLink>
<ServerListingCard guild={guild} />
</CompletelyStylelessLink>
</Link>
</CardContainer>
))}
</ContentContainer>
);

View file

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

View file

@ -0,0 +1,13 @@
import * as React from 'react';
import { mastheadSlugs, user } from 'roleypoly/common/types/storyData';
import { ServersTemplate } from '.';
export default {
title: 'Templates/Servers Page',
args: {
guilds: mastheadSlugs,
user: user,
},
};
export const serversPage = (args) => <ServersTemplate {...args} />;

View file

@ -0,0 +1,14 @@
import * as React from 'react';
import { GuildSlug } from 'roleypoly/common/types';
import { AppShell, AppShellProps } from 'roleypoly/design-system/organisms/app-shell';
import { ServersListing } from 'roleypoly/design-system/organisms/servers-listing/ServersListing';
type ServerTemplateProps = Omit<AppShellProps, 'children'> & {
guilds: GuildSlug[];
};
export const ServersTemplate = (props: ServerTemplateProps) => (
<AppShell {...props} disableGuildPicker>
<ServersListing guilds={props.guilds}></ServersListing>
</AppShell>
);

View file

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

View file

@ -1,11 +1,17 @@
import { AppShell } from 'roleypoly/design-system/organisms/app-shell';
import Head from 'next/head';
import { ServersTemplate } from 'roleypoly/design-system/templates/servers';
import { useAppShellProps } from 'roleypoly/providers/appShellData';
export default () => {
const Servers = () => {
const { appShellProps } = useAppShellProps();
return (
<AppShell {...appShellProps}>
<div></div>
</AppShell>
<>
<Head>
<title>Viewing your servers - Roleypoly</title>
</Head>
<ServersTemplate {...appShellProps} guilds={appShellProps.guilds || []} />
</>
);
};
export default Servers;

View file

@ -12966,6 +12966,11 @@ styled-jsx@3.3.2:
stylis "3.5.4"
stylis-rule-sheet "0.0.10"
styled-normalize@^8.0.7:
version "8.0.7"
resolved "https://registry.yarnpkg.com/styled-normalize/-/styled-normalize-8.0.7.tgz#e883bff6a0c59a65a39365a4eb9c6cf48372c61f"
integrity sha512-qQV4O7B9g7ZUnStCwGde7Dc/mcFF/pz0Ha/LL7+j/r6uopf6kJCmmR7jCPQMCBrDkYiQ4xvw1hUoceVJkdaMuQ==
stylelint-config-prettier@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-8.0.2.tgz#da9de33da4c56893cbe7e26df239a7374045e14e"