mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-04-25 03:49:11 +00:00
feat(UI): add initial server picker
This commit is contained in:
parent
d4e8e8330a
commit
e758c09fbf
19 changed files with 319 additions and 12 deletions
|
@ -43,6 +43,7 @@
|
||||||
"react-is": "^17.0.1",
|
"react-is": "^17.0.1",
|
||||||
"react-tooltip": "^4.2.11",
|
"react-tooltip": "^4.2.11",
|
||||||
"styled-components": "^5.2.1",
|
"styled-components": "^5.2.1",
|
||||||
|
"styled-normalize": "^8.0.7",
|
||||||
"swr": "^0.3.9"
|
"swr": "^0.3.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -140,6 +140,13 @@ export const guild: Guild = {
|
||||||
roles: [],
|
roles: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const roleypolyGuild: GuildSlug = {
|
||||||
|
name: 'Roleypoly',
|
||||||
|
id: '386659935687147521',
|
||||||
|
permissionLevel: 0,
|
||||||
|
icon: 'ffee638c73ff9c972554f64ca34d67ee',
|
||||||
|
};
|
||||||
|
|
||||||
export const guildMap: { [x: string]: GuildSlug } = {
|
export const guildMap: { [x: string]: GuildSlug } = {
|
||||||
'emoji megaporium': {
|
'emoji megaporium': {
|
||||||
name: guild.name,
|
name: guild.name,
|
||||||
|
@ -147,12 +154,7 @@ export const guildMap: { [x: string]: GuildSlug } = {
|
||||||
permissionLevel: 0,
|
permissionLevel: 0,
|
||||||
icon: guild.icon,
|
icon: guild.icon,
|
||||||
},
|
},
|
||||||
Roleypoly: {
|
Roleypoly: roleypolyGuild,
|
||||||
name: 'Roleypoly',
|
|
||||||
id: '203493697696956418',
|
|
||||||
permissionLevel: 0,
|
|
||||||
icon: 'ff08d36f5aee1ff48f8377b65d031ab0',
|
|
||||||
},
|
|
||||||
'chamber of secrets': {
|
'chamber of secrets': {
|
||||||
name: 'chamber of secrets',
|
name: 'chamber of secrets',
|
||||||
id: 'aaa',
|
id: 'aaa',
|
||||||
|
@ -234,6 +236,6 @@ export const mastheadSlugs: GuildSlug[] = guildEnum.guilds.map<GuildSlug>(
|
||||||
id: guild.guild.id,
|
id: guild.guild.id,
|
||||||
name: guild.guild.name,
|
name: guild.guild.name,
|
||||||
icon: guild.guild.icon,
|
icon: guild.guild.icon,
|
||||||
permissionLevel: idx % 3,
|
permissionLevel: 1 << idx % 3,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
13
src/design-system/atoms/collapse/Collapse.stories.tsx
Normal file
13
src/design-system/atoms/collapse/Collapse.stories.tsx
Normal 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>
|
||||||
|
);
|
10
src/design-system/atoms/collapse/Collapse.tsx
Normal file
10
src/design-system/atoms/collapse/Collapse.tsx
Normal 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;
|
||||||
|
`)}
|
||||||
|
`;
|
1
src/design-system/atoms/collapse/index.ts
Normal file
1
src/design-system/atoms/collapse/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './Collapse';
|
|
@ -96,3 +96,13 @@ export const Link = styled.a`
|
||||||
color: ${palette.taupe600};
|
color: ${palette.taupe600};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const CompletelyStylelessLink = styled.a`
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
:visited,
|
||||||
|
:active,
|
||||||
|
:hover {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -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} />;
|
|
@ -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;
|
||||||
|
`)}
|
||||||
|
`;
|
|
@ -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;
|
||||||
|
};
|
1
src/design-system/molecules/server-listing-card/index.ts
Normal file
1
src/design-system/molecules/server-listing-card/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './ServerListingCard';
|
|
@ -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} />;
|
|
@ -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%;
|
||||||
|
`)}
|
||||||
|
`;
|
|
@ -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>
|
||||||
|
);
|
1
src/design-system/organisms/servers-listing/index.ts
Normal file
1
src/design-system/organisms/servers-listing/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './ServersListing';
|
13
src/design-system/templates/servers/Servers.stories.tsx
Normal file
13
src/design-system/templates/servers/Servers.stories.tsx
Normal 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} />;
|
14
src/design-system/templates/servers/Servers.tsx
Normal file
14
src/design-system/templates/servers/Servers.tsx
Normal 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>
|
||||||
|
);
|
1
src/design-system/templates/servers/index.ts
Normal file
1
src/design-system/templates/servers/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './Servers';
|
|
@ -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';
|
import { useAppShellProps } from 'roleypoly/providers/appShellData';
|
||||||
|
|
||||||
export default () => {
|
const Servers = () => {
|
||||||
const { appShellProps } = useAppShellProps();
|
const { appShellProps } = useAppShellProps();
|
||||||
return (
|
return (
|
||||||
<AppShell {...appShellProps}>
|
<>
|
||||||
<div></div>
|
<Head>
|
||||||
</AppShell>
|
<title>Viewing your servers - Roleypoly</title>
|
||||||
|
</Head>
|
||||||
|
<ServersTemplate {...appShellProps} guilds={appShellProps.guilds || []} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Servers;
|
||||||
|
|
|
@ -12966,6 +12966,11 @@ styled-jsx@3.3.2:
|
||||||
stylis "3.5.4"
|
stylis "3.5.4"
|
||||||
stylis-rule-sheet "0.0.10"
|
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:
|
stylelint-config-prettier@^8.0.2:
|
||||||
version "8.0.2"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-8.0.2.tgz#da9de33da4c56893cbe7e26df239a7374045e14e"
|
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-8.0.2.tgz#da9de33da4c56893cbe7e26df239a7374045e14e"
|
||||||
|
|
Loading…
Add table
Reference in a new issue